]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-118761: Add helper to ensure that lazy imports are actually lazy (#132614)
authorJelle Zijlstra <jelle.zijlstra@gmail.com>
Thu, 17 Apr 2025 03:46:36 +0000 (20:46 -0700)
committerGitHub <noreply@github.com>
Thu, 17 Apr 2025 03:46:36 +0000 (03:46 +0000)
This ensures that if we jump through some hoops to make sure something is imported
lazily, we don't regress on importing it.

I recently already accidentally made typing import warnings and annotationlib eagerly.

Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
Lib/test/support/import_helper.py
Lib/test/test_annotationlib.py
Lib/test/test_typing.py

index 2b91bdcf9cd8595cabdf1840cd6ff077019f2969..42cfe9cfa8cb72e4eb16a7d1b59963cfc19b52fc 100644 (file)
@@ -5,6 +5,7 @@ import importlib.util
 import os
 import shutil
 import sys
+import textwrap
 import unittest
 import warnings
 
@@ -309,3 +310,25 @@ def ready_to_import(name=None, source=""):
                 sys.modules[name] = old_module
             else:
                 sys.modules.pop(name, None)
+
+
+def ensure_lazy_imports(imported_module, modules_to_block):
+    """Test that when imported_module is imported, none of the modules in
+    modules_to_block are imported as a side effect."""
+    modules_to_block = frozenset(modules_to_block)
+    script = textwrap.dedent(
+        f"""
+        import sys
+        modules_to_block = {modules_to_block}
+        if unexpected := modules_to_block & sys.modules.keys():
+            startup = ", ".join(unexpected)
+            raise AssertionError(f'unexpectedly imported at startup: {{startup}}')
+
+        import {imported_module}
+        if unexpected := modules_to_block & sys.modules.keys():
+            after = ", ".join(unexpected)
+            raise AssertionError(f'unexpectedly imported after importing {imported_module}: {{after}}')
+        """
+    )
+    from .script_helper import assert_python_ok
+    assert_python_ok("-S", "-c", script)
index 6f097c07295f3b49cd244e1d1bcfd1acd09af9f5..0890be529a7e525f7aa6b703567a7d0010a4f341 100644 (file)
@@ -24,6 +24,7 @@ from typing import (
 )
 
 from test import support
+from test.support import import_helper
 from test.test_inspect import inspect_stock_annotations
 from test.test_inspect import inspect_stringized_annotations
 from test.test_inspect import inspect_stringized_annotations_2
@@ -1367,3 +1368,9 @@ class ForwardRefTests(unittest.TestCase):
 class TestAnnotationLib(unittest.TestCase):
     def test__all__(self):
         support.check__all__(self, annotationlib)
+
+    def test_lazy_imports(self):
+        import_helper.ensure_lazy_imports("annotationlib", {
+            "typing",
+            "warnings",
+        })
index 32f12a3f8b22f104645e2839f5d9b0be8dd5dd36..81474a81be645d2f4284a9e744f30c0c60a45c6b 100644 (file)
@@ -6317,6 +6317,15 @@ class InternalsTests(BaseTestCase):
             typing._collect_parameters
         self.assertEqual(cm.filename, __file__)
 
+    def test_lazy_import(self):
+        import_helper.ensure_lazy_imports("typing", {
+            "warnings",
+            "inspect",
+            "re",
+            "contextlib",
+            # "annotationlib",  # TODO
+        })
+
 
 @lru_cache()
 def cached_func(x, y):