Add Python 3 compatibility.
parent
affe3ae688
commit
453eb61598
|
|
@ -16,6 +16,7 @@ deploy:
|
|||
python:
|
||||
- '2.6'
|
||||
- '2.7'
|
||||
- '3.4'
|
||||
|
||||
env:
|
||||
matrix:
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
.. image:: https://img.shields.io/coveralls/baztian/jaydebeapi/master.svg
|
||||
:target: https://coveralls.io/r/baztian/jaydebeapi
|
||||
|
||||
.. image:: https://img.shields.io/badge/python-2.6,_2.7-blue.svg
|
||||
.. image:: https://img.shields.io/badge/python-2.6,_2.7,_3.4-blue.svg
|
||||
:target: https://pypi.python.org/pypi/JayDeBeApi
|
||||
|
||||
.. image:: https://img.shields.io/badge/jython-2.5.3,_2.7--rc1-blue.svg
|
||||
|
|
@ -168,6 +168,9 @@ Changelog
|
|||
=========
|
||||
|
||||
- Next version - unreleased
|
||||
|
||||
- Python 3 support (requires JPype1 >= 0.6.0).
|
||||
|
||||
- 0.1.6 - 2015-04-10
|
||||
|
||||
- Fix Jython handling of Java exceptions that don't subclass python Exception
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
cat requirements-python.txt >> requirements.txt
|
||||
if [ -f requirements-python-${TRAVIS_PYTHON_VERSION}.txt ]
|
||||
then
|
||||
cat requirements-python-${TRAVIS_PYTHON_VERSION}.txt >> requirements.txt
|
||||
fi
|
||||
ln -s $VIRTUAL_ENV $HOME/myvirtualenv
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ __version_info__ = (0, 1, 6)
|
|||
__version__ = ".".join(str(i) for i in __version_info__)
|
||||
|
||||
import datetime
|
||||
import exceptions
|
||||
import glob
|
||||
import os
|
||||
import time
|
||||
|
|
@ -29,6 +28,40 @@ import re
|
|||
import sys
|
||||
import warnings
|
||||
|
||||
PY2 = sys.version_info[0] == 2
|
||||
|
||||
if PY2:
|
||||
# Ideas stolen from the six python 2 and 3 compatibility layer
|
||||
def exec_(_code_, _globs_=None, _locs_=None):
|
||||
"""Execute code in a namespace."""
|
||||
if _globs_ is None:
|
||||
frame = sys._getframe(1)
|
||||
_globs_ = frame.f_globals
|
||||
if _locs_ is None:
|
||||
_locs_ = frame.f_locals
|
||||
del frame
|
||||
elif _locs_ is None:
|
||||
_locs_ = _globs_
|
||||
exec("""exec _code_ in _globs_, _locs_""")
|
||||
|
||||
exec_("""def reraise(tp, value, tb=None):
|
||||
raise tp, value, tb
|
||||
""")
|
||||
else:
|
||||
def reraise(tp, value, tb=None):
|
||||
if value is None:
|
||||
value = tp()
|
||||
else:
|
||||
value = tp(value)
|
||||
if tb:
|
||||
raise value.with_traceback(tb)
|
||||
raise value
|
||||
|
||||
if PY2:
|
||||
string_type = basestring
|
||||
else:
|
||||
string_type = str
|
||||
|
||||
# Mapping from java.sql.Types attribute name to attribute value
|
||||
_jdbc_name_to_const = None
|
||||
|
||||
|
|
@ -48,7 +81,7 @@ def _handle_sql_exception_jython():
|
|||
exc_type = DatabaseError
|
||||
else:
|
||||
exc_type = InterfaceError
|
||||
raise exc_type, exc_info[1], exc_info[2]
|
||||
reraise(exc_type, exc_info[1], exc_info[2])
|
||||
|
||||
def _jdbc_connect_jython(jclassname, jars, libs, *args):
|
||||
if _jdbc_name_to_const is None:
|
||||
|
|
@ -112,7 +145,7 @@ def _handle_sql_exception_jpype():
|
|||
exc_type = DatabaseError
|
||||
else:
|
||||
exc_type = InterfaceError
|
||||
raise exc_type, exc_info[1], exc_info[2]
|
||||
reraise(exc_type, exc_info[1], exc_info[2])
|
||||
|
||||
def _jdbc_connect_jpype(jclassname, jars, libs, *driver_args):
|
||||
import jpype
|
||||
|
|
@ -191,7 +224,7 @@ class DBAPITypeObject(object):
|
|||
self.values = values
|
||||
for type_name in values:
|
||||
if type_name in DBAPITypeObject._mappings:
|
||||
raise ValueError, "Non unique mapping for type '%s'" % type_name
|
||||
raise ValueError("Non unique mapping for type '%s'" % type_name)
|
||||
DBAPITypeObject._mappings[type_name] = self
|
||||
def __cmp__(self, other):
|
||||
if other in self.values:
|
||||
|
|
@ -239,10 +272,10 @@ DATETIME = DBAPITypeObject('TIMESTAMP')
|
|||
ROWID = DBAPITypeObject('ROWID')
|
||||
|
||||
# DB-API 2.0 Module Interface Exceptions
|
||||
class Error(exceptions.StandardError):
|
||||
class Error(Exception):
|
||||
pass
|
||||
|
||||
class Warning(exceptions.StandardError):
|
||||
class Warning(Exception):
|
||||
pass
|
||||
|
||||
class InterfaceError(Error):
|
||||
|
|
@ -311,15 +344,15 @@ def connect(jclassname, driver_args, jars=None, libs=None):
|
|||
libs: Dll/so filenames or sequence of dlls/sos used as shared
|
||||
library by the JDBC driver
|
||||
"""
|
||||
if isinstance(driver_args, basestring):
|
||||
if isinstance(driver_args, string_type):
|
||||
driver_args = [ driver_args ]
|
||||
if jars:
|
||||
if isinstance(jars, basestring):
|
||||
if isinstance(jars, string_type):
|
||||
jars = [ jars ]
|
||||
else:
|
||||
jars = []
|
||||
if libs:
|
||||
if isinstance(libs, basestring):
|
||||
if isinstance(libs, string_type):
|
||||
libs = [ libs ]
|
||||
else:
|
||||
libs = []
|
||||
|
|
@ -347,7 +380,7 @@ class Connection(object):
|
|||
|
||||
def close(self):
|
||||
if self._closed:
|
||||
raise Error
|
||||
raise Error()
|
||||
self.jconn.close()
|
||||
self._closed = True
|
||||
|
||||
|
|
@ -436,7 +469,7 @@ class Cursor(object):
|
|||
|
||||
def execute(self, operation, parameters=None):
|
||||
if self._connection._closed:
|
||||
raise Error
|
||||
raise Error()
|
||||
if not parameters:
|
||||
parameters = ()
|
||||
self._close_last()
|
||||
|
|
@ -467,7 +500,7 @@ class Cursor(object):
|
|||
|
||||
def fetchone(self):
|
||||
if not self._rs:
|
||||
raise Error
|
||||
raise Error()
|
||||
if not self._rs.next():
|
||||
return None
|
||||
row = []
|
||||
|
|
@ -480,14 +513,14 @@ class Cursor(object):
|
|||
|
||||
def fetchmany(self, size=None):
|
||||
if not self._rs:
|
||||
raise Error
|
||||
raise Error()
|
||||
if size is None:
|
||||
size = self.arraysize
|
||||
# TODO: handle SQLException if not supported by db
|
||||
self._rs.setFetchSize(size)
|
||||
rows = []
|
||||
row = None
|
||||
for i in xrange(size):
|
||||
for i in range(size):
|
||||
row = self.fetchone()
|
||||
if row is None:
|
||||
break
|
||||
|
|
@ -554,7 +587,9 @@ def _java_to_py(java_method):
|
|||
java_val = rs.getObject(col)
|
||||
if java_val is None:
|
||||
return
|
||||
if isinstance(java_val, (basestring, int, long, float, bool)):
|
||||
if PY2 and isinstance(java_val, (string_type, int, long, float, bool)):
|
||||
return java_val
|
||||
elif isinstance(java_val, (string_type, int, float, bool)):
|
||||
return java_val
|
||||
return getattr(java_val, java_method)()
|
||||
return to_py
|
||||
|
|
@ -567,7 +602,7 @@ def _init_types(types_map):
|
|||
global _jdbc_name_to_const
|
||||
_jdbc_name_to_const = types_map
|
||||
global _jdbc_const_to_name
|
||||
_jdbc_const_to_name = dict((y,x) for x,y in types_map.iteritems())
|
||||
_jdbc_const_to_name = dict((y,x) for x,y in types_map.items())
|
||||
_init_converters(types_map)
|
||||
|
||||
def _init_converters(types_map):
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
JPype1==0.6.0
|
||||
|
|
@ -0,0 +1 @@
|
|||
JPype1==0.6.0
|
||||
|
|
@ -1 +0,0 @@
|
|||
JPype1==0.5.7
|
||||
7
setup.py
7
setup.py
|
|
@ -32,16 +32,17 @@ setup(
|
|||
author_email = 'bastian.dev@gmail.com',
|
||||
license = 'GNU LGPL',
|
||||
url='https://github.com/baztian/jaydebeapi',
|
||||
description=('A bridge from JDBC database drivers to Python DB-API.'),
|
||||
long_description=file('README.rst').read(),
|
||||
description=('Use JDBC database drivers from Python 2/3 or Jython with a DB-API.'),
|
||||
long_description=open('README.rst').read(),
|
||||
keywords = ('db api java jdbc bridge connect sql jpype jython'),
|
||||
classifiers = [
|
||||
'Development Status :: 3 - Alpha',
|
||||
'Development Status :: 4 - Beta',
|
||||
'Intended Audience :: Developers',
|
||||
'License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)',
|
||||
'Programming Language :: Java',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Topic :: Database',
|
||||
'Topic :: Software Development :: Libraries :: Java Libraries',
|
||||
'Topic :: Software Development :: Libraries :: Python Modules',
|
||||
|
|
|
|||
|
|
@ -27,9 +27,14 @@ import unittest2 as unittest
|
|||
|
||||
_THIS_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
PY26 = not sys.version_info >= (2, 7)
|
||||
|
||||
def is_jython():
|
||||
return sys.platform.lower().startswith('java')
|
||||
|
||||
if PY26 and not is_jython:
|
||||
memoryview = buffer
|
||||
|
||||
class IntegrationTestBase(object):
|
||||
|
||||
def sql_file(self, filename):
|
||||
|
|
@ -140,12 +145,12 @@ class IntegrationTestBase(object):
|
|||
"BLOCKING, DBL_COL, OPENED_AT, VALID, PRODUCT_NAME) " \
|
||||
"values (?, ?, ?, ?, ?, ?, ?, ?)"
|
||||
d = self.dbapi
|
||||
account_id = d.Timestamp(2010, 01, 26, 14, 31, 59)
|
||||
account_id = d.Timestamp(2010, 1, 26, 14, 31, 59)
|
||||
account_no = 20
|
||||
balance = 1.2
|
||||
blocking = 10.0
|
||||
dbl_col = 3.5
|
||||
opened_at = d.Date(2008, 02, 27)
|
||||
opened_at = d.Date(2008, 2, 27)
|
||||
valid = 1
|
||||
product_name = u'Savings account'
|
||||
parms = (account_id, account_no, balance, blocking, dbl_col,
|
||||
|
|
@ -168,7 +173,7 @@ class IntegrationTestBase(object):
|
|||
"OPENED_AT_TIME) " \
|
||||
"values (?, ?, ?, ?)"
|
||||
d = self.dbapi
|
||||
account_id = d.Timestamp(2010, 01, 26, 14, 31, 59)
|
||||
account_id = d.Timestamp(2010, 1, 26, 14, 31, 59)
|
||||
account_no = 20
|
||||
balance = 1.2
|
||||
opened_at_time = d.Time(13, 59, 59)
|
||||
|
|
@ -209,7 +214,8 @@ class SqliteTestBase(IntegrationTestBase):
|
|||
cursor = self.conn.cursor()
|
||||
stmt = "insert into ACCOUNT (ACCOUNT_ID, ACCOUNT_NO, BALANCE, " \
|
||||
"STUFF) values (?, ?, ?, ?)"
|
||||
stuff = self.dbapi.Binary('abcdef')
|
||||
binary_stuff = 'abcdef'.encode('UTF-8')
|
||||
stuff = self.dbapi.Binary(binary_stuff)
|
||||
parms = ('2009-09-11 14:15:22.123450', 20, 13.1, stuff)
|
||||
cursor.execute(stmt, parms)
|
||||
stmt = "select STUFF from ACCOUNT where ACCOUNT_NO = ?"
|
||||
|
|
@ -218,7 +224,7 @@ class SqliteTestBase(IntegrationTestBase):
|
|||
result = cursor.fetchone()
|
||||
cursor.close()
|
||||
value = result[0]
|
||||
self.assertEqual(value, buffer('abcdef'))
|
||||
self.assertEqual(value, memoryview(binary_stuff))
|
||||
|
||||
@unittest.skipIf(is_jython(), "requires python")
|
||||
class SqlitePyTest(SqliteTestBase, unittest.TestCase):
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ class MockTest(unittest.TestCase):
|
|||
try:
|
||||
cursor.execute("dummy stmt")
|
||||
fail("expected exception")
|
||||
except jaydebeapi.DatabaseError, e:
|
||||
except jaydebeapi.DatabaseError as e:
|
||||
self.assertEquals(str(e), "java.sql.SQLException: expected")
|
||||
|
||||
def test_runtime_exception_on_execute(self):
|
||||
|
|
@ -62,7 +62,7 @@ class MockTest(unittest.TestCase):
|
|||
try:
|
||||
cursor.execute("dummy stmt")
|
||||
fail("expected exception")
|
||||
except jaydebeapi.InterfaceError, e:
|
||||
except jaydebeapi.InterfaceError as e:
|
||||
self.assertEquals(str(e), "java.lang.RuntimeException: expected")
|
||||
|
||||
def test_sql_exception_on_commit(self):
|
||||
|
|
@ -70,7 +70,7 @@ class MockTest(unittest.TestCase):
|
|||
try:
|
||||
self.conn.commit()
|
||||
fail("expected exception")
|
||||
except jaydebeapi.DatabaseError, e:
|
||||
except jaydebeapi.DatabaseError as e:
|
||||
self.assertEquals(str(e), "java.sql.SQLException: expected")
|
||||
|
||||
def test_runtime_exception_on_commit(self):
|
||||
|
|
@ -78,7 +78,7 @@ class MockTest(unittest.TestCase):
|
|||
try:
|
||||
self.conn.commit()
|
||||
fail("expected exception")
|
||||
except jaydebeapi.InterfaceError, e:
|
||||
except jaydebeapi.InterfaceError as e:
|
||||
self.assertEquals(str(e), "java.lang.RuntimeException: expected")
|
||||
|
||||
def test_sql_exception_on_rollback(self):
|
||||
|
|
@ -86,7 +86,7 @@ class MockTest(unittest.TestCase):
|
|||
try:
|
||||
self.conn.rollback()
|
||||
fail("expected exception")
|
||||
except jaydebeapi.DatabaseError, e:
|
||||
except jaydebeapi.DatabaseError as e:
|
||||
self.assertEquals(str(e), "java.sql.SQLException: expected")
|
||||
|
||||
def test_runtime_exception_on_rollback(self):
|
||||
|
|
@ -94,5 +94,5 @@ class MockTest(unittest.TestCase):
|
|||
try:
|
||||
self.conn.rollback()
|
||||
fail("expected exception")
|
||||
except jaydebeapi.InterfaceError, e:
|
||||
except jaydebeapi.InterfaceError as e:
|
||||
self.assertEquals(str(e), "java.lang.RuntimeException: expected")
|
||||
|
|
|
|||
Loading…
Reference in New Issue