More convenient way to specify classpath

master
baztian 2013-10-03 16:24:38 +02:00
parent 1be932113e
commit 027f81aab1
3 changed files with 100 additions and 47 deletions

View File

@ -43,7 +43,7 @@ or if you are using Jython use ::
$ jython setup.py install $ jython setup.py install
It has been tested with Jython 2.5.2. It has been tested with Jython 2.5.3.
If you are using cPython ensure that you have installed JPype_ If you are using cPython ensure that you have installed JPype_
properly. It has been tested with JPype 0.5.4. properly. It has been tested with JPype 0.5.4.
@ -56,15 +56,20 @@ the ``connect`` method. This gives you a DB-API_ conform connection to
the database. the database.
The first argument to ``connect`` is the name of the Java driver The first argument to ``connect`` is the name of the Java driver
class. The rest of the arguments are internally passed to the Java class. Then you can supply a single argument or a sequence of
``DriverManager.getConnection`` method. See the Javadoc of arguments that are internally passed to the Java
``DriverManager`` class for details. ``DriverManager.getConnection`` method. Usually this is the JDBC
connection URL. See the Javadoc of ``DriverManager`` class for
details. As the next parameter you can optionally specify the
jar-Files of the driver if your classpath isn't set up sufficiently
yet.
Here is an example: Here is an example:
>>> import jaydebeapi >>> import jaydebeapi
>>> conn = jaydebeapi.connect('org.hsqldb.jdbcDriver', >>> conn = jaydebeapi.connect('org.hsqldb.jdbcDriver',
... 'jdbc:hsqldb:mem', 'SA', '') ... ['jdbc:hsqldb:mem:.', 'SA', ''],
... '/path/to/hsqldb.jar',)
>>> curs = conn.cursor() >>> curs = conn.cursor()
>>> curs.execute('create table CUSTOMER' >>> curs.execute('create table CUSTOMER'
... '("CUST_ID" INTEGER not null,' ... '("CUST_ID" INTEGER not null,'
@ -99,7 +104,7 @@ or in Jython I have to
Supported databases Supported databases
=================== ===================
In theory every database with a suitable JDBC driver should work. It In theory *every database with a suitable JDBC driver should work*. It
is known to work with the following databases: is known to work with the following databases:
+-----------------------------------------+------------------------------------------------+---------------+----------------------+ +-----------------------------------------+------------------------------------------------+---------------+----------------------+
@ -127,14 +132,16 @@ is known to work with the following databases:
|for z/OS | | |without problems. | |for z/OS | | |without problems. |
+-----------------------------------------+------------------------------------------------+---------------+----------------------+ +-----------------------------------------+------------------------------------------------+---------------+----------------------+
|Oracle 11g |Oracle Thin Driver |Medium |Not thoroughly | |Oracle 11g |Oracle Thin Driver |Medium |Not thoroughly |
| | | |testst. No support for| | | | |tests. No support for |
| | | |rading of timestamps | | | | |rading of timestamps |
| | | |yet. | | | | |yet. |
+-----------------------------------------+------------------------------------------------+---------------+----------------------+ +-----------------------------------------+------------------------------------------------+---------------+----------------------+
|Teradata DB |terajdbc4.jar |Medium |A user reported |
| | | |success. |
+-----------------------------------------+------------------------------------------------+---------------+----------------------+
|Other databases |Other JDBC drivers |Unkown |Please test yourself | |Other databases |Other JDBC drivers |Unkown |Please test yourself |
| | | |and report the | | | | |and report the |
| | | |results. | | | | |results. |
| | | | |
+-----------------------------------------+------------------------------------------------+---------------+----------------------+ +-----------------------------------------+------------------------------------------------+---------------+----------------------+
Contributing Contributing
@ -157,6 +164,9 @@ Changelog
- 0.1.4 - 0.1.4
- More convenient way to setup Java classpath. *Important note*
check the changes to the ``connect`` method and adapt your code.
- Set ``.rowcount`` properly. - Set ``.rowcount`` properly.
- 0.1.3 - 0.1.3

View File

@ -1,6 +1,6 @@
#-*- coding: utf-8 -*- #-*- coding: utf-8 -*-
# Copyright 2010 Bastian Bowe # Copyright 2010, 2011, 2012, 2013 Bastian Bowe
# #
# This file is part of JayDeBeApi. # This file is part of JayDeBeApi.
# JayDeBeApi is free software: you can redistribute it and/or modify # JayDeBeApi is free software: you can redistribute it and/or modify
@ -19,6 +19,7 @@
import datetime import datetime
import exceptions import exceptions
import os
import time import time
import re import re
import sys import sys
@ -27,7 +28,7 @@ _jdbc_connect = None
_java_array_byte = None _java_array_byte = None
def _jdbc_connect_jython(jclassname, *args): def _jdbc_connect_jython(jclassname, jars, libs, *args):
if _converters is None: if _converters is None:
from java.sql import Types from java.sql import Types
types = Types types = Types
@ -37,24 +38,63 @@ def _jdbc_connect_jython(jclassname, *args):
if const_re.match(i): if const_re.match(i):
types_map[i] = getattr(types, i) types_map[i] = getattr(types, i)
_init_converters(types_map) _init_converters(types_map)
# register driver for DriverManager
__import__(jclassname)
global _java_array_byte global _java_array_byte
if _java_array_byte is None: if _java_array_byte is None:
import jarray import jarray
def _java_array_byte(data): def _java_array_byte(data):
return jarray.array(data, 'b') return jarray.array(data, 'b')
# register driver for DriverManager
jpackage = jclassname[:jclassname.rfind('.')]
dclassname = jclassname[jclassname.rfind('.') + 1:]
# print jpackage
# print dclassname
# print jpackage
from java.lang import Class
from java.lang import ClassNotFoundException
try:
Class.forName(jclassname).newInstance()
except ClassNotFoundException:
if not jars:
raise
_jython_set_classpath(jars)
Class.forName(jclassname).newInstance()
from java.sql import DriverManager from java.sql import DriverManager
return DriverManager.getConnection(*args) return DriverManager.getConnection(*args)
def _jython_set_classpath(jars):
'''
import a jar at runtime (needed for JDBC [Class.forName])
adapted by Bastian Bowe from
http://stackoverflow.com/questions/3015059/jython-classpath-sys-path-and-jdbc-drivers
'''
from java.net import URL, URLClassLoader
from java.lang import ClassLoader
from java.io import File
m = URLClassLoader.getDeclaredMethod("addURL", [URL])
m.accessible = 1
urls = [File(i).toURL() for i in jars]
m.invoke(ClassLoader.getSystemClassLoader(), urls)
def _prepare_jython(): def _prepare_jython():
global _jdbc_connect global _jdbc_connect
_jdbc_connect = _jdbc_connect_jython _jdbc_connect = _jdbc_connect_jython
def _jdbc_connect_jpype(jclassname, *args): def _jdbc_connect_jpype(jclassname, jars, libs, *args):
import jpype import jpype
if not jpype.isJVMStarted(): if not jpype.isJVMStarted():
jpype.startJVM(jpype.getDefaultJVMPath()) args = []
if jars:
class_path = os.path.pathsep.join(jars)
args.append('-Djava.class.path=%s' % class_path)
if libs:
# path to shared libraries
libs_path = os.path.pathsep.join(libs)
args.append('-Djava.library.path=%s' % libs_path)
# jvm_path = ('/usr/lib/jvm/java-6-openjdk'
# '/jre/lib/i386/client/libjvm.so')
jvm_path = jpype.getDefaultJVMPath()
jpype.startJVM(jvm_path, *args)
if not jpype.isThreadAttachedToJVM(): if not jpype.isThreadAttachedToJVM():
jpype.attachThreadToJVM() jpype.attachThreadToJVM()
if _converters is None: if _converters is None:
@ -176,8 +216,33 @@ def TimestampFromTicks(ticks):
return apply(Timestamp, time.localtime(ticks)[:6]) return apply(Timestamp, time.localtime(ticks)[:6])
# DB-API 2.0 Module Interface connect constructor # DB-API 2.0 Module Interface connect constructor
def connect(jclassname, *args): def connect(jclassname, driver_args, jars=None, libs=None):
jconn = _jdbc_connect(jclassname, *args) """Open a connection to a database using a JDBC driver and return
a Connection instance.
jclassname: Full qualified Java class name of the JDBC driver.
driver_args: Argument or sequence of arguments to be passed to the
Java DriverManager.getConnection method. Usually the
database URL. See
http://docs.oracle.com/javase/6/docs/api/java/sql/DriverManager.html
for more details
jars: Jar filename or sequence of filenames for the JDBC driver
libs: Dll/so filenames or sequence of dlls/sos used as shared
library by the JDBC driver
"""
if isinstance(driver_args, basestring):
driver_args = [ driver_args ]
if jars:
if isinstance(jars, basestring):
jars = [ jars ]
else:
jars = []
if libs:
if isinstance(libs, basestring):
libs = [ libs ]
else:
libs = []
jconn = _jdbc_connect(jclassname, jars, libs, *driver_args)
return Connection(jconn, _converters) return Connection(jconn, _converters)
# DB-API 2.0 Connection Object # DB-API 2.0 Connection Object

View File

@ -50,23 +50,6 @@ class IntegrationTest(TestCase):
for i in stmts: for i in stmts:
cursor.execute(i) cursor.execute(i)
def setup_jpype(self, jars, libs=None):
import jpype
if not jpype.isJVMStarted():
jvm_path = jpype.getDefaultJVMPath()
#jvm_path = ('/usr/lib/jvm/java-6-openjdk'
# '/jre/lib/i386/client/libjvm.so')
# path to shared libraries
args = []
if libs:
libs_path = path.pathsep.join(libs)
args.append('-Djava.library.path=%s' % libs_path)
class_path = path.pathsep.join(jars)
args.append('-Djava.class.path=%s' % class_path)
jpype.startJVM(jvm_path, *args)
if not jpype.isThreadAttachedToJVM():
jpype.attachThreadToJVM()
def connect(self): def connect(self):
# rename the latter connect method to run tests against # rename the latter connect method to run tests against
# pysqlite # pysqlite
@ -76,30 +59,25 @@ class IntegrationTest(TestCase):
return sqlite3, sqlite3.connect(':memory:') return sqlite3, sqlite3.connect(':memory:')
def connect(self): def connect(self):
jar_names = [ 'sqlitejdbc-v056.jar', 'hsqldb.jar', 'sqlite.jar' ]
jars = [ path.join(jar_dir, i) for i in jar_names ]
if is_jython():
sys.path.extend(jars)
# print "CLASSPATH=%s" % path.pathsep.join(jars)
else:
self.setup_jpype(jars, [jar_dir])
# http://www.zentus.com/sqlitejdbc/ # http://www.zentus.com/sqlitejdbc/
conn = jaydebeapi.connect('org.sqlite.JDBC', conn = jaydebeapi.connect('org.sqlite.JDBC',
'jdbc:sqlite::memory:') 'jdbc:sqlite::memory:',
path.join(jar_dir, 'sqlitejdbc-v056.jar'),)
# http://hsqldb.org/ # http://hsqldb.org/
# conn = jaydebeapi.connect('org.hsqldb.jdbcDriver', # conn = jaydebeapi.connect('org.hsqldb.jdbcDriver',
# 'jdbc:hsqldb:mem', 'SA', '') # ['jdbc:hsqldb:mem:.', 'SA', ''],
# 'hsqldb.jar')
# conn = jaydebeapi.connect('com.ibm.db2.jcc.DB2Driver', # conn = jaydebeapi.connect('com.ibm.db2.jcc.DB2Driver',
# 'jdbc:db2://4.100.73.81:50000/db2t', # ['jdbc:db2://4.100.73.81:50000/db2t',
# user, passwd) # user, passwd])
# driver from http://www.ch-werner.de/javasqlite/ seems to be # driver from http://www.ch-werner.de/javasqlite/ seems to be
# crap as it returns decimal values as VARCHAR type # crap as it returns decimal values as VARCHAR type
# conn = jaydebeapi.connect('SQLite.JDBCDriver', # conn = jaydebeapi.connect('SQLite.JDBCDriver',
# 'jdbc:sqlite:/:memory:') # 'jdbc:sqlite:/:memory:', 'sqlite.jar')
# Oracle Thin Driver # Oracle Thin Driver
# conn = jaydebeapi.connect('oracle.jdbc.OracleDriver', # conn = jaydebeapi.connect('oracle.jdbc.OracleDriver',
# 'jdbc:oracle:thin:@//hh-cluster-scan:1521/HH_TPP', # ['jdbc:oracle:thin:@//hh-cluster-scan:1521/HH_TPP',
# user, passwd) # user, passwd])
return jaydebeapi, conn return jaydebeapi, conn
def setUp(self): def setUp(self):