Merge pull request #150 from baztian/close-cursors

Removed cursor destructor to avoid issues with some JPype versions
master
baztian 2020-06-12 08:50:51 +02:00 committed by GitHub
commit ea36e12f57
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 116 additions and 109 deletions

1
.env 100644
View File

@ -0,0 +1 @@
FOO=BAR

View File

@ -95,9 +95,9 @@ Here is an example:
... "/path/to/hsqldb.jar",) ... "/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,'
... ' "NAME" VARCHAR(50) not null,' ... ' "NAME" VARCHAR(50) not null,'
... ' primary key ("CUST_ID"))' ... ' primary key ("CUST_ID"))'
... ) ... )
>>> curs.execute("insert into CUSTOMER values (1, 'John')") >>> curs.execute("insert into CUSTOMER values (1, 'John')")
>>> curs.execute("select * from CUSTOMER") >>> curs.execute("select * from CUSTOMER")
@ -106,6 +106,12 @@ Here is an example:
>>> curs.close() >>> curs.close()
>>> conn.close() >>> conn.close()
If you're having trouble getting this work check if your ``JAVA_HOME``
environmentvariable is set correctly. For example I have to set it on
my Ubuntu machine like this ::
$ JAVA_HOME=/usr/lib/jvm/java-8-openjdk python
An alternative way to establish connection using connection An alternative way to establish connection using connection
properties: properties:
@ -115,12 +121,16 @@ properties:
... 'other_property': "foobar"}, ... 'other_property': "foobar"},
... "/path/to/hsqldb.jar",) ... "/path/to/hsqldb.jar",)
Also using the ``with`` statement might be handy:
If you're having trouble getting this work check if your ``JAVA_HOME`` >>> with jaydebeapi.connect("org.hsqldb.jdbcDriver",
environmentvariable is set correctly. For example I have to set it on ... "jdbc:hsqldb:mem:.",
my Ubuntu machine like this :: ... ["SA", ""],
... "/path/to/hsqldb.jar",) as conn:
$ JAVA_HOME=/usr/lib/jvm/java-8-openjdk python ... with conn.cursor() as curs:
... curs.execute("select count(*) from CUSTOMER")
... curs.fetchall()
[(1,)]
Supported databases Supported databases
=================== ===================
@ -164,6 +174,8 @@ Changelog
- Make pip install for Python 2 work by changing JPype1 requirement to older - Make pip install for Python 2 work by changing JPype1 requirement to older
version version
- Make pip install for Jython work by removing JPype1 requirement for Jython - Make pip install for Jython work by removing JPype1 requirement for Jython
- Removed cursor destructor to avoid issues with some JPype versions (please
make sure you're always closing your cursors properly)
- 1.2.2 - 2020-06-04 - 1.2.2 - 2020-06-04

View File

@ -517,10 +517,6 @@ class Cursor(object):
self._meta = None self._meta = None
self._description = None self._description = None
# TODO: this is a possible way to close the open result sets
# but I'm not sure when __del__ will be called
__del__ = _close_last
def _set_stmt_parms(self, prep_stmt, parameters): def _set_stmt_parms(self, prep_stmt, parameters):
for i in range(len(parameters)): for i in range(len(parameters)):
# print (i, parameters[i], type(parameters[i])) # print (i, parameters[i], type(parameters[i]))

View File

@ -53,9 +53,9 @@ class IntegrationTestBase(object):
if ";" in i: if ";" in i:
stmts.append(" ".join(stmt)) stmts.append(" ".join(stmt))
stmt = [] stmt = []
cursor = self.conn.cursor() with self.conn.cursor() as cursor:
for i in stmts: for i in stmts:
cursor.execute(i) cursor.execute(i)
def setUp(self): def setUp(self):
(self.dbapi, self.conn) = self.connect() (self.dbapi, self.conn) = self.connect()
@ -68,36 +68,37 @@ class IntegrationTestBase(object):
raise NotImplementedError raise NotImplementedError
def tearDown(self): def tearDown(self):
cursor = self.conn.cursor() with self.conn.cursor() as cursor:
cursor.execute("drop table ACCOUNT"); cursor.execute("drop table ACCOUNT")
self.conn.close() self.conn.close()
def test_execute_and_fetch_no_data(self): def test_execute_and_fetch_no_data(self):
cursor = self.conn.cursor() with self.conn.cursor() as cursor:
stmt = "select * from ACCOUNT where ACCOUNT_ID is null" stmt = "select * from ACCOUNT where ACCOUNT_ID is null"
cursor.execute(stmt) cursor.execute(stmt)
self.assertEqual(cursor.fetchall(), []) result = cursor.fetchall()
self.assertEqual(result, [])
def test_execute_and_fetch(self): def test_execute_and_fetch(self):
cursor = self.conn.cursor() with self.conn.cursor() as cursor:
cursor.execute("select ACCOUNT_ID, ACCOUNT_NO, BALANCE, BLOCKING " \ cursor.execute("select ACCOUNT_ID, ACCOUNT_NO, BALANCE, BLOCKING " \
"from ACCOUNT") "from ACCOUNT")
result = cursor.fetchall() result = cursor.fetchall()
self.assertEqual(result, [(u'2009-09-10 14:15:22.123456', 18, 12.4, None), self.assertEqual(result, [(u'2009-09-10 14:15:22.123456', 18, 12.4, None),
(u'2009-09-11 14:15:22.123456', 19, 12.9, 1)]) (u'2009-09-11 14:15:22.123456', 19, 12.9, 1)])
def test_execute_and_fetch_parameter(self): def test_execute_and_fetch_parameter(self):
cursor = self.conn.cursor() with self.conn.cursor() as cursor:
cursor.execute("select ACCOUNT_ID, ACCOUNT_NO, BALANCE, BLOCKING " \ cursor.execute("select ACCOUNT_ID, ACCOUNT_NO, BALANCE, BLOCKING " \
"from ACCOUNT where ACCOUNT_NO = ?", (18,)) "from ACCOUNT where ACCOUNT_NO = ?", (18,))
result = cursor.fetchall() result = cursor.fetchall()
self.assertEqual(result, [(u'2009-09-10 14:15:22.123456', 18, 12.4, None)]) self.assertEqual(result, [(u'2009-09-10 14:15:22.123456', 18, 12.4, None)])
def test_execute_and_fetchone(self): def test_execute_and_fetchone(self):
cursor = self.conn.cursor() with self.conn.cursor() as cursor:
cursor.execute("select ACCOUNT_ID, ACCOUNT_NO, BALANCE, BLOCKING " \ cursor.execute("select ACCOUNT_ID, ACCOUNT_NO, BALANCE, BLOCKING " \
"from ACCOUNT order by ACCOUNT_NO") "from ACCOUNT order by ACCOUNT_NO")
result = cursor.fetchone() result = cursor.fetchone()
self.assertEqual(result, (u'2009-09-10 14:15:22.123456', 18, 12.4, None)) self.assertEqual(result, (u'2009-09-10 14:15:22.123456', 18, 12.4, None))
cursor.close() cursor.close()
@ -105,25 +106,25 @@ class IntegrationTestBase(object):
"""Expect the descriptions property being reset when no query """Expect the descriptions property being reset when no query
has been made via execute method. has been made via execute method.
""" """
cursor = self.conn.cursor() with self.conn.cursor() as cursor:
cursor.execute("select * from ACCOUNT") cursor.execute("select * from ACCOUNT")
self.assertIsNotNone(cursor.description) self.assertIsNotNone(cursor.description)
cursor.fetchone() cursor.fetchone()
cursor.execute("delete from ACCOUNT") cursor.execute("delete from ACCOUNT")
self.assertIsNone(cursor.description) self.assertIsNone(cursor.description)
def test_execute_and_fetchone_after_end(self): def test_execute_and_fetchone_after_end(self):
cursor = self.conn.cursor() with self.conn.cursor() as cursor:
cursor.execute("select * from ACCOUNT where ACCOUNT_NO = ?", (18,)) cursor.execute("select * from ACCOUNT where ACCOUNT_NO = ?", (18,))
cursor.fetchone() cursor.fetchone()
result = cursor.fetchone() result = cursor.fetchone()
self.assertIsNone(result) self.assertIsNone(result)
def test_execute_and_fetchmany(self): def test_execute_and_fetchmany(self):
cursor = self.conn.cursor() with self.conn.cursor() as cursor:
cursor.execute("select ACCOUNT_ID, ACCOUNT_NO, BALANCE, BLOCKING " \ cursor.execute("select ACCOUNT_ID, ACCOUNT_NO, BALANCE, BLOCKING " \
"from ACCOUNT order by ACCOUNT_NO") "from ACCOUNT order by ACCOUNT_NO")
result = cursor.fetchmany() result = cursor.fetchmany()
self.assertEqual(result, [(u'2009-09-10 14:15:22.123456', 18, 12.4, None)]) self.assertEqual(result, [(u'2009-09-10 14:15:22.123456', 18, 12.4, None)])
# TODO: find out why this cursor has to be closed in order to # TODO: find out why this cursor has to be closed in order to
# let this test work with sqlite if __del__ is not overridden # let this test work with sqlite if __del__ is not overridden
@ -131,7 +132,6 @@ class IntegrationTestBase(object):
# cursor.close() # cursor.close()
def test_executemany(self): def test_executemany(self):
cursor = self.conn.cursor()
stmt = "insert into ACCOUNT (ACCOUNT_ID, ACCOUNT_NO, BALANCE) " \ stmt = "insert into ACCOUNT (ACCOUNT_ID, ACCOUNT_NO, BALANCE) " \
"values (?, ?, ?)" "values (?, ?, ?)"
parms = ( parms = (
@ -139,11 +139,11 @@ class IntegrationTestBase(object):
( '2009-09-11 14:15:22.123451', 21, 13.2 ), ( '2009-09-11 14:15:22.123451', 21, 13.2 ),
( '2009-09-11 14:15:22.123452', 22, 13.3 ), ( '2009-09-11 14:15:22.123452', 22, 13.3 ),
) )
cursor.executemany(stmt, parms) with self.conn.cursor() as cursor:
self.assertEqual(cursor.rowcount, 3) cursor.executemany(stmt, parms)
self.assertEqual(cursor.rowcount, 3)
def test_execute_types(self): def test_execute_types(self):
cursor = self.conn.cursor()
stmt = "insert into ACCOUNT (ACCOUNT_ID, ACCOUNT_NO, BALANCE, " \ stmt = "insert into ACCOUNT (ACCOUNT_ID, ACCOUNT_NO, BALANCE, " \
"BLOCKING, DBL_COL, OPENED_AT, VALID, PRODUCT_NAME) " \ "BLOCKING, DBL_COL, OPENED_AT, VALID, PRODUCT_NAME) " \
"values (?, ?, ?, ?, ?, ?, ?, ?)" "values (?, ?, ?, ?, ?, ?, ?, ?)"
@ -158,20 +158,19 @@ class IntegrationTestBase(object):
product_name = u'Savings account' product_name = u'Savings account'
parms = (account_id, account_no, balance, blocking, dbl_col, parms = (account_id, account_no, balance, blocking, dbl_col,
opened_at, valid, product_name) opened_at, valid, product_name)
cursor.execute(stmt, parms) with self.conn.cursor() as cursor:
stmt = "select ACCOUNT_ID, ACCOUNT_NO, BALANCE, BLOCKING, " \ cursor.execute(stmt, parms)
"DBL_COL, OPENED_AT, VALID, PRODUCT_NAME " \ stmt = "select ACCOUNT_ID, ACCOUNT_NO, BALANCE, BLOCKING, " \
"from ACCOUNT where ACCOUNT_NO = ?" "DBL_COL, OPENED_AT, VALID, PRODUCT_NAME " \
parms = (20, ) "from ACCOUNT where ACCOUNT_NO = ?"
cursor.execute(stmt, parms) parms = (20, )
result = cursor.fetchone() cursor.execute(stmt, parms)
cursor.close() result = cursor.fetchone()
exp = ( '2010-01-26 14:31:59', account_no, balance, blocking, exp = ( '2010-01-26 14:31:59', account_no, balance, blocking,
dbl_col, '2008-02-27', valid, product_name ) dbl_col, '2008-02-27', valid, product_name )
self.assertEqual(result, exp) self.assertEqual(result, exp)
def test_execute_type_time(self): def test_execute_type_time(self):
cursor = self.conn.cursor()
stmt = "insert into ACCOUNT (ACCOUNT_ID, ACCOUNT_NO, BALANCE, " \ stmt = "insert into ACCOUNT (ACCOUNT_ID, ACCOUNT_NO, BALANCE, " \
"OPENED_AT_TIME) " \ "OPENED_AT_TIME) " \
"values (?, ?, ?, ?)" "values (?, ?, ?, ?)"
@ -181,31 +180,31 @@ class IntegrationTestBase(object):
balance = 1.2 balance = 1.2
opened_at_time = d.Time(13, 59, 59) opened_at_time = d.Time(13, 59, 59)
parms = (account_id, account_no, balance, opened_at_time) parms = (account_id, account_no, balance, opened_at_time)
cursor.execute(stmt, parms) with self.conn.cursor() as cursor:
stmt = "select ACCOUNT_ID, ACCOUNT_NO, BALANCE, OPENED_AT_TIME " \ cursor.execute(stmt, parms)
"from ACCOUNT where ACCOUNT_NO = ?" stmt = "select ACCOUNT_ID, ACCOUNT_NO, BALANCE, OPENED_AT_TIME " \
parms = (20, ) "from ACCOUNT where ACCOUNT_NO = ?"
cursor.execute(stmt, parms) parms = (20, )
result = cursor.fetchone() cursor.execute(stmt, parms)
cursor.close() result = cursor.fetchone()
exp = ( '2010-01-26 14:31:59', account_no, balance, '13:59:59' ) exp = ( '2010-01-26 14:31:59', account_no, balance, '13:59:59' )
self.assertEqual(result, exp) self.assertEqual(result, exp)
def test_execute_different_rowcounts(self): def test_execute_different_rowcounts(self):
cursor = self.conn.cursor()
stmt = "insert into ACCOUNT (ACCOUNT_ID, ACCOUNT_NO, BALANCE) " \ stmt = "insert into ACCOUNT (ACCOUNT_ID, ACCOUNT_NO, BALANCE) " \
"values (?, ?, ?)" "values (?, ?, ?)"
parms = ( parms = (
( '2009-09-11 14:15:22.123450', 20, 13.1 ), ( '2009-09-11 14:15:22.123450', 20, 13.1 ),
( '2009-09-11 14:15:22.123452', 22, 13.3 ), ( '2009-09-11 14:15:22.123452', 22, 13.3 ),
) )
cursor.executemany(stmt, parms) with self.conn.cursor() as cursor:
self.assertEqual(cursor.rowcount, 2) cursor.executemany(stmt, parms)
parms = ( '2009-09-11 14:15:22.123451', 21, 13.2 ) self.assertEqual(cursor.rowcount, 2)
cursor.execute(stmt, parms) parms = ( '2009-09-11 14:15:22.123451', 21, 13.2 )
self.assertEqual(cursor.rowcount, 1) cursor.execute(stmt, parms)
cursor.execute("select * from ACCOUNT") self.assertEqual(cursor.rowcount, 1)
self.assertEqual(cursor.rowcount, -1) cursor.execute("select * from ACCOUNT")
self.assertEqual(cursor.rowcount, -1)
class SqliteTestBase(IntegrationTestBase): class SqliteTestBase(IntegrationTestBase):
@ -214,18 +213,17 @@ class SqliteTestBase(IntegrationTestBase):
self.sql_file(os.path.join(_THIS_DIR, 'data', 'insert.sql')) self.sql_file(os.path.join(_THIS_DIR, 'data', 'insert.sql'))
def test_execute_type_blob(self): def test_execute_type_blob(self):
cursor = self.conn.cursor()
stmt = "insert into ACCOUNT (ACCOUNT_ID, ACCOUNT_NO, BALANCE, " \ stmt = "insert into ACCOUNT (ACCOUNT_ID, ACCOUNT_NO, BALANCE, " \
"STUFF) values (?, ?, ?, ?)" "STUFF) values (?, ?, ?, ?)"
binary_stuff = 'abcdef'.encode('UTF-8') binary_stuff = 'abcdef'.encode('UTF-8')
stuff = self.dbapi.Binary(binary_stuff) stuff = self.dbapi.Binary(binary_stuff)
parms = ('2009-09-11 14:15:22.123450', 20, 13.1, stuff) parms = ('2009-09-11 14:15:22.123450', 20, 13.1, stuff)
cursor.execute(stmt, parms) with self.conn.cursor() as cursor:
stmt = "select STUFF from ACCOUNT where ACCOUNT_NO = ?" cursor.execute(stmt, parms)
parms = (20, ) stmt = "select STUFF from ACCOUNT where ACCOUNT_NO = ?"
cursor.execute(stmt, parms) parms = (20, )
result = cursor.fetchone() cursor.execute(stmt, parms)
cursor.close() result = cursor.fetchone()
value = result[0] value = result[0]
self.assertEqual(value, memoryview(binary_stuff)) self.assertEqual(value, memoryview(binary_stuff))

View File

@ -41,9 +41,9 @@ class MockTest(unittest.TestCase):
if isinstance(db_api_type, jaydebeapi.DBAPITypeObject): if isinstance(db_api_type, jaydebeapi.DBAPITypeObject):
for jsql_type_name in db_api_type.values: for jsql_type_name in db_api_type.values:
self.conn.jconn.mockType(jsql_type_name) self.conn.jconn.mockType(jsql_type_name)
cursor = self.conn.cursor() with self.conn.cursor() as cursor:
cursor.execute("dummy stmt") cursor.execute("dummy stmt")
cursor.fetchone() cursor.fetchone()
verify = self.conn.jconn.verifyResultSet() verify = self.conn.jconn.verifyResultSet()
verify_get = getattr(verify, verify_get = getattr(verify,
extra_type_mappings.get(jsql_type_name, extra_type_mappings.get(jsql_type_name,
@ -52,49 +52,49 @@ class MockTest(unittest.TestCase):
def test_ancient_date_mapped(self): def test_ancient_date_mapped(self):
self.conn.jconn.mockDateResult(1899, 12, 31) self.conn.jconn.mockDateResult(1899, 12, 31)
cursor = self.conn.cursor() with self.conn.cursor() as cursor:
cursor.execute("dummy stmt") cursor.execute("dummy stmt")
result = cursor.fetchone() result = cursor.fetchone()
self.assertEquals(result[0], "1899-12-31") self.assertEquals(result[0], "1899-12-31")
def test_decimal_scale_zero(self): def test_decimal_scale_zero(self):
self.conn.jconn.mockBigDecimalResult(12345, 0) self.conn.jconn.mockBigDecimalResult(12345, 0)
cursor = self.conn.cursor() with self.conn.cursor() as cursor:
cursor.execute("dummy stmt") cursor.execute("dummy stmt")
result = cursor.fetchone() result = cursor.fetchone()
self.assertEquals(str(result[0]), "12345") self.assertEquals(str(result[0]), "12345")
def test_decimal_places(self): def test_decimal_places(self):
self.conn.jconn.mockBigDecimalResult(12345, 1) self.conn.jconn.mockBigDecimalResult(12345, 1)
cursor = self.conn.cursor() with self.conn.cursor() as cursor:
cursor.execute("dummy stmt") cursor.execute("dummy stmt")
result = cursor.fetchone() result = cursor.fetchone()
self.assertEquals(str(result[0]), "1234.5") self.assertEquals(str(result[0]), "1234.5")
def test_double_decimal(self): def test_double_decimal(self):
self.conn.jconn.mockDoubleDecimalResult(1234.5) self.conn.jconn.mockDoubleDecimalResult(1234.5)
cursor = self.conn.cursor() with self.conn.cursor() as cursor:
cursor.execute("dummy stmt") cursor.execute("dummy stmt")
result = cursor.fetchone() result = cursor.fetchone()
self.assertEquals(str(result[0]), "1234.5") self.assertEquals(str(result[0]), "1234.5")
def test_sql_exception_on_execute(self): def test_sql_exception_on_execute(self):
self.conn.jconn.mockExceptionOnExecute("java.sql.SQLException", "expected") self.conn.jconn.mockExceptionOnExecute("java.sql.SQLException", "expected")
cursor = self.conn.cursor() with self.conn.cursor() as cursor:
try: try:
cursor.execute("dummy stmt") cursor.execute("dummy stmt")
self.fail("expected exception") self.fail("expected exception")
except jaydebeapi.DatabaseError as e: except jaydebeapi.DatabaseError as e:
self.assertEquals(str(e), "java.sql.SQLException: expected") self.assertEquals(str(e), "java.sql.SQLException: expected")
def test_runtime_exception_on_execute(self): def test_runtime_exception_on_execute(self):
self.conn.jconn.mockExceptionOnExecute("java.lang.RuntimeException", "expected") self.conn.jconn.mockExceptionOnExecute("java.lang.RuntimeException", "expected")
cursor = self.conn.cursor() with self.conn.cursor() as cursor:
try: try:
cursor.execute("dummy stmt") cursor.execute("dummy stmt")
self.fail("expected exception") self.fail("expected exception")
except jaydebeapi.InterfaceError as e: except jaydebeapi.InterfaceError as e:
self.assertEquals(str(e), "java.lang.RuntimeException: expected") self.assertEquals(str(e), "java.lang.RuntimeException: expected")
def test_sql_exception_on_commit(self): def test_sql_exception_on_commit(self):
self.conn.jconn.mockExceptionOnCommit("java.sql.SQLException", "expected") self.conn.jconn.mockExceptionOnCommit("java.sql.SQLException", "expected")