Skip to content

Commit 6dbf4ba

Browse files
authored
gh-149981: Test lazy import corner cases with module-level __getattr__ (#149982)
1 parent 388e023 commit 6dbf4ba

3 files changed

Lines changed: 122 additions & 0 deletions

File tree

Lib/test/test_lazy_import/__init__.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,59 @@ def test_from_import_with_module_getattr(self):
9898
""")
9999
assert_python_ok("-c", code)
100100

101+
@support.requires_subprocess()
102+
def test_from_import_with_module_getattr_raising(self):
103+
"""Lazy from import should respect module-level __getattr__."""
104+
code = textwrap.dedent("""
105+
lazy from test.test_lazy_import.data.module_with_getattr import raising_attr
106+
107+
try:
108+
raising_attr
109+
except ValueError as exc:
110+
assert str(exc) == 'from_getattr', exc
111+
else:
112+
assert False, f'ValueError is not raised: {raising_attr}'
113+
""")
114+
assert_python_ok("-c", code)
115+
116+
@support.requires_subprocess()
117+
def test_from_import_with_module_getattr_missing(self):
118+
"""Lazy from import should respect module-level __getattr__."""
119+
for attr in ("missing_attr", "import_error_attr"):
120+
with self.subTest(attr=attr):
121+
code = textwrap.dedent(f"""
122+
lazy from test.test_lazy_import.data.module_with_getattr import {attr}
123+
124+
try:
125+
{attr}
126+
except ImportError as exc:
127+
assert '{attr}' in str(exc), exc
128+
assert exc.__cause__ is not None
129+
else:
130+
assert False, ('ImportError is not raised', {attr})
131+
""")
132+
assert_python_ok("-c", code)
133+
134+
@support.requires_subprocess()
135+
def test_from_import_with_module_getattr_warning(self):
136+
"""Lazy from import should respect module-level __getattr__."""
137+
code = textwrap.dedent("""
138+
import warnings
139+
140+
with warnings.catch_warnings(record=True) as log:
141+
lazy from test.test_lazy_import.data.module_with_getattr import warning_attr
142+
143+
assert log == []
144+
145+
with warnings.catch_warnings(record=True) as log:
146+
warning_attr
147+
assert warning_attr == 'from_warning_attr', warning_attr
148+
assert len(log) == 1, log
149+
assert isinstance(log[0].message, UserWarning), log
150+
assert str(log[0].message) == 'from_getattr', log
151+
""")
152+
assert_python_ok("-c", code)
153+
101154
@support.requires_subprocess()
102155
def test_from_import_with_imported_module_getattr(self):
103156
"""Lazy from import should not shadow an imported module's __getattr__."""
@@ -463,6 +516,59 @@ def test_lazy_import_pkg_cross_import(self):
463516
self.assertEqual(type(g["x"]), int)
464517
self.assertEqual(type(g["b"]), types.LazyImportType)
465518

519+
@support.requires_subprocess()
520+
def test_package_from_import_with_module_getattr_raising(self):
521+
"""Lazy from import should respect a package's __getattr__."""
522+
code = textwrap.dedent("""
523+
lazy from test.test_lazy_import.data.pkg import raising_attr
524+
525+
try:
526+
raising_attr
527+
except ValueError as exc:
528+
assert str(exc) == 'from_getattr', exc
529+
else:
530+
assert False, f'ValueError is not raised: {raising_attr}'
531+
""")
532+
assert_python_ok("-c", code)
533+
534+
@support.requires_subprocess()
535+
def test_package_from_import_with_module_getattr_missing(self):
536+
"""Lazy from import should respect package's __getattr__."""
537+
for attr in ("missing_attr", "import_error_attr"):
538+
with self.subTest(attr=attr):
539+
code = textwrap.dedent(f"""
540+
lazy from test.test_lazy_import.data.pkg import {attr}
541+
542+
try:
543+
{attr}
544+
except ImportError as exc:
545+
assert '{attr}' in str(exc), exc
546+
assert exc.__cause__ is not None
547+
else:
548+
assert False, ('ImportError is not raised', {attr})
549+
""")
550+
assert_python_ok("-c", code)
551+
552+
@support.requires_subprocess()
553+
def test_from_import_with_module_getattr_warning(self):
554+
"""Lazy from import should respect package's __getattr__."""
555+
code = textwrap.dedent("""
556+
import warnings
557+
558+
with warnings.catch_warnings(record=True) as log:
559+
lazy from test.test_lazy_import.data.pkg import warning_attr
560+
561+
assert log == []
562+
563+
with warnings.catch_warnings(record=True) as log:
564+
warning_attr
565+
assert warning_attr == 'from_warning_attr', warning_attr
566+
assert len(log) == 1, log
567+
assert isinstance(log[0].message, UserWarning), log
568+
assert str(log[0].message) == 'from_getattr', log
569+
""")
570+
assert_python_ok("-c", code)
571+
466572
@support.requires_subprocess()
467573
def test_package_from_import_with_module_getattr(self):
468574
"""Lazy from import should respect a package's __getattr__."""
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
def __getattr__(name):
22
if name == "dynamic_attr":
33
return "from_getattr"
4+
elif name == "raising_attr":
5+
raise ValueError("from_getattr")
6+
elif name == "import_error_attr":
7+
raise ImportError(name)
8+
elif name == "warning_attr":
9+
import warnings
10+
warnings.warn("from_getattr", category=UserWarning)
11+
return "from_warning_attr"
412
raise AttributeError(name)

Lib/test/test_lazy_import/data/pkg/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,12 @@
33
def __getattr__(name):
44
if name == "dynamic_attr":
55
return "from_getattr"
6+
elif name == "raising_attr":
7+
raise ValueError("from_getattr")
8+
elif name == "import_error_attr":
9+
raise ImportError(name)
10+
elif name == "warning_attr":
11+
import warnings
12+
warnings.warn("from_getattr", category=UserWarning)
13+
return "from_warning_attr"
614
raise AttributeError(name)

0 commit comments

Comments
 (0)