Skip to content

Commit 0c1c8c8

Browse files
Backport PR #40471: compat: sqlalchemy deprecations (#40481)
Co-authored-by: jbrockmendel <[email protected]>
1 parent 59fe44e commit 0c1c8c8

File tree

2 files changed

+54
-13
lines changed

2 files changed

+54
-13
lines changed

pandas/io/sql.py

+35-7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
from contextlib import contextmanager
77
from datetime import date, datetime, time
8+
from distutils.version import LooseVersion
89
from functools import partial
910
import re
1011
from typing import Iterator, List, Optional, Union, overload
@@ -55,6 +56,16 @@ def _is_sqlalchemy_connectable(con):
5556
return False
5657

5758

59+
def _gt14() -> bool:
60+
"""
61+
Check if sqlalchemy.__version__ is at least 1.4.0, when several
62+
deprecations were made.
63+
"""
64+
import sqlalchemy
65+
66+
return LooseVersion(sqlalchemy.__version__) >= LooseVersion("1.4.0")
67+
68+
5869
def _convert_params(sql, params):
5970
"""Convert SQL and params args to DBAPI2.0 compliant format."""
6071
args = [sql]
@@ -715,7 +726,10 @@ def sql_schema(self):
715726

716727
def _execute_create(self):
717728
# Inserting table into database, add to MetaData object
718-
self.table = self.table.tometadata(self.pd_sql.meta)
729+
if _gt14():
730+
self.table = self.table.to_metadata(self.pd_sql.meta)
731+
else:
732+
self.table = self.table.tometadata(self.pd_sql.meta)
719733
self.table.create()
720734

721735
def create(self):
@@ -1409,9 +1423,17 @@ def to_sql(
14091423
# Only check when name is not a number and name is not lower case
14101424
engine = self.connectable.engine
14111425
with self.connectable.connect() as conn:
1412-
table_names = engine.table_names(
1413-
schema=schema or self.meta.schema, connection=conn
1414-
)
1426+
if _gt14():
1427+
from sqlalchemy import inspect
1428+
1429+
insp = inspect(conn)
1430+
table_names = insp.get_table_names(
1431+
schema=schema or self.meta.schema
1432+
)
1433+
else:
1434+
table_names = engine.table_names(
1435+
schema=schema or self.meta.schema, connection=conn
1436+
)
14151437
if name not in table_names:
14161438
msg = (
14171439
f"The provided table name '{name}' is not found exactly as "
@@ -1426,9 +1448,15 @@ def tables(self):
14261448
return self.meta.tables
14271449

14281450
def has_table(self, name, schema=None):
1429-
return self.connectable.run_callable(
1430-
self.connectable.dialect.has_table, name, schema or self.meta.schema
1431-
)
1451+
if _gt14():
1452+
import sqlalchemy as sa
1453+
1454+
insp = sa.inspect(self.connectable)
1455+
return insp.has_table(name, schema or self.meta.schema)
1456+
else:
1457+
return self.connectable.run_callable(
1458+
self.connectable.dialect.has_table, name, schema or self.meta.schema
1459+
)
14321460

14331461
def get_table(self, table_name, schema=None):
14341462
schema = schema or self.meta.schema

pandas/tests/io/test_sql.py

+19-6
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,11 @@
4444
import pandas._testing as tm
4545

4646
import pandas.io.sql as sql
47-
from pandas.io.sql import read_sql_query, read_sql_table
47+
from pandas.io.sql import _gt14, read_sql_query, read_sql_table
4848

4949
try:
5050
import sqlalchemy
51+
from sqlalchemy import inspect
5152
from sqlalchemy.ext import declarative
5253
from sqlalchemy.orm import session as sa_session
5354
import sqlalchemy.schema
@@ -1331,7 +1332,11 @@ def test_create_table(self):
13311332
pandasSQL = sql.SQLDatabase(temp_conn)
13321333
pandasSQL.to_sql(temp_frame, "temp_frame")
13331334

1334-
assert temp_conn.has_table("temp_frame")
1335+
if _gt14():
1336+
insp = inspect(temp_conn)
1337+
assert insp.has_table("temp_frame")
1338+
else:
1339+
assert temp_conn.has_table("temp_frame")
13351340

13361341
def test_drop_table(self):
13371342
temp_conn = self.connect()
@@ -1343,11 +1348,18 @@ def test_drop_table(self):
13431348
pandasSQL = sql.SQLDatabase(temp_conn)
13441349
pandasSQL.to_sql(temp_frame, "temp_frame")
13451350

1346-
assert temp_conn.has_table("temp_frame")
1351+
if _gt14():
1352+
insp = inspect(temp_conn)
1353+
assert insp.has_table("temp_frame")
1354+
else:
1355+
assert temp_conn.has_table("temp_frame")
13471356

13481357
pandasSQL.drop_table("temp_frame")
13491358

1350-
assert not temp_conn.has_table("temp_frame")
1359+
if _gt14():
1360+
assert not insp.has_table("temp_frame")
1361+
else:
1362+
assert not temp_conn.has_table("temp_frame")
13511363

13521364
def test_roundtrip(self):
13531365
self._roundtrip()
@@ -1689,9 +1701,10 @@ def test_nan_string(self):
16891701
tm.assert_frame_equal(result, df)
16901702

16911703
def _get_index_columns(self, tbl_name):
1692-
from sqlalchemy.engine import reflection
1704+
from sqlalchemy import inspect
1705+
1706+
insp = inspect(self.conn)
16931707

1694-
insp = reflection.Inspector.from_engine(self.conn)
16951708
ixs = insp.get_indexes(tbl_name)
16961709
ixs = [i["column_names"] for i in ixs]
16971710
return ixs

0 commit comments

Comments
 (0)