diff --git a/py-polars/polars/__init__.py b/py-polars/polars/__init__.py index c2fefa29a5b1..4ca4c40bd534 100644 --- a/py-polars/polars/__init__.py +++ b/py-polars/polars/__init__.py @@ -25,7 +25,7 @@ __register_startup_deps() -from typing import Any +from typing import TYPE_CHECKING, Any from polars import api, exceptions, plugins, selectors from polars._utils.polars_version import get_polars_version as _get_polars_version @@ -455,33 +455,36 @@ ] -def __getattr__(name: str) -> Any: - # Deprecate re-export of exceptions at top-level - if name in dir(exceptions): - from polars._utils.deprecation import issue_deprecation_warning +if not TYPE_CHECKING: + # This causes typechecking to resolve any Polars module attribute + # as Any regardless of existence so we check for TYPE_CHECKING, see #24334. + def __getattr__(name: str) -> Any: + # Deprecate re-export of exceptions at top-level + if name in dir(exceptions): + from polars._utils.deprecation import issue_deprecation_warning - issue_deprecation_warning( - message=( - f"accessing `{name}` from the top-level `polars` module was deprecated " - "in version 1.0.0. Import it directly from the `polars.exceptions` module " - f"instead, e.g.: `from polars.exceptions import {name}`" - ), - ) - return getattr(exceptions, name) + issue_deprecation_warning( + message=( + f"accessing `{name}` from the top-level `polars` module was deprecated " + "in version 1.0.0. Import it directly from the `polars.exceptions` module " + f"instead, e.g.: `from polars.exceptions import {name}`" + ), + ) + return getattr(exceptions, name) - # Deprecate data type groups at top-level - import polars.datatypes.group as dtgroup + # Deprecate data type groups at top-level + import polars.datatypes.group as dtgroup - if name in dir(dtgroup): - from polars._utils.deprecation import issue_deprecation_warning + if name in dir(dtgroup): + from polars._utils.deprecation import issue_deprecation_warning - issue_deprecation_warning( - message=( - f"`{name}` was deprecated in version 1.0.0. Define your own data type groups or " - "use the `polars.selectors` module for selecting columns of a certain data type." - ), - ) - return getattr(dtgroup, name) + issue_deprecation_warning( + message=( + f"`{name}` was deprecated in version 1.0.0. Define your own data type groups or " + "use the `polars.selectors` module for selecting columns of a certain data type." + ), + ) + return getattr(dtgroup, name) - msg = f"module {__name__!r} has no attribute {name!r}" - raise AttributeError(msg) + msg = f"module {__name__!r} has no attribute {name!r}" + raise AttributeError(msg) diff --git a/py-polars/tests/unit/datatypes/test_struct.py b/py-polars/tests/unit/datatypes/test_struct.py index bd5123c1f9ec..f70f783529b0 100644 --- a/py-polars/tests/unit/datatypes/test_struct.py +++ b/py-polars/tests/unit/datatypes/test_struct.py @@ -15,7 +15,7 @@ from polars.testing import assert_frame_equal, assert_series_equal if TYPE_CHECKING: - from polars._typing import PolarsDataType + from polars._typing import PolarsDataType, SerializationFormat def test_struct_to_list() -> None: @@ -1108,7 +1108,7 @@ def test_zfs_struct_fns() -> None: @pytest.mark.parametrize("format", ["binary", "json"]) @pytest.mark.parametrize("size", [0, 1, 2, 13]) -def test_zfs_serialization_roundtrip(format: pl.SerializationFormat, size: int) -> None: +def test_zfs_serialization_roundtrip(format: SerializationFormat, size: int) -> None: a = pl.Series("a", [{}] * size, pl.Struct([])).to_frame() f = io.BytesIO() diff --git a/py-polars/tests/unit/io/test_parquet.py b/py-polars/tests/unit/io/test_parquet.py index 20f239f6c5a7..6a4e590de5ca 100644 --- a/py-polars/tests/unit/io/test_parquet.py +++ b/py-polars/tests/unit/io/test_parquet.py @@ -1903,7 +1903,7 @@ def test_empty_parquet() -> None: ) @pytest.mark.write_disk def test_row_index_projection_pushdown_18463( - tmp_path: Path, strategy: pl.ParallelStrategy + tmp_path: Path, strategy: ParallelStrategy ) -> None: tmp_path.mkdir(exist_ok=True) f = tmp_path / "test.parquet" @@ -2141,7 +2141,7 @@ def test_decimal_precision_nested_roundtrip( @pytest.mark.may_fail_cloud # reason: sortedness flag @pytest.mark.parametrize("parallel", ["prefiltered", "columns", "row_groups", "auto"]) def test_conserve_sortedness( - monkeypatch: Any, capfd: pytest.CaptureFixture[str], parallel: pl.ParallelStrategy + monkeypatch: Any, capfd: pytest.CaptureFixture[str], parallel: ParallelStrategy ) -> None: f = io.BytesIO() diff --git a/py-polars/tests/unit/test_init.py b/py-polars/tests/unit/test_init.py index 987404784c1e..34e4288a875d 100644 --- a/py-polars/tests/unit/test_init.py +++ b/py-polars/tests/unit/test_init.py @@ -10,14 +10,14 @@ def test_init_nonexistent_attribute() -> None: with pytest.raises( AttributeError, match="module 'polars' has no attribute 'stroopwafel'" ): - pl.stroopwafel + pl.stroopwafel # type: ignore[attr-defined] def test_init_exceptions_deprecated() -> None: with pytest.deprecated_call( match="accessing `ComputeError` from the top-level `polars` module was deprecated in version 1.0.0." ): - exc = pl.ComputeError + exc = pl.ComputeError # type: ignore[attr-defined] msg = "nope" with pytest.raises(ComputeError, match=msg): @@ -28,7 +28,7 @@ def test_dtype_groups_deprecated() -> None: with pytest.deprecated_call( match="`INTEGER_DTYPES` was deprecated in version 1.0.0." ): - dtypes = pl.INTEGER_DTYPES + dtypes = pl.INTEGER_DTYPES # type: ignore[attr-defined] assert pl.Int8 in dtypes