diff --git a/doc/source/whatsnew/v3.1.0.rst b/doc/source/whatsnew/v3.1.0.rst index 5fe30b4189717..55884d98714fe 100644 --- a/doc/source/whatsnew/v3.1.0.rst +++ b/doc/source/whatsnew/v3.1.0.rst @@ -346,6 +346,7 @@ MultiIndex I/O ^^^ - :func:`read_csv` with ``memory_map=True`` and an in-memory buffer (e.g. ``BytesIO``) now raises a clear ``ValueError`` instead of a cryptic ``UnsupportedOperation: fileno`` (:issue:`45630`) +- :meth:`DataFrame.to_sql` now raises a clearer ``ValueError`` when a non-string ``dtype`` is passed for a raw DB-API (e.g. sqlite3) connection (:issue:`61385`) - Fixed bug in :func:`read_csv` with the ``c`` engine where an embedded ``\r`` followed by a space in an unquoted field could cause an infinite re-parsing loop, producing spurious rows or a buffer overflow (:issue:`51141`) - Fixed bug in :func:`read_excel` where usage of ``skiprows`` could lead to an infinite loop (:issue:`64027`) - Fixed bug where :func:`read_html` parsed nested tables incorrectly when using ``html5lib`` or ``bs4`` flavors (:issue:`64524`) diff --git a/pandas/io/sql.py b/pandas/io/sql.py index f79f037d908fe..51120d5cec431 100644 --- a/pandas/io/sql.py +++ b/pandas/io/sql.py @@ -2867,7 +2867,12 @@ def to_sql( for col, my_type in dtype.items(): if not isinstance(my_type, str): - raise ValueError(f"{col} ({my_type}) not a string") + raise ValueError( + f"Invalid type '{my_type}' for dtype of column '{col}': " + "expected a string. When using a DB-API connection " + "(e.g. sqlite3), dtype values must be SQL type " + "strings (e.g. 'TEXT', 'FLOAT')." + ) table = SQLiteTable( name, diff --git a/pandas/tests/io/test_sql.py b/pandas/tests/io/test_sql.py index 63feb8c12e359..861ca8afd5f79 100644 --- a/pandas/tests/io/test_sql.py +++ b/pandas/tests/io/test_sql.py @@ -4066,7 +4066,7 @@ def test_sqlite_test_dtype(sqlite_buildin): assert get_sqlite_column_type(conn, "dtype_test", "B") == "INTEGER" assert get_sqlite_column_type(conn, "dtype_test2", "B") == "STRING" - msg = r"B \(\) not a string" + msg = r"Invalid type '' for dtype of column 'B': expected a string" with pytest.raises(ValueError, match=msg): df.to_sql(name="error", con=conn, dtype={"B": bool})