https://github.com/python/cpython/commit/10d1b63ed8b0261e7a9b7ffc3231eafd89187a4b
commit: 10d1b63ed8b0261e7a9b7ffc3231eafd89187a4b
branch: main
author: Brittany Reynoso <[email protected]>
committer: DinoV <[email protected]>
date: 2026-06-23T13:15:11-07:00
summary:
gh-150565: Add additional tests for Lazy Imports (#149739)
Add lazy import tests ported from internal test suite
files:
A Lib/test/test_lazy_import/data/circular_import_pkg/__init__.py
A Lib/test/test_lazy_import/data/circular_import_pkg/main.py
A Lib/test/test_lazy_import/data/circular_import_pkg/x.py
A Lib/test/test_lazy_import/data/circular_import_pkg/y.py
A Lib/test/test_lazy_import/data/metasyntactic/__init__.py
A Lib/test/test_lazy_import/data/metasyntactic/foo/__init__.py
A Lib/test/test_lazy_import/data/metasyntactic/foo/ack/__init__.py
A Lib/test/test_lazy_import/data/metasyntactic/foo/bar/__init__.py
A Lib/test/test_lazy_import/data/metasyntactic/foo/bar/baz/__init__.py
A Lib/test/test_lazy_import/data/metasyntactic/foo/bar/baz/qux/__init__.py
A Lib/test/test_lazy_import/data/metasyntactic/foo/bar/thud/__init__.py
A Lib/test/test_lazy_import/data/metasyntactic/names.py
A Lib/test/test_lazy_import/data/metasyntactic/plugh/__init__.py
A Lib/test/test_lazy_import/data/metasyntactic/waldo/__init__.py
A Lib/test/test_lazy_import/data/metasyntactic/waldo/fred/__init__.py
A Lib/test/test_lazy_import/data/module_same_name_var_order1/__init__.py
A Lib/test/test_lazy_import/data/module_same_name_var_order1/bar.py
A Lib/test/test_lazy_import/data/module_same_name_var_order2/__init__.py
A Lib/test/test_lazy_import/data/module_same_name_var_order2/bar.py
A Lib/test/test_lazy_import/data/versioned/__init__.py
A Lib/test/test_lazy_import/data/versioned/__version__.py
M Lib/test/test_lazy_import/__init__.py
M Makefile.pre.in
diff --git a/Lib/test/test_lazy_import/__init__.py
b/Lib/test/test_lazy_import/__init__.py
index 1c5ab4ef73da2fb..4658882243d65ff 100644
--- a/Lib/test/test_lazy_import/__init__.py
+++ b/Lib/test/test_lazy_import/__init__.py
@@ -1961,5 +1961,135 @@ def test_dunder_lazy_import_without_frame(self):
)
+class SubmoduleLazinessTests(unittest.TestCase):
+ """Tests that module-level lazy imports remain lazy until accessed."""
+
+ def tearDown(self):
+ for key in list(sys.modules.keys()):
+ if key.startswith('test.test_lazy_import.data'):
+ del sys.modules[key]
+ sys.set_lazy_imports_filter(None)
+ sys.set_lazy_imports("normal")
+
+ def test_unaccessed_imports_stay_lazy(self):
+ """Imports in 'all' mode should stay lazy until accessed."""
+ sys.set_lazy_imports("all")
+ from test.test_lazy_import.data.metasyntactic import names
+ self.assertIsInstance(names.__dict__["Foo"], types.LazyImportType)
+ self.assertNotIn(
+ "test.test_lazy_import.data.metasyntactic.foo", sys.modules
+ )
+ _ = names.Foo
+ self.assertEqual(names.Foo, "Foo")
+ self.assertIn(
+ "test.test_lazy_import.data.metasyntactic.foo", sys.modules
+ )
+ self.assertIsInstance(names.__dict__["Ack"], types.LazyImportType)
+ self.assertNotIn(
+ "test.test_lazy_import.data.metasyntactic.foo.ack", sys.modules
+ )
+
+
+class AttributeSideEffectTests(unittest.TestCase):
+ """Tests that submodule imports don't overwrite parent attributes."""
+
+ def tearDown(self):
+ for key in list(sys.modules.keys()):
+ if key.startswith('test.test_lazy_import.data'):
+ del sys.modules[key]
+ sys.set_lazy_imports_filter(None)
+ sys.set_lazy_imports("normal")
+
+ def test_version_submodule_does_not_overwrite(self):
+ """A __version__ submodule should not overwrite the parent's
+ __version__ attribute imported in __init__.py."""
+ import test.test_lazy_import.data.versioned as versioned
+ self.assertEqual(versioned.__version__, "1.0")
+ self.assertEqual(
+ versioned.__copyright__,
+ "Copyright (c) 2001-2022 Python Software Foundation.",
+ )
+
+
+class ModuleVariableNameCollisionTests(unittest.TestCase):
+ """Tests for name collision between a submodule and a variable."""
+
+ def tearDown(self):
+ for key in list(sys.modules.keys()):
+ if key.startswith('test.test_lazy_import.data'):
+ del sys.modules[key]
+ sys.set_lazy_imports_filter(None)
+ sys.set_lazy_imports("normal")
+
+ def test_variable_after_import_wins(self):
+ """Variable assigned after import should overwrite the submodule."""
+ from test.test_lazy_import.data import module_same_name_var_order1
+ self.assertEqual(module_same_name_var_order1.bar, "Blah")
+
+ def test_import_after_variable_wins(self):
+ """Import after variable assignment should overwrite the variable."""
+ from test.test_lazy_import.data import module_same_name_var_order2
+ bar_mod = sys.modules[
+ "test.test_lazy_import.data.module_same_name_var_order2.bar"
+ ]
+ self.assertIs(module_same_name_var_order2.bar, bar_mod)
+
+
+class DeletedModuleReimportTests(unittest.TestCase):
+ """Tests for reimporting after module deletion from sys.modules."""
+
+ def tearDown(self):
+ for key in list(sys.modules.keys()):
+ if key.startswith('test.test_lazy_import.data'):
+ del sys.modules[key]
+ sys.set_lazy_imports_filter(None)
+ sys.set_lazy_imports("normal")
+
+ def test_reimport_creates_new_module(self):
+ """Deleting and reimporting should create a new module object."""
+ import test.test_lazy_import.data.metasyntactic.foo
+ import test.test_lazy_import.data.metasyntactic.foo.bar.baz
+
+ first_bar = test.test_lazy_import.data.metasyntactic.foo.bar
+
+ del sys.modules[
+ "test.test_lazy_import.data.metasyntactic.foo.bar"
+ ]
+
+ import test.test_lazy_import.data.metasyntactic.foo.bar.thud
+
+ second_bar = test.test_lazy_import.data.metasyntactic.foo.bar
+
+ self.assertIsNot(first_bar, second_bar)
+ self.assertIn("baz", dir(first_bar))
+ self.assertNotIn("thud", dir(first_bar))
+ self.assertIn("thud", dir(second_bar))
+ self.assertNotIn("baz", dir(second_bar))
+
+
[email protected]_subprocess()
+class CircularImportLazyTests(unittest.TestCase):
+ """Tests that lazy imports can break circular import patterns."""
+
+ def test_succeeds_with_lazy(self):
+ """Same-level circular imports should succeed with lazy mode."""
+ proc = assert_python_ok(
+ "-X", "lazy_imports=all", "-c",
+ "import test.test_lazy_import.data.circular_import_pkg.main;"
+ "print('OK')",
+ )
+ self.assertIn(b"OK", proc.out)
+
+ def test_fails_without_lazy(self):
+ """Same-level circular imports should fail without lazy mode."""
+ result = subprocess.run(
+ [sys.executable, "-c",
+ "import test.test_lazy_import.data.circular_import_pkg.main"],
+ capture_output=True, text=True,
+ )
+ self.assertNotEqual(result.returncode, 0)
+ self.assertIn("ImportError", result.stderr)
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/Lib/test/test_lazy_import/data/circular_import_pkg/__init__.py
b/Lib/test/test_lazy_import/data/circular_import_pkg/__init__.py
new file mode 100644
index 000000000000000..e69de29bb2d1d64
diff --git a/Lib/test/test_lazy_import/data/circular_import_pkg/main.py
b/Lib/test/test_lazy_import/data/circular_import_pkg/main.py
new file mode 100644
index 000000000000000..0b897b377e28a66
--- /dev/null
+++ b/Lib/test/test_lazy_import/data/circular_import_pkg/main.py
@@ -0,0 +1,2 @@
+from .x import X2
+X2()
diff --git a/Lib/test/test_lazy_import/data/circular_import_pkg/x.py
b/Lib/test/test_lazy_import/data/circular_import_pkg/x.py
new file mode 100644
index 000000000000000..b44d5185c9e70fc
--- /dev/null
+++ b/Lib/test/test_lazy_import/data/circular_import_pkg/x.py
@@ -0,0 +1,7 @@
+def X1():
+ return "X"
+
+from .y import Y1
+
+def X2():
+ return Y1()
diff --git a/Lib/test/test_lazy_import/data/circular_import_pkg/y.py
b/Lib/test/test_lazy_import/data/circular_import_pkg/y.py
new file mode 100644
index 000000000000000..d2385f7e67c01fd
--- /dev/null
+++ b/Lib/test/test_lazy_import/data/circular_import_pkg/y.py
@@ -0,0 +1,7 @@
+def Y1():
+ return "Y"
+
+from .x import X2
+
+def Y2():
+ return X2()
diff --git a/Lib/test/test_lazy_import/data/metasyntactic/__init__.py
b/Lib/test/test_lazy_import/data/metasyntactic/__init__.py
new file mode 100644
index 000000000000000..e69de29bb2d1d64
diff --git a/Lib/test/test_lazy_import/data/metasyntactic/foo/__init__.py
b/Lib/test/test_lazy_import/data/metasyntactic/foo/__init__.py
new file mode 100644
index 000000000000000..632a9fb87ac0fd7
--- /dev/null
+++ b/Lib/test/test_lazy_import/data/metasyntactic/foo/__init__.py
@@ -0,0 +1 @@
+Foo = "Foo"
diff --git a/Lib/test/test_lazy_import/data/metasyntactic/foo/ack/__init__.py
b/Lib/test/test_lazy_import/data/metasyntactic/foo/ack/__init__.py
new file mode 100644
index 000000000000000..c4c249f3b651536
--- /dev/null
+++ b/Lib/test/test_lazy_import/data/metasyntactic/foo/ack/__init__.py
@@ -0,0 +1 @@
+Ack = "Ack"
diff --git a/Lib/test/test_lazy_import/data/metasyntactic/foo/bar/__init__.py
b/Lib/test/test_lazy_import/data/metasyntactic/foo/bar/__init__.py
new file mode 100644
index 000000000000000..03faa550258f97f
--- /dev/null
+++ b/Lib/test/test_lazy_import/data/metasyntactic/foo/bar/__init__.py
@@ -0,0 +1 @@
+Bar = "Bar"
diff --git
a/Lib/test/test_lazy_import/data/metasyntactic/foo/bar/baz/__init__.py
b/Lib/test/test_lazy_import/data/metasyntactic/foo/bar/baz/__init__.py
new file mode 100644
index 000000000000000..62d8366b4404d6c
--- /dev/null
+++ b/Lib/test/test_lazy_import/data/metasyntactic/foo/bar/baz/__init__.py
@@ -0,0 +1 @@
+Baz = "Baz"
diff --git
a/Lib/test/test_lazy_import/data/metasyntactic/foo/bar/baz/qux/__init__.py
b/Lib/test/test_lazy_import/data/metasyntactic/foo/bar/baz/qux/__init__.py
new file mode 100644
index 000000000000000..12389d76a28539c
--- /dev/null
+++ b/Lib/test/test_lazy_import/data/metasyntactic/foo/bar/baz/qux/__init__.py
@@ -0,0 +1 @@
+Qux = "Qux"
diff --git
a/Lib/test/test_lazy_import/data/metasyntactic/foo/bar/thud/__init__.py
b/Lib/test/test_lazy_import/data/metasyntactic/foo/bar/thud/__init__.py
new file mode 100644
index 000000000000000..a4dd8ab0fae17ee
--- /dev/null
+++ b/Lib/test/test_lazy_import/data/metasyntactic/foo/bar/thud/__init__.py
@@ -0,0 +1 @@
+Thud = "Thud"
diff --git a/Lib/test/test_lazy_import/data/metasyntactic/names.py
b/Lib/test/test_lazy_import/data/metasyntactic/names.py
new file mode 100644
index 000000000000000..b2edf13e850389a
--- /dev/null
+++ b/Lib/test/test_lazy_import/data/metasyntactic/names.py
@@ -0,0 +1,9 @@
+from .foo import Foo
+from .foo.ack import Ack
+from .foo.bar import Bar
+from .foo.bar.baz import Baz
+from .foo.bar.thud import Thud
+from .waldo import Waldo
+from .waldo.fred import Fred
+from .plugh import Plugh
+Metasyntactic = "Metasyntactic"
diff --git a/Lib/test/test_lazy_import/data/metasyntactic/plugh/__init__.py
b/Lib/test/test_lazy_import/data/metasyntactic/plugh/__init__.py
new file mode 100644
index 000000000000000..5db053204fc17ce
--- /dev/null
+++ b/Lib/test/test_lazy_import/data/metasyntactic/plugh/__init__.py
@@ -0,0 +1 @@
+Plugh = "Plugh"
diff --git a/Lib/test/test_lazy_import/data/metasyntactic/waldo/__init__.py
b/Lib/test/test_lazy_import/data/metasyntactic/waldo/__init__.py
new file mode 100644
index 000000000000000..39f5a1b18385733
--- /dev/null
+++ b/Lib/test/test_lazy_import/data/metasyntactic/waldo/__init__.py
@@ -0,0 +1 @@
+Waldo = "Waldo"
diff --git
a/Lib/test/test_lazy_import/data/metasyntactic/waldo/fred/__init__.py
b/Lib/test/test_lazy_import/data/metasyntactic/waldo/fred/__init__.py
new file mode 100644
index 000000000000000..8c9dce1b3cfb9d1
--- /dev/null
+++ b/Lib/test/test_lazy_import/data/metasyntactic/waldo/fred/__init__.py
@@ -0,0 +1 @@
+Fred = "Fred"
diff --git
a/Lib/test/test_lazy_import/data/module_same_name_var_order1/__init__.py
b/Lib/test/test_lazy_import/data/module_same_name_var_order1/__init__.py
new file mode 100644
index 000000000000000..b815b2a7d6fedf1
--- /dev/null
+++ b/Lib/test/test_lazy_import/data/module_same_name_var_order1/__init__.py
@@ -0,0 +1,3 @@
+from .bar import Bar
+bar = "Blah"
+Bar
diff --git a/Lib/test/test_lazy_import/data/module_same_name_var_order1/bar.py
b/Lib/test/test_lazy_import/data/module_same_name_var_order1/bar.py
new file mode 100644
index 000000000000000..03faa550258f97f
--- /dev/null
+++ b/Lib/test/test_lazy_import/data/module_same_name_var_order1/bar.py
@@ -0,0 +1 @@
+Bar = "Bar"
diff --git
a/Lib/test/test_lazy_import/data/module_same_name_var_order2/__init__.py
b/Lib/test/test_lazy_import/data/module_same_name_var_order2/__init__.py
new file mode 100644
index 000000000000000..008d199c73e534d
--- /dev/null
+++ b/Lib/test/test_lazy_import/data/module_same_name_var_order2/__init__.py
@@ -0,0 +1,3 @@
+bar = "Blah"
+from .bar import Bar
+Bar
diff --git a/Lib/test/test_lazy_import/data/module_same_name_var_order2/bar.py
b/Lib/test/test_lazy_import/data/module_same_name_var_order2/bar.py
new file mode 100644
index 000000000000000..03faa550258f97f
--- /dev/null
+++ b/Lib/test/test_lazy_import/data/module_same_name_var_order2/bar.py
@@ -0,0 +1 @@
+Bar = "Bar"
diff --git a/Lib/test/test_lazy_import/data/versioned/__init__.py
b/Lib/test/test_lazy_import/data/versioned/__init__.py
new file mode 100644
index 000000000000000..be5bb3f8e607185
--- /dev/null
+++ b/Lib/test/test_lazy_import/data/versioned/__init__.py
@@ -0,0 +1,2 @@
+from .__version__ import __version__
+from .__version__ import __copyright__
diff --git a/Lib/test/test_lazy_import/data/versioned/__version__.py
b/Lib/test/test_lazy_import/data/versioned/__version__.py
new file mode 100644
index 000000000000000..37a104387354e28
--- /dev/null
+++ b/Lib/test/test_lazy_import/data/versioned/__version__.py
@@ -0,0 +1,2 @@
+__version__ = "1.0"
+__copyright__ = "Copyright (c) 2001-2022 Python Software Foundation."
diff --git a/Makefile.pre.in b/Makefile.pre.in
index cf700e9f2340901..b9914369ad1bedc 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -2675,6 +2675,20 @@ TESTSUBDIRS= idlelib/idle_test \
test/test_lazy_import/data \
test/test_lazy_import/data/pkg \
test/test_lazy_import/data/badsyntax \
+ test/test_lazy_import/data/circular_import_pkg \
+ test/test_lazy_import/data/metasyntactic \
+ test/test_lazy_import/data/metasyntactic/foo \
+ test/test_lazy_import/data/metasyntactic/foo/ack \
+ test/test_lazy_import/data/metasyntactic/foo/bar \
+ test/test_lazy_import/data/metasyntactic/foo/bar/baz \
+ test/test_lazy_import/data/metasyntactic/foo/bar/baz/qux \
+ test/test_lazy_import/data/metasyntactic/foo/bar/thud \
+ test/test_lazy_import/data/metasyntactic/plugh \
+ test/test_lazy_import/data/metasyntactic/waldo \
+ test/test_lazy_import/data/metasyntactic/waldo/fred \
+ test/test_lazy_import/data/module_same_name_var_order1 \
+ test/test_lazy_import/data/module_same_name_var_order2 \
+ test/test_lazy_import/data/versioned \
test/test_module \
test/test_multiprocessing_fork \
test/test_multiprocessing_forkserver \
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]