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
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_
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 first argument to ``connect`` is the name of the Java driver
class. The rest of the arguments are internally passed to the Java
``DriverManager.getConnection`` method. See the Javadoc of
``DriverManager`` class for details.
class. Then you can supply a single argument or a sequence of
arguments that are internally passed to the Java
``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:
>>> import jaydebeapi
>>> conn = jaydebeapi.connect('org.hsqldb.jdbcDriver',
... 'jdbc:hsqldb:mem', 'SA', '')
... ['jdbc:hsqldb:mem:.', 'SA', ''],
... '/path/to/hsqldb.jar',)
>>> curs = conn.cursor()
>>> curs.execute('create table CUSTOMER'
... '("CUST_ID" INTEGER not null,'
@ -99,7 +104,7 @@ or in Jython I have to
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:
+-----------------------------------------+------------------------------------------------+---------------+----------------------+
@ -127,14 +132,16 @@ is known to work with the following databases:
|for z/OS | | |without problems. |
+-----------------------------------------+------------------------------------------------+---------------+----------------------+
|Oracle 11g |Oracle Thin Driver |Medium |Not thoroughly |
| | | |testst. No support for|
| | | |tests. No support for |
| | | |rading of timestamps |
| | | |yet. |
+-----------------------------------------+------------------------------------------------+---------------+----------------------+
|Teradata DB |terajdbc4.jar |Medium |A user reported |
| | | |success. |
+-----------------------------------------+------------------------------------------------+---------------+----------------------+
|Other databases |Other JDBC drivers |Unkown |Please test yourself |
| | | |and report the |
| | | |results. |
| | | | |
+-----------------------------------------+------------------------------------------------+---------------+----------------------+
Contributing
@ -157,6 +164,9 @@ Changelog
- 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.
- 0.1.3

View File

@ -1,6 +1,6 @@
#-*- coding: utf-8 -*-
# Copyright 2010 Bastian Bowe
# Copyright 2010, 2011, 2012, 2013 Bastian Bowe
#
# This file is part of JayDeBeApi.
# JayDeBeApi is free software: you can redistribute it and/or modify
@ -19,6 +19,7 @@
import datetime
import exceptions
import os
import time
import re
import sys
@ -27,7 +28,7 @@ _jdbc_connect = None
_java_array_byte = None
def _jdbc_connect_jython(jclassname, *args):
def _jdbc_connect_jython(jclassname, jars, libs, *args):
if _converters is None:
from java.sql import Types
types = Types
@ -37,24 +38,63 @@ def _jdbc_connect_jython(jclassname, *args):
if const_re.match(i):
types_map[i] = getattr(types, i)
_init_converters(types_map)
# register driver for DriverManager
__import__(jclassname)
global _java_array_byte
if _java_array_byte is None:
import jarray
def _java_array_byte(data):
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
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():
global _jdbc_connect
_jdbc_connect = _jdbc_connect_jython
def _jdbc_connect_jpype(jclassname, *args):
def _jdbc_connect_jpype(jclassname, jars, libs, *args):
import jpype
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():
jpype.attachThreadToJVM()
if _converters is None:
@ -176,8 +216,33 @@ def TimestampFromTicks(ticks):
return apply(Timestamp, time.localtime(ticks)[:6])
# DB-API 2.0 Module Interface connect constructor
def connect(jclassname, *args):
jconn = _jdbc_connect(jclassname, *args)
def connect(jclassname, driver_args, jars=None, libs=None):
"""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)
# DB-API 2.0 Connection Object

View File

@ -50,23 +50,6 @@ class IntegrationTest(TestCase):
for i in stmts:
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):
# rename the latter connect method to run tests against
# pysqlite
@ -76,30 +59,25 @@ class IntegrationTest(TestCase):
return sqlite3, sqlite3.connect(':memory:')
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/
conn = jaydebeapi.connect('org.sqlite.JDBC',
'jdbc:sqlite::memory:')
'jdbc:sqlite::memory:',
path.join(jar_dir, 'sqlitejdbc-v056.jar'),)
# http://hsqldb.org/
# conn = jaydebeapi.connect('org.hsqldb.jdbcDriver',
# 'jdbc:hsqldb:mem', 'SA', '')
# ['jdbc:hsqldb:mem:.', 'SA', ''],
# 'hsqldb.jar')
# conn = jaydebeapi.connect('com.ibm.db2.jcc.DB2Driver',
# 'jdbc:db2://4.100.73.81:50000/db2t',
# user, passwd)
# ['jdbc:db2://4.100.73.81:50000/db2t',
# user, passwd])
# driver from http://www.ch-werner.de/javasqlite/ seems to be
# crap as it returns decimal values as VARCHAR type
# conn = jaydebeapi.connect('SQLite.JDBCDriver',
# 'jdbc:sqlite:/:memory:')
# 'jdbc:sqlite:/:memory:', 'sqlite.jar')
# Oracle Thin Driver
# conn = jaydebeapi.connect('oracle.jdbc.OracleDriver',
# 'jdbc:oracle:thin:@//hh-cluster-scan:1521/HH_TPP',
# user, passwd)
# ['jdbc:oracle:thin:@//hh-cluster-scan:1521/HH_TPP',
# user, passwd])
return jaydebeapi, conn
def setUp(self):