Skip to content

Commit 8cffd37

Browse files
abowden1989simonjayhawkins
authored andcommitted
Backport PR pandas-dev#45679: BUG: Do not error on other dbapi2 connections
1 parent db131b6 commit 8cffd37

File tree

3 files changed

+24
-4
lines changed

3 files changed

+24
-4
lines changed

doc/source/whatsnew/v1.4.1.rst

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Fixed regressions
1919
- Regression in :meth:`Series.fillna` with ``downcast=False`` incorrectly downcasting ``object`` dtype (:issue:`45603`)
2020
- Regression in :meth:`DataFrame.loc.__setitem__` losing :class:`Index` name if :class:`DataFrame` was empty before (:issue:`45621`)
2121
- Regression in :func:`join` with overlapping :class:`IntervalIndex` raising an ``InvalidIndexError`` (:issue:`45661`)
22+
- Regression in :func:`read_sql` with a DBAPI2 connection that is not an instance of ``sqlite3.Connection`` incorrectly requiring SQLAlchemy be installed (:issue:`45660`)
2223
-
2324

2425
.. ---------------------------------------------------------------------------

pandas/io/sql.py

+6-3
Original file line numberDiff line numberDiff line change
@@ -747,12 +747,15 @@ def pandasSQL_builder(con, schema: str | None = None):
747747
if isinstance(con, sqlite3.Connection) or con is None:
748748
return SQLiteDatabase(con)
749749

750-
sqlalchemy = import_optional_dependency("sqlalchemy")
750+
sqlalchemy = import_optional_dependency("sqlalchemy", errors="ignore")
751751

752752
if isinstance(con, str):
753-
con = sqlalchemy.create_engine(con)
753+
if sqlalchemy is None:
754+
raise ImportError("Using URI string without sqlalchemy installed.")
755+
else:
756+
con = sqlalchemy.create_engine(con)
754757

755-
if isinstance(con, sqlalchemy.engine.Connectable):
758+
if sqlalchemy is not None and isinstance(con, sqlalchemy.engine.Connectable):
756759
return SQLDatabase(con, schema=schema)
757760

758761
warnings.warn(

pandas/tests/io/test_sql.py

+17-1
Original file line numberDiff line numberDiff line change
@@ -1534,9 +1534,25 @@ def test_sql_open_close(self, test_frame3):
15341534
@pytest.mark.skipif(SQLALCHEMY_INSTALLED, reason="SQLAlchemy is installed")
15351535
def test_con_string_import_error(self):
15361536
conn = "mysql://root@localhost/pandas"
1537-
with pytest.raises(ImportError, match="SQLAlchemy"):
1537+
msg = "Using URI string without sqlalchemy installed"
1538+
with pytest.raises(ImportError, match=msg):
15381539
sql.read_sql("SELECT * FROM iris", conn)
15391540

1541+
@pytest.mark.skipif(SQLALCHEMY_INSTALLED, reason="SQLAlchemy is installed")
1542+
def test_con_unknown_dbapi2_class_does_not_error_without_sql_alchemy_installed(
1543+
self,
1544+
):
1545+
class MockSqliteConnection:
1546+
def __init__(self, *args, **kwargs):
1547+
self.conn = sqlite3.Connection(*args, **kwargs)
1548+
1549+
def __getattr__(self, name):
1550+
return getattr(self.conn, name)
1551+
1552+
conn = MockSqliteConnection(":memory:")
1553+
with tm.assert_produces_warning(UserWarning):
1554+
sql.read_sql("SELECT 1", conn)
1555+
15401556
def test_read_sql_delegate(self):
15411557
iris_frame1 = sql.read_sql_query("SELECT * FROM iris", self.conn)
15421558
iris_frame2 = sql.read_sql("SELECT * FROM iris", self.conn)

0 commit comments

Comments
 (0)