@@ -1961,5 +1961,135 @@ def test_dunder_lazy_import_without_frame(self):
19611961 )
19621962
19631963
1964+ class SubmoduleLazinessTests (unittest .TestCase ):
1965+ """Tests that module-level lazy imports remain lazy until accessed."""
1966+
1967+ def tearDown (self ):
1968+ for key in list (sys .modules .keys ()):
1969+ if key .startswith ('test.test_lazy_import.data' ):
1970+ del sys .modules [key ]
1971+ sys .set_lazy_imports_filter (None )
1972+ sys .set_lazy_imports ("normal" )
1973+
1974+ def test_unaccessed_imports_stay_lazy (self ):
1975+ """Imports in 'all' mode should stay lazy until accessed."""
1976+ sys .set_lazy_imports ("all" )
1977+ from test .test_lazy_import .data .metasyntactic import names
1978+ self .assertIsInstance (names .__dict__ ["Foo" ], types .LazyImportType )
1979+ self .assertNotIn (
1980+ "test.test_lazy_import.data.metasyntactic.foo" , sys .modules
1981+ )
1982+ _ = names .Foo
1983+ self .assertEqual (names .Foo , "Foo" )
1984+ self .assertIn (
1985+ "test.test_lazy_import.data.metasyntactic.foo" , sys .modules
1986+ )
1987+ self .assertIsInstance (names .__dict__ ["Ack" ], types .LazyImportType )
1988+ self .assertNotIn (
1989+ "test.test_lazy_import.data.metasyntactic.foo.ack" , sys .modules
1990+ )
1991+
1992+
1993+ class AttributeSideEffectTests (unittest .TestCase ):
1994+ """Tests that submodule imports don't overwrite parent attributes."""
1995+
1996+ def tearDown (self ):
1997+ for key in list (sys .modules .keys ()):
1998+ if key .startswith ('test.test_lazy_import.data' ):
1999+ del sys .modules [key ]
2000+ sys .set_lazy_imports_filter (None )
2001+ sys .set_lazy_imports ("normal" )
2002+
2003+ def test_version_submodule_does_not_overwrite (self ):
2004+ """A __version__ submodule should not overwrite the parent's
2005+ __version__ attribute imported in __init__.py."""
2006+ import test .test_lazy_import .data .versioned as versioned
2007+ self .assertEqual (versioned .__version__ , "1.0" )
2008+ self .assertEqual (
2009+ versioned .__copyright__ ,
2010+ "Copyright (c) 2001-2022 Python Software Foundation." ,
2011+ )
2012+
2013+
2014+ class ModuleVariableNameCollisionTests (unittest .TestCase ):
2015+ """Tests for name collision between a submodule and a variable."""
2016+
2017+ def tearDown (self ):
2018+ for key in list (sys .modules .keys ()):
2019+ if key .startswith ('test.test_lazy_import.data' ):
2020+ del sys .modules [key ]
2021+ sys .set_lazy_imports_filter (None )
2022+ sys .set_lazy_imports ("normal" )
2023+
2024+ def test_variable_after_import_wins (self ):
2025+ """Variable assigned after import should overwrite the submodule."""
2026+ from test .test_lazy_import .data import module_same_name_var_order1
2027+ self .assertEqual (module_same_name_var_order1 .bar , "Blah" )
2028+
2029+ def test_import_after_variable_wins (self ):
2030+ """Import after variable assignment should overwrite the variable."""
2031+ from test .test_lazy_import .data import module_same_name_var_order2
2032+ bar_mod = sys .modules [
2033+ "test.test_lazy_import.data.module_same_name_var_order2.bar"
2034+ ]
2035+ self .assertIs (module_same_name_var_order2 .bar , bar_mod )
2036+
2037+
2038+ class DeletedModuleReimportTests (unittest .TestCase ):
2039+ """Tests for reimporting after module deletion from sys.modules."""
2040+
2041+ def tearDown (self ):
2042+ for key in list (sys .modules .keys ()):
2043+ if key .startswith ('test.test_lazy_import.data' ):
2044+ del sys .modules [key ]
2045+ sys .set_lazy_imports_filter (None )
2046+ sys .set_lazy_imports ("normal" )
2047+
2048+ def test_reimport_creates_new_module (self ):
2049+ """Deleting and reimporting should create a new module object."""
2050+ import test .test_lazy_import .data .metasyntactic .foo
2051+ import test .test_lazy_import .data .metasyntactic .foo .bar .baz
2052+
2053+ first_bar = test .test_lazy_import .data .metasyntactic .foo .bar
2054+
2055+ del sys .modules [
2056+ "test.test_lazy_import.data.metasyntactic.foo.bar"
2057+ ]
2058+
2059+ import test .test_lazy_import .data .metasyntactic .foo .bar .thud
2060+
2061+ second_bar = test .test_lazy_import .data .metasyntactic .foo .bar
2062+
2063+ self .assertIsNot (first_bar , second_bar )
2064+ self .assertIn ("baz" , dir (first_bar ))
2065+ self .assertNotIn ("thud" , dir (first_bar ))
2066+ self .assertIn ("thud" , dir (second_bar ))
2067+ self .assertNotIn ("baz" , dir (second_bar ))
2068+
2069+
2070+ @support .requires_subprocess ()
2071+ class CircularImportLazyTests (unittest .TestCase ):
2072+ """Tests that lazy imports can break circular import patterns."""
2073+
2074+ def test_succeeds_with_lazy (self ):
2075+ """Same-level circular imports should succeed with lazy mode."""
2076+ proc = assert_python_ok (
2077+ "-X" , "lazy_imports=all" , "-c" ,
2078+ "import test.test_lazy_import.data.circular_import_pkg.main;"
2079+ "print('OK')" ,
2080+ )
2081+ self .assertIn (b"OK" , proc .out )
2082+
2083+ def test_fails_without_lazy (self ):
2084+ """Same-level circular imports should fail without lazy mode."""
2085+ result = subprocess .run (
2086+ [sys .executable , "-c" ,
2087+ "import test.test_lazy_import.data.circular_import_pkg.main" ],
2088+ capture_output = True , text = True ,
2089+ )
2090+ self .assertNotEqual (result .returncode , 0 )
2091+ self .assertIn ("ImportError" , result .stderr )
2092+
2093+
19642094if __name__ == '__main__' :
19652095 unittest .main ()
0 commit comments