From c260f2740ec331c9d22c77f065aa04a0e3ee8115 Mon Sep 17 00:00:00 2001 From: mao <118530756+maoxor@users.noreply.github.com> Date: Thu, 29 Oct 2026 12:44:20 +0100 Subject: [PATCH] Keep `from python_utils.types import *` working on Python 3.15 Python 3.15 removed `typing.ByteString` and `typing.no_type_check_decorator`, so `from typing import *` no longer provides them, but both were still listed in `__all__` and the star import raised `AttributeError`. List them only on Python < 3.15. Add regression tests that every `__all__` entry resolves and that the star import exports all of them, and run the test suite on 3.15 in CI and tox. --- .github/workflows/ci.yml | 2 +- _python_utils_tests/test_types.py | 17 +++++++++++++++++ pyproject.toml | 1 + python_utils/types.py | 8 ++++++-- tox.ini | 5 +++-- 5 files changed, 28 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6c7ad17..aae01c4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: fail-fast: false matrix: python-version: - ['3.10', '3.11', '3.12', '3.13', '3.14', 'pypy3.10', 'pypy3.11'] + ['3.10', '3.11', '3.12', '3.13', '3.14', '3.15', 'pypy3.10', 'pypy3.11'] steps: - uses: actions/checkout@v7 - uses: astral-sh/setup-uv@v8.2.0 diff --git a/_python_utils_tests/test_types.py b/_python_utils_tests/test_types.py index 7da66ba..c6c4bd7 100644 --- a/_python_utils_tests/test_types.py +++ b/_python_utils_tests/test_types.py @@ -13,3 +13,20 @@ def test_types_all_entries_are_unique() -> None: ) assert duplicates == [] + + +def test_types_all_entries_exist() -> None: + """Resolve every name in ``__all__`` so star imports keep working.""" + missing: list[str] = [ + name for name in types.__all__ if not hasattr(types, name) + ] + + assert missing == [] + + +def test_types_star_import() -> None: + """Import the public facade with ``from python_utils.types import *``.""" + namespace: dict[str, object] = {} + exec('from python_utils.types import *', namespace) # noqa: S102 + + assert set(types.__all__) <= namespace.keys() diff --git a/pyproject.toml b/pyproject.toml index e17f5f2..348dfab 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,6 +38,7 @@ classifiers = [ 'Programming Language :: Python :: 3.12', 'Programming Language :: Python :: 3.13', 'Programming Language :: Python :: 3.14', + 'Programming Language :: Python :: 3.15', 'Programming Language :: Python :: 3 :: Only', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', diff --git a/python_utils/types.py b/python_utils/types.py index b975496..8d83a02 100644 --- a/python_utils/types.py +++ b/python_utils/types.py @@ -16,6 +16,7 @@ # `from python_utils.types import datetime, decimal` worked in 3.x. import datetime as datetime import decimal as decimal +import sys from re import Match, Pattern from types import * # pragma: no cover # noqa: F403 from typing import * # pragma: no cover # noqa: F403 @@ -70,7 +71,6 @@ 'BinaryIO', 'BuiltinFunctionType', 'BuiltinMethodType', - 'ByteString', 'Callable', # Concrete collection types. 'ChainMap', @@ -168,10 +168,14 @@ 'is_typeddict', 'new_class', 'no_type_check', - 'no_type_check_decorator', 'overload', 'prepare_class', 'resolve_bases', 'runtime_checkable', 'timestamp_type', ] + +# Python 3.15 removed these from `typing`. Exporting them there would make +# `from python_utils.types import *` raise `AttributeError`. +if sys.version_info < (3, 15): # pragma: no cover + __all__.extend(['ByteString', 'no_type_check_decorator']) diff --git a/tox.ini b/tox.ini index 6425793..c400a6d 100644 --- a/tox.ini +++ b/tox.ini @@ -6,7 +6,7 @@ requires = # PyPy) isn't installed; CI provides each interpreter via tox-gh-actions. skip_missing_interpreters = true env_list = - py{310,311,312,313,314} + py{310,311,312,313,314,315} pypy{310,311} lint mypy @@ -16,7 +16,7 @@ env_list = docs coverage labels = - test = py{310,311,312,313,314}, pypy{310,311} + test = py{310,311,312,313,314,315}, pypy{310,311} check = lint, mypy, pyright, pyrefly, codespell [gh-actions] @@ -26,6 +26,7 @@ python = 3.12: py312 3.13: py313 3.14: py314 + 3.15: py315 pypy-3.10: pypy310 pypy-3.11: pypy311