From b447ff994be76db81910eb600e21f7d92c766f5a Mon Sep 17 00:00:00 2001 From: Sebastian Rittau Date: Thu, 16 Jul 2026 13:06:30 +0200 Subject: [PATCH 1/2] Refactor `VERSIONS` handling `parse_stdlib_versions_file` now returns a class with methods `supported_versions_for_module` and `is_supported`, obsoleting stand-alone function `supported_versions_for_module`. --- lib/ts_utils/utils.py | 30 +++++++++++++++++++----------- tests/mypy_test.py | 5 +---- tests/ty_test.py | 6 ++---- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/lib/ts_utils/utils.py b/lib/ts_utils/utils.py index 6c8cd022aa70..d72f2abefd3c 100644 --- a/lib/ts_utils/utils.py +++ b/lib/ts_utils/utils.py @@ -149,14 +149,30 @@ def get_mypy_req() -> str: # ==================================================================== VersionTuple: TypeAlias = tuple[int, int] -SupportedVersionsDict: TypeAlias = dict[str, tuple[VersionTuple, VersionTuple]] VERSIONS_PATH = STDLIB_PATH / "VERSIONS" VERSION_LINE_RE = re.compile(r"^([a-zA-Z_][a-zA-Z0-9_.]*): ([23]\.\d{1,2})-([23]\.\d{1,2})?$") VERSION_RE = re.compile(r"^([23])\.(\d+)$") -def parse_stdlib_versions_file() -> SupportedVersionsDict: +class SupportedVersions: + def __init__(self, module_versions: dict[str, tuple[VersionTuple, VersionTuple]]) -> None: + self.module_versions = module_versions + + def supported_versions_for_module(self, module_name: str) -> tuple[VersionTuple, VersionTuple]: + while "." in module_name: + if module_name in self.module_versions: + return self.module_versions[module_name] + module_name = ".".join(module_name.split(".")[:-1]) + return self.module_versions[module_name] + + def is_supported(self, module_name: str, version: str) -> bool: + version_tuple = tuple(map(int, version.split("."))) + minimum, maximum = self.supported_versions_for_module(module_name) + return minimum <= version_tuple <= maximum + + +def parse_stdlib_versions_file() -> SupportedVersions: result: dict[str, tuple[VersionTuple, VersionTuple]] = {} with VERSIONS_PATH.open(encoding="UTF-8") as f: for line in f: @@ -170,15 +186,7 @@ def parse_stdlib_versions_file() -> SupportedVersionsDict: min_version = _parse_version(m.group(2)) max_version = _parse_version(m.group(3)) if m.group(3) else (99, 99) result[mod] = min_version, max_version - return result - - -def supported_versions_for_module(module_versions: SupportedVersionsDict, module_name: str) -> tuple[VersionTuple, VersionTuple]: - while "." in module_name: - if module_name in module_versions: - return module_versions[module_name] - module_name = ".".join(module_name.split(".")[:-1]) - return module_versions[module_name] + return SupportedVersions(result) def _parse_version(v_str: str) -> tuple[int, int]: diff --git a/tests/mypy_test.py b/tests/mypy_test.py index 1fd8a87f2618..e88171f4bfe4 100755 --- a/tests/mypy_test.py +++ b/tests/mypy_test.py @@ -33,7 +33,6 @@ print_error, print_success_msg, spec_matches_path, - supported_versions_for_module, venv_python, ) @@ -311,15 +310,13 @@ def test_stdlib(args: TestConfig) -> TestResult: def remove_modules_not_in_python_version(paths: list[Path], py_version: VersionString) -> list[Path]: - py_version_tuple = tuple(map(int, py_version.split("."))) module_versions = parse_stdlib_versions_file() new_paths: list[Path] = [] for path in paths: if path.parts[0] != "stdlib" or path.suffix != ".pyi": continue module_name = stdlib_module_name_from_path(path) - min_version, max_version = supported_versions_for_module(module_versions, module_name) - if min_version <= py_version_tuple <= max_version: + if module_versions.is_supported(module_name, py_version): new_paths.append(path) return new_paths diff --git a/tests/ty_test.py b/tests/ty_test.py index 909a1f4d852b..9aa087413a32 100755 --- a/tests/ty_test.py +++ b/tests/ty_test.py @@ -9,7 +9,7 @@ from pathlib import Path from ts_utils.paths import STDLIB_PATH, STUBS_PATH, TS_BASE_PATH -from ts_utils.utils import parse_stdlib_versions_file, supported_versions_for_module +from ts_utils.utils import parse_stdlib_versions_file SUPPORTED_VERSIONS = ("3.10", "3.11", "3.12", "3.13", "3.14", "3.15") SUPPORTED_PLATFORMS = ("linux", "darwin", "win32") @@ -19,7 +19,6 @@ def stdlib_files(version: str) -> list[Path]: """Return the stdlib stubs available in the requested Python version.""" - version_tuple = tuple(map(int, version.split("."))) module_versions = parse_stdlib_versions_file() files: list[Path] = [] @@ -33,8 +32,7 @@ def stdlib_files(version: str) -> list[Path]: parts = list(relative.parts[:-1]) if relative.name != "__init__.pyi": parts.append(relative.stem) - minimum, maximum = supported_versions_for_module(module_versions, ".".join(parts)) - if minimum <= version_tuple <= maximum: + if module_versions.is_supported(".".join(parts), version): files.append(path) return files From 7a37198a93ac56b7ec855490219e9a17aab56e98 Mon Sep 17 00:00:00 2001 From: Sebastian Rittau Date: Thu, 16 Jul 2026 13:09:40 +0200 Subject: [PATCH 2/2] Fix typeshed structure script --- tests/check_typeshed_structure.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/check_typeshed_structure.py b/tests/check_typeshed_structure.py index 8c3892ff04a6..8748c80aea5a 100755 --- a/tests/check_typeshed_structure.py +++ b/tests/check_typeshed_structure.py @@ -130,7 +130,7 @@ def check_no_symlinks() -> None: def check_versions_file() -> None: """Check that the stdlib/VERSIONS file has the correct format.""" - version_map = parse_stdlib_versions_file() + version_map = parse_stdlib_versions_file().module_versions versions = list(version_map.keys()) sorted_versions = sorted(versions)