Skip to content

Commit 6e80100

Browse files
author
Thomas Grainger
committed
support both sqlalchemy engines and connections Fixes #10104
1 parent eafd22d commit 6e80100

File tree

1 file changed

+27
-7
lines changed

1 file changed

+27
-7
lines changed

pandas/io/sql.py

+27-7
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class DatabaseError(IOError):
3838
_SQLALCHEMY_INSTALLED = None
3939

4040

41-
def _is_sqlalchemy_engine(con):
41+
def _is_sqlalchemy_connectable(con):
4242
global _SQLALCHEMY_INSTALLED
4343
if _SQLALCHEMY_INSTALLED is None:
4444
try:
@@ -61,8 +61,8 @@ def compile_big_int_sqlite(type_, compiler, **kw):
6161
_SQLALCHEMY_INSTALLED = False
6262

6363
if _SQLALCHEMY_INSTALLED:
64-
import sqlalchemy
65-
return isinstance(con, sqlalchemy.engine.Engine)
64+
from sqlalchemy.engine import interfaces
65+
return isinstance(con, interfaces.Connectable)
6666
else:
6767
return False
6868

@@ -328,7 +328,7 @@ def read_sql_table(table_name, con, schema=None, index_col=None,
328328
read_sql
329329
330330
"""
331-
if not _is_sqlalchemy_engine(con):
331+
if not _is_sqlalchemy_connectable(con):
332332
raise NotImplementedError("read_sql_table only supported for "
333333
"SQLAlchemy engines.")
334334
import sqlalchemy
@@ -592,7 +592,7 @@ def pandasSQL_builder(con, flavor=None, schema=None, meta=None,
592592
"""
593593
# When support for DBAPI connections is removed,
594594
# is_cursor should not be necessary.
595-
if _is_sqlalchemy_engine(con):
595+
if _is_sqlalchemy_connectable(con):
596596
return SQLDatabase(con, schema=schema, meta=meta)
597597
else:
598598
if flavor == 'mysql':
@@ -993,7 +993,7 @@ class SQLDatabase(PandasSQL):
993993
994994
Parameters
995995
----------
996-
engine : SQLAlchemy engine
996+
engine : SQLAlchemy engine or connection
997997
Engine to connect with the database. Using SQLAlchemy makes it
998998
possible to use any DB supported by that library.
999999
schema : string, default None
@@ -1014,8 +1014,28 @@ def __init__(self, engine, schema=None, meta=None):
10141014

10151015
self.meta = meta
10161016

1017+
1018+
class SQLAlchemyTransaction(object):
1019+
"""
1020+
Context manager for sql alchemy transactions
1021+
that returns the relevent connectable.
1022+
"""
1023+
def __init__(connectable):
1024+
self.connectable = connectable
1025+
1026+
def __enter__(self):
1027+
self.tx = self.connectable.begin()
1028+
if _is_sqlalchemy_connectable(self.tx):
1029+
return self.tx
1030+
else:
1031+
return self.connectable
1032+
1033+
def __exit__(self, *args, **kwargs):
1034+
return self.tx.__exit__(*args, **kwargs)
1035+
1036+
10171037
def run_transaction(self):
1018-
return self.engine.begin()
1038+
return self.SQLAlchemyTransaction(self.engine)
10191039

10201040
def execute(self, *args, **kwargs):
10211041
"""Simple passthrough to SQLAlchemy engine"""

0 commit comments

Comments
 (0)