Skip to content

Commit 39ee468

Browse files
gh-118761: Add helper to ensure that lazy imports are actually lazy (#132614)
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>
1 parent b530e17 commit 39ee468

File tree

3 files changed

+39
-0
lines changed

3 files changed

+39
-0
lines changed

Lib/test/support/import_helper.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import os
66
import shutil
77
import sys
8+
import textwrap
89
import unittest
910
import warnings
1011

@@ -309,3 +310,25 @@ def ready_to_import(name=None, source=""):
309310
sys.modules[name] = old_module
310311
else:
311312
sys.modules.pop(name, None)
313+
314+
315+
def ensure_lazy_imports(imported_module, modules_to_block):
316+
"""Test that when imported_module is imported, none of the modules in
317+
modules_to_block are imported as a side effect."""
318+
modules_to_block = frozenset(modules_to_block)
319+
script = textwrap.dedent(
320+
f"""
321+
import sys
322+
modules_to_block = {modules_to_block}
323+
if unexpected := modules_to_block & sys.modules.keys():
324+
startup = ", ".join(unexpected)
325+
raise AssertionError(f'unexpectedly imported at startup: {{startup}}')
326+
327+
import {imported_module}
328+
if unexpected := modules_to_block & sys.modules.keys():
329+
after = ", ".join(unexpected)
330+
raise AssertionError(f'unexpectedly imported after importing {imported_module}: {{after}}')
331+
"""
332+
)
333+
from .script_helper import assert_python_ok
334+
assert_python_ok("-S", "-c", script)

Lib/test/test_annotationlib.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
)
2525

2626
from test import support
27+
from test.support import import_helper
2728
from test.test_inspect import inspect_stock_annotations
2829
from test.test_inspect import inspect_stringized_annotations
2930
from test.test_inspect import inspect_stringized_annotations_2
@@ -1367,3 +1368,9 @@ def test_multiple_ways_to_create(self):
13671368
class TestAnnotationLib(unittest.TestCase):
13681369
def test__all__(self):
13691370
support.check__all__(self, annotationlib)
1371+
1372+
def test_lazy_imports(self):
1373+
import_helper.ensure_lazy_imports("annotationlib", {
1374+
"typing",
1375+
"warnings",
1376+
})

Lib/test/test_typing.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6317,6 +6317,15 @@ def test_collect_parameters(self):
63176317
typing._collect_parameters
63186318
self.assertEqual(cm.filename, __file__)
63196319

6320+
def test_lazy_import(self):
6321+
import_helper.ensure_lazy_imports("typing", {
6322+
"warnings",
6323+
"inspect",
6324+
"re",
6325+
"contextlib",
6326+
# "annotationlib", # TODO
6327+
})
6328+
63206329

63216330
@lru_cache()
63226331
def cached_func(x, y):

0 commit comments

Comments
 (0)