Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(python)!: Removal of read_database_uri passthrough from read_database #16783

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 12 additions & 34 deletions py-polars/polars/io/database/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
import re
from typing import TYPE_CHECKING, Any, Iterable, Literal, overload

from polars._utils.deprecation import issue_deprecation_warning
from polars.datatypes import N_INFER_DEFAULT
from polars.dependencies import import_optional
from polars.exceptions import InvalidOperationError
from polars.io.database._cursor_proxies import ODBCCursorProxy
from polars.io.database._executor import ConnectionExecutor

Expand Down Expand Up @@ -37,7 +35,6 @@ def read_database(
schema_overrides: SchemaDict | None = ...,
infer_schema_length: int | None = ...,
execute_options: dict[str, Any] | None = ...,
**kwargs: Any,
) -> DataFrame: ...


Expand All @@ -51,7 +48,6 @@ def read_database(
schema_overrides: SchemaDict | None = ...,
infer_schema_length: int | None = ...,
execute_options: dict[str, Any] | None = ...,
**kwargs: Any,
) -> Iterable[DataFrame]: ...


Expand All @@ -65,11 +61,10 @@ def read_database(
schema_overrides: SchemaDict | None = ...,
infer_schema_length: int | None = ...,
execute_options: dict[str, Any] | None = ...,
**kwargs: Any,
) -> DataFrame | Iterable[DataFrame]: ...


def read_database( # noqa: D417
def read_database(
query: str | Selectable,
connection: ConnectionOrCursor | str,
*,
Expand All @@ -78,7 +73,6 @@ def read_database( # noqa: D417
schema_overrides: SchemaDict | None = None,
infer_schema_length: int | None = N_INFER_DEFAULT,
execute_options: dict[str, Any] | None = None,
**kwargs: Any,
) -> DataFrame | Iterable[DataFrame]:
"""
Read the results of a SQL query into a DataFrame, given a connection object.
Expand Down Expand Up @@ -147,17 +141,18 @@ def read_database( # noqa: D417

* The `read_database_uri` function can be noticeably faster than `read_database`
if you are using a SQLAlchemy or DBAPI2 connection, as `connectorx` and `adbc`
optimises translation of the result set into Arrow format. Note that you can
optimise translation of the result set into Arrow format. Note that you can
determine a connection's URI from a SQLAlchemy engine object by calling
`conn.engine.url.render_as_string(hide_password=False)`.

* If Polars has to create a cursor from your connection in order to execute the
query then that cursor will be automatically closed when the query completes;
however, Polars will *never* close any other open connection or cursor.

* We are able to support more than just relational databases and SQL queries
through this function. For example, we can load graph database results from
a `KùzuDB` connection in conjunction with a Cypher query.
* Polars is able to support more than just relational databases and SQL queries
through this function. For example, you can load local graph database results
from a `KùzuDB` connection in conjunction with a Cypher query, or use SurrealQL
with SurrealDB.

See Also
--------
Expand Down Expand Up @@ -245,30 +240,13 @@ def read_database( # noqa: D417
err_suffix="package",
)
connection = ODBCCursorProxy(connection)
elif "://" in connection:
# otherwise looks like a mistaken call to read_database_uri
msg = "Use of string URI is invalid here; call `read_database_uri` instead"
raise ValueError(msg)
else:
# otherwise looks like a call to read_database_uri
issue_deprecation_warning(
message="Use of a string URI with 'read_database' is deprecated; use `read_database_uri` instead",
version="0.19.0",
)
if iter_batches or batch_size:
msg = "Batch parameters are not supported for `read_database_uri`"
raise InvalidOperationError(msg)
if not isinstance(query, (list, str)):
msg = f"`read_database_uri` expects one or more string queries; found {type(query)}"
raise TypeError(msg)
return read_database_uri(
query,
uri=connection,
schema_overrides=schema_overrides,
**kwargs,
)

# note: can remove this check (and **kwargs) once we drop the
# pass-through deprecation support for read_database_uri
if kwargs:
msg = f"`read_database` **kwargs only exist for passthrough to `read_database_uri`: found {kwargs!r}"
raise ValueError(msg)
msg = "unable to identify string connection as valid ODBC (no driver)"
raise ValueError(msg)

# return frame from arbitrary connections using the executor abstraction
with ConnectionExecutor(connection) as cx:
Expand Down
26 changes: 13 additions & 13 deletions py-polars/tests/unit/io/database/test_read.py
Original file line number Diff line number Diff line change
Expand Up @@ -593,17 +593,6 @@ def test_read_database_mocked(
),
id="Invalid statement type",
),
pytest.param(
*ExceptionTestParams(
read_method="read_database",
query="SELECT * FROM test_data",
protocol=sqlite3.connect(":memory:"),
errclass=ValueError,
errmsg=r"`read_database` \*\*kwargs only exist for passthrough to `read_database_uri`",
kwargs={"partition_on": "id"},
),
id="Invalid kwargs",
),
pytest.param(
*ExceptionTestParams(
read_method="read_database",
Expand All @@ -621,12 +610,23 @@ def test_read_database_mocked(
engine="adbc",
query="SELECT * FROM test_data",
protocol=sqlite3.connect(":memory:"),
errclass=ValueError,
errmsg=r"`read_database` \*\*kwargs only exist for passthrough to `read_database_uri`",
errclass=TypeError,
errmsg=r"unexpected keyword argument 'partition_on'",
kwargs={"partition_on": "id"},
),
id="Invalid kwargs",
),
pytest.param(
*ExceptionTestParams(
read_method="read_database",
engine="adbc",
query="SELECT * FROM test_data",
protocol="{not:a, valid:odbc_string}",
errclass=ValueError,
errmsg=r"unable to identify string connection as valid ODBC",
),
id="Invalid ODBC string",
),
],
)
def test_read_database_exceptions(
Expand Down