diff --git a/narwhals/__init__.py b/narwhals/__init__.py index 52e0eb0506..e0dc71bf48 100644 --- a/narwhals/__init__.py +++ b/narwhals/__init__.py @@ -177,13 +177,17 @@ ] -def __getattr__(name: _t.Literal["__version__"]) -> str: # type: ignore[misc] - if name == "__version__": - global __version__ # noqa: PLW0603 +if not _t.TYPE_CHECKING: - from importlib import metadata + def __getattr__(name: str) -> _t.Any: + if name == "__version__": + global __version__ # noqa: PLW0603 - __version__ = metadata.version(__name__) - return __version__ - msg = f"module {__name__!r} has no attribute {name!r}" - raise AttributeError(msg) + from importlib import metadata + + __version__ = metadata.version(__name__) + return __version__ + msg = f"module {__name__!r} has no attribute {name!r}" + raise AttributeError(msg) +else: # pragma: no cover + ... diff --git a/tests/version_test.py b/tests/version_test.py index 98846ee9bf..c0f2ace7d7 100644 --- a/tests/version_test.py +++ b/tests/version_test.py @@ -1,9 +1,13 @@ from __future__ import annotations import re +from collections.abc import Callable from importlib.metadata import distribution from os import environ from pathlib import Path +from typing import TYPE_CHECKING, Any + +import pytest import narwhals as nw from narwhals._utils import parse_version @@ -35,3 +39,20 @@ def test_package_version() -> None: assert version_comp <= parse_version(pyproject_version) dist_version = distribution("narwhals").version assert version == dist_version + + +def test_package_getattr() -> None: + pytest.importorskip("typing_extensions") + from typing_extensions import assert_type + + ok = nw.__version__ + assert_type(ok, str) + also_ok = nw.all + assert_type(also_ok, Callable[[], nw.Expr]) + + if TYPE_CHECKING: + bad = nw.not_real # type: ignore[attr-defined] + assert_type(bad, Any) + + with pytest.raises(AttributeError): + very_bad = nw.not_real # type: ignore[attr-defined] # noqa: F841