diff --git a/scripts/sync_test_dependencies.py b/scripts/sync_test_dependencies.py index 498d08c9e..6da3dbf66 100644 --- a/scripts/sync_test_dependencies.py +++ b/scripts/sync_test_dependencies.py @@ -34,9 +34,9 @@ PYPROJECT_FILE = Path("pyproject.toml") DEV_EXTRA = "dev" -# Stdlib modules that don't need to be installed (keep in sync with -# tests/test_dependency_enforcement.py) -STDLIB_MODULES = { +# Stdlib modules that don't need to be installed. Prefer Python's runtime +# inventory and keep a fallback for older runtimes/consumer scripts. +_FALLBACK_STDLIB_MODULES = { "abc", "argparse", "ast", @@ -55,6 +55,8 @@ "gc", "glob", "hashlib", + "html", + "http", "importlib", "inspect", "io", @@ -73,6 +75,7 @@ "runpy", "shlex", "shutil", + "secrets", "signal", "sitecustomize", "socket", @@ -104,6 +107,7 @@ "traceback", "pprint", } +STDLIB_MODULES = set(getattr(sys, "stdlib_module_names", ())) | _FALLBACK_STDLIB_MODULES # Known test framework modules TEST_FRAMEWORK_MODULES = { @@ -224,6 +228,7 @@ def get_project_modules() -> set[str]: "PIL": "Pillow", "sklearn": "scikit-learn", "cv2": "opencv-python", + "jwt": "PyJWT", "pre_commit": "pre-commit", "pptx": "python-pptx", } diff --git a/templates/consumer-repo/scripts/sync_test_dependencies.py b/templates/consumer-repo/scripts/sync_test_dependencies.py index 2c4beddba..6da3dbf66 100644 --- a/templates/consumer-repo/scripts/sync_test_dependencies.py +++ b/templates/consumer-repo/scripts/sync_test_dependencies.py @@ -34,9 +34,9 @@ PYPROJECT_FILE = Path("pyproject.toml") DEV_EXTRA = "dev" -# Stdlib modules that don't need to be installed (keep in sync with -# tests/test_dependency_enforcement.py) -STDLIB_MODULES = { +# Stdlib modules that don't need to be installed. Prefer Python's runtime +# inventory and keep a fallback for older runtimes/consumer scripts. +_FALLBACK_STDLIB_MODULES = { "abc", "argparse", "ast", @@ -55,6 +55,8 @@ "gc", "glob", "hashlib", + "html", + "http", "importlib", "inspect", "io", @@ -73,6 +75,7 @@ "runpy", "shlex", "shutil", + "secrets", "signal", "sitecustomize", "socket", @@ -96,6 +99,7 @@ "weakref", "xml", "zipfile", + "zlib", "__future__", "dataclasses", "enum", @@ -103,6 +107,7 @@ "traceback", "pprint", } +STDLIB_MODULES = set(getattr(sys, "stdlib_module_names", ())) | _FALLBACK_STDLIB_MODULES # Known test framework modules TEST_FRAMEWORK_MODULES = { @@ -223,6 +228,7 @@ def get_project_modules() -> set[str]: "PIL": "Pillow", "sklearn": "scikit-learn", "cv2": "opencv-python", + "jwt": "PyJWT", "pre_commit": "pre-commit", "pptx": "python-pptx", } diff --git a/tests/scripts/test_sync_test_dependencies.py b/tests/scripts/test_sync_test_dependencies.py index cb1f87f09..f7d99cf65 100644 --- a/tests/scripts/test_sync_test_dependencies.py +++ b/tests/scripts/test_sync_test_dependencies.py @@ -218,6 +218,44 @@ def test_find_missing_dependencies_ignores_local_and_mapped_modules( assert std.find_missing_dependencies() == {"pandas"} +def test_find_missing_dependencies_ignores_reviewed_stdlib_and_maps_jwt( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + pyproject = tmp_path / "pyproject.toml" + pyproject.write_text( + "\n".join( + [ + "[project.optional-dependencies]", + "dev = [", + ' "PyJWT[crypto]",', + "]", + ] + ) + + "\n", + encoding="utf-8", + ) + tests_dir = tmp_path / "tests" + tests_dir.mkdir() + (tests_dir / "test_reviewed_imports.py").write_text( + "\n".join( + [ + "import html", + "from http.server import BaseHTTPRequestHandler", + "import secrets", + "import jwt", + "import pandas", + ] + ) + + "\n", + encoding="utf-8", + ) + + monkeypatch.chdir(tmp_path) + monkeypatch.setattr(std, "PYPROJECT_FILE", pyproject) + + assert std.find_missing_dependencies() == {"pandas"} + + def test_detect_local_project_modules_skips_missing_source_dir( tmp_path: Path, monkeypatch: pytest.MonkeyPatch ) -> None: diff --git a/tests/scripts/test_sync_test_dependencies_mapping.py b/tests/scripts/test_sync_test_dependencies_mapping.py index c722748c6..f5367e247 100644 --- a/tests/scripts/test_sync_test_dependencies_mapping.py +++ b/tests/scripts/test_sync_test_dependencies_mapping.py @@ -13,19 +13,23 @@ def _load_module(module_name: str, path: Path): return module -def test_pptx_maps_to_python_pptx_in_repo_script(): +def test_import_exceptions_map_to_package_names_in_repo_script(): module = _load_module( "sync_test_dependencies_repo", Path("scripts/sync_test_dependencies.py"), ) assert module.MODULE_TO_PACKAGE["pptx"] == "python-pptx" + assert module.MODULE_TO_PACKAGE["jwt"] == "PyJWT" + assert {"html", "http", "secrets"}.issubset(module.STDLIB_MODULES) -def test_pptx_maps_to_python_pptx_in_consumer_template(): +def test_import_exceptions_map_to_package_names_in_consumer_template(): module = _load_module( "sync_test_dependencies_consumer_template", Path("templates/consumer-repo/scripts/sync_test_dependencies.py"), ) assert module.MODULE_TO_PACKAGE["pptx"] == "python-pptx" + assert module.MODULE_TO_PACKAGE["jwt"] == "PyJWT" + assert {"html", "http", "secrets"}.issubset(module.STDLIB_MODULES)