Skip to content

Commit 848dc71

Browse files
author
Chuck Cadman
committed
ENH: Make pandas.io.sql compatible with sqlalchemy 2.0 (#40686)
1 parent a297a51 commit 848dc71

File tree

3 files changed

+15
-10
lines changed

3 files changed

+15
-10
lines changed

doc/source/whatsnew/v2.0.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ Other enhancements
108108
- :meth:`DataFrame.plot.hist` now recognizes ``xlabel`` and ``ylabel`` arguments (:issue:`49793`)
109109
- Improved error message in :func:`to_datetime` for non-ISO8601 formats, informing users about the position of the first error (:issue:`50361`)
110110
- Improved error message when trying to align :class:`DataFrame` objects (for example, in :func:`DataFrame.compare`) to clarify that "identically labelled" refers to both index and columns (:issue:`50083`)
111+
- Added support for SQLAlchemy 2.0 (:issue:`40686`)
111112
-
112113

113114
.. ---------------------------------------------------------------------------

pandas/io/sql.py

+13-9
Original file line numberDiff line numberDiff line change
@@ -1153,7 +1153,7 @@ def _create_table_setup(self):
11531153

11541154
column_names_and_types = self._get_column_names_and_types(self._sqlalchemy_type)
11551155

1156-
columns = [
1156+
columns: list[Any] = [
11571157
Column(name, typ, index=is_index)
11581158
for name, typ, is_index in column_names_and_types
11591159
]
@@ -1443,7 +1443,7 @@ def insert_records(
14431443

14441444
try:
14451445
return table.insert(chunksize=chunksize, method=method)
1446-
except exc.SQLAlchemyError as err:
1446+
except exc.StatementError as err:
14471447
# GH34431
14481448
# https://stackoverflow.com/a/67358288/6067848
14491449
msg = r"""(\(1054, "Unknown column 'inf(e0)?' in 'field list'"\))(?#
@@ -1514,10 +1514,11 @@ def __init__(
15141514
self.exit_stack = ExitStack()
15151515
if isinstance(con, str):
15161516
con = create_engine(con)
1517+
self.exit_stack.callback(con.dispose)
15171518
if isinstance(con, Engine):
15181519
con = self.exit_stack.enter_context(con.connect())
1519-
if need_transaction:
1520-
self.exit_stack.enter_context(con.begin())
1520+
if need_transaction and not con.in_transaction():
1521+
self.exit_stack.enter_context(con.begin())
15211522
self.con = con
15221523
self.meta = MetaData(schema=schema)
15231524
self.returns_generator = False
@@ -1533,6 +1534,8 @@ def run_transaction(self):
15331534
def execute(self, sql: str | Select | TextClause, params=None):
15341535
"""Simple passthrough to SQLAlchemy connectable"""
15351536
args = [] if params is None else [params]
1537+
if isinstance(sql, str):
1538+
return self.con.exec_driver_sql(sql, *args)
15361539
return self.con.execute(sql, *args)
15371540

15381541
def read_table(
@@ -1761,13 +1764,14 @@ def prep_table(
17611764
else:
17621765
dtype = cast(dict, dtype)
17631766

1764-
from sqlalchemy.types import (
1765-
TypeEngine,
1766-
to_instance,
1767-
)
1767+
from sqlalchemy.types import TypeEngine
17681768

17691769
for col, my_type in dtype.items():
1770-
if not isinstance(to_instance(my_type), TypeEngine):
1770+
if isinstance(my_type, type) and issubclass(my_type, TypeEngine):
1771+
pass
1772+
elif isinstance(my_type, TypeEngine):
1773+
pass
1774+
else:
17711775
raise ValueError(f"The type of {col} is not a SQLAlchemy type")
17721776

17731777
table = SQLTable(

pandas/tests/io/test_sql.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -838,7 +838,7 @@ def load_types_data(self, types_data):
838838

839839
def _read_sql_iris_parameter(self):
840840
query = SQL_STRINGS["read_parameters"][self.flavor]
841-
params = ["Iris-setosa", 5.1]
841+
params = ("Iris-setosa", 5.1)
842842
iris_frame = self.pandasSQL.read_query(query, params=params)
843843
check_iris_frame(iris_frame)
844844

0 commit comments

Comments
 (0)