From f42b9acbc4061c5837eefe780b99b452402323d4 Mon Sep 17 00:00:00 2001 From: Adam Bowden <23028875+abowden1989@users.noreply.github.com> Date: Thu, 27 Jan 2022 16:27:07 +0000 Subject: [PATCH 1/5] Add test case --- pandas/tests/io/test_sql.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/pandas/tests/io/test_sql.py b/pandas/tests/io/test_sql.py index 741af4324c1a6..df823587b296e 100644 --- a/pandas/tests/io/test_sql.py +++ b/pandas/tests/io/test_sql.py @@ -1527,6 +1527,20 @@ def test_con_string_import_error(self): with pytest.raises(ImportError, match="SQLAlchemy"): sql.read_sql("SELECT * FROM iris", conn) + @pytest.mark.skipif(SQLALCHEMY_INSTALLED, reason="SQLAlchemy is installed") + def test_con_unknown_dbapi2_class_does_not_error_without_sql_alchemy_installed( + self, + ): + class MockSqliteConnection: + def __init__(self, *args, **kwargs): + self.conn = sqlite3.Connection(*args, **kwargs) + + def __getattr__(self, name): + return getattr(self.conn, name) + + conn = MockSqliteConnection(":memory:") + sql.read_sql("SELECT 1", conn) + def test_read_sql_delegate(self): iris_frame1 = sql.read_sql_query("SELECT * FROM iris", self.conn) iris_frame2 = sql.read_sql("SELECT * FROM iris", self.conn) From 7c0a246bd692b61922fa0f17f69665e3357e609b Mon Sep 17 00:00:00 2001 From: Adam Bowden <23028875+abowden1989@users.noreply.github.com> Date: Thu, 27 Jan 2022 16:47:02 +0000 Subject: [PATCH 2/5] Make test pass --- pandas/io/sql.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/pandas/io/sql.py b/pandas/io/sql.py index fcb3f5177ae3f..05eff2b508ae0 100644 --- a/pandas/io/sql.py +++ b/pandas/io/sql.py @@ -736,13 +736,14 @@ def pandasSQL_builder(con, schema: str | None = None): if isinstance(con, sqlite3.Connection) or con is None: return SQLiteDatabase(con) - sqlalchemy = import_optional_dependency("sqlalchemy") + sqlalchemy = import_optional_dependency("sqlalchemy", errors="ignore") - if isinstance(con, str): - con = sqlalchemy.create_engine(con) + if sqlalchemy is not None: + if isinstance(con, str): + con = sqlalchemy.create_engine(con) - if isinstance(con, sqlalchemy.engine.Connectable): - return SQLDatabase(con, schema=schema) + if isinstance(con, sqlalchemy.engine.Connectable): + return SQLDatabase(con, schema=schema) warnings.warn( "pandas only support SQLAlchemy connectable(engine/connection) or" From 48b7e30d80bb84227ebf31b8c07ec266ba3ca974 Mon Sep 17 00:00:00 2001 From: Adam Bowden <23028875+abowden1989@users.noreply.github.com> Date: Fri, 28 Jan 2022 13:35:36 +0000 Subject: [PATCH 3/5] Restore previous behaviour when con is a str without sqlalchemy installed --- pandas/io/sql.py | 10 ++++++---- pandas/tests/io/test_sql.py | 3 ++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/pandas/io/sql.py b/pandas/io/sql.py index 05eff2b508ae0..ba18412856d6c 100644 --- a/pandas/io/sql.py +++ b/pandas/io/sql.py @@ -738,12 +738,14 @@ def pandasSQL_builder(con, schema: str | None = None): sqlalchemy = import_optional_dependency("sqlalchemy", errors="ignore") - if sqlalchemy is not None: - if isinstance(con, str): + if isinstance(con, str): + if sqlalchemy is None: + raise ImportError("Using URI string without sqlalchemy installed.") + else: con = sqlalchemy.create_engine(con) - if isinstance(con, sqlalchemy.engine.Connectable): - return SQLDatabase(con, schema=schema) + if sqlalchemy is not None and isinstance(con, sqlalchemy.engine.Connectable): + return SQLDatabase(con, schema=schema) warnings.warn( "pandas only support SQLAlchemy connectable(engine/connection) or" diff --git a/pandas/tests/io/test_sql.py b/pandas/tests/io/test_sql.py index df823587b296e..d44ee3449448c 100644 --- a/pandas/tests/io/test_sql.py +++ b/pandas/tests/io/test_sql.py @@ -1524,7 +1524,8 @@ def test_sql_open_close(self, test_frame3): @pytest.mark.skipif(SQLALCHEMY_INSTALLED, reason="SQLAlchemy is installed") def test_con_string_import_error(self): conn = "mysql://root@localhost/pandas" - with pytest.raises(ImportError, match="SQLAlchemy"): + msg = "Using URI string without sqlalchemy installed" + with pytest.raises(ImportError, match=msg): sql.read_sql("SELECT * FROM iris", conn) @pytest.mark.skipif(SQLALCHEMY_INSTALLED, reason="SQLAlchemy is installed") From 0fa71e14f66d8b7ea514aa5d4ea5cf73584ee05e Mon Sep 17 00:00:00 2001 From: Adam Bowden <23028875+abowden1989@users.noreply.github.com> Date: Fri, 28 Jan 2022 14:49:54 +0000 Subject: [PATCH 4/5] Add assertion that warning is produced --- pandas/tests/io/test_sql.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pandas/tests/io/test_sql.py b/pandas/tests/io/test_sql.py index d44ee3449448c..f287a47259c94 100644 --- a/pandas/tests/io/test_sql.py +++ b/pandas/tests/io/test_sql.py @@ -1540,7 +1540,8 @@ def __getattr__(self, name): return getattr(self.conn, name) conn = MockSqliteConnection(":memory:") - sql.read_sql("SELECT 1", conn) + with tm.assert_produces_warning(UserWarning): + sql.read_sql("SELECT 1", conn) def test_read_sql_delegate(self): iris_frame1 = sql.read_sql_query("SELECT * FROM iris", self.conn) From a2c29eb329467e8de136899d6a41c1bff409fa9e Mon Sep 17 00:00:00 2001 From: Daniel O'Brien Date: Mon, 31 Jan 2022 12:12:27 +0000 Subject: [PATCH 5/5] Update whatsnew for v1.4.1 with regression in read_sql incorrectly requiring SQLAlchemy Co-authored-by: Daniel O'Brien Co-authored-by: Joshua C. Randall --- doc/source/whatsnew/v1.4.1.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/whatsnew/v1.4.1.rst b/doc/source/whatsnew/v1.4.1.rst index 1bd8da2d2b03c..ce8178f1b0f88 100644 --- a/doc/source/whatsnew/v1.4.1.rst +++ b/doc/source/whatsnew/v1.4.1.rst @@ -16,6 +16,7 @@ Fixed regressions ~~~~~~~~~~~~~~~~~ - Regression in :meth:`Series.mask` with ``inplace=True`` and ``PeriodDtype`` and an incompatible ``other`` coercing to a common dtype instead of raising (:issue:`45546`) - Regression in :meth:`DataFrame.loc.__setitem__` losing :class:`Index` name if :class:`DataFrame` was empty before (:issue:`45621`) +- Regression in :func:`read_sql` with a DBAPI2 connection that is not an instance of ``sqlite3.Connection`` incorrectly requiring SQLAlchemy be installed (:issue:`45660`) - .. ---------------------------------------------------------------------------