Skip to content

gh-144957: Add test for lazy imports with __getattr__#145330

Open
gourijain029-del wants to merge 2 commits intopython:mainfrom
gourijain029-del:gh-144957-lazy-import-test
Open

gh-144957: Add test for lazy imports with __getattr__#145330
gourijain029-del wants to merge 2 commits intopython:mainfrom
gourijain029-del:gh-144957-lazy-import-test

Conversation

@gourijain029-del
Copy link

@gourijain029-del gourijain029-del commented Feb 27, 2026

Adds a regression test for lazy imports working with modules that use __getattr__.

The issue reported that lazy from typing import Match would fail since Match is provided by typing.__getattr__ rather than being in the module dict. Testing shows this works correctly in current main - the existing code in register_lazy_on_parent() already checks for __getattr__ and skips adding lazy import objects to those modules.

This test documents the expected behavior and prevents future regressions.

@bedevere-app bedevere-app bot added awaiting review tests Tests in the Lib/test dir labels Feb 27, 2026
@bedevere-app
Copy link

bedevere-app bot commented Feb 27, 2026

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

Adds regression test to verify lazy imports work correctly with
modules that use __getattr__ for dynamic attributes (e.g. typing.Match).

The issue appears to be already fixed in current main branch.
@johnslavik
Copy link
Member

johnslavik commented Feb 27, 2026

Testing shows this works correctly in current main - the existing code in register_lazy_on_parent() already checks for __getattr__ and skips adding lazy import objects to those modules.

Your test doesn't pass locally for me:

❯ ./python.exe -m unittest Lib.test.test_import.test_lazy_imports
....................................................F............BAR_MODULE_LOADED
...........................
======================================================================
FAIL: test_lazy_import_with_getattr (Lib.test.test_import.test_lazy_imports.LazyImportTests.test_lazy_import_with_getattr)
Lazy imports work with module __getattr__ (gh-144957).
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/bartosz.slawecki/Python/cpython/Lib/test/test_import/test_lazy_imports.py", line 101, in test_lazy_import_with_getattr
    self.assertEqual(result.returncode, 0, result.stderr)
    ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: 1 != 0 : Traceback (most recent call last):
  File "<string>", line 4, in <module>
ImportError: deferred import of 'typing.Match' raised an exception during resolution

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<string>", line 5, in <module>
    print(Match)
          ^^^^^
ImportError: cannot import name 'Match' from 'typing' (/Users/bartosz.slawecki/Python/cpython/Lib/typing.py)

Presumably there's something with CI, needs investigation.
EDIT: See #145334.

@gourijain029-del gourijain029-del force-pushed the gh-144957-lazy-import-test branch from 122ad9f to 3e63300 Compare February 27, 2026 20:59
When resolving lazy imports, check if a lazy import object was found
and the module has __getattr__. If so, try calling __getattr__ first
before using the lazy import object.
Comment on lines +90 to +103
code = textwrap.dedent("""
import sys
sys.set_lazy_imports("normal")
lazy from test.test_import.data.lazy_imports.module_with_getattr import dynamic_attr
assert dynamic_attr == "from_getattr"
print("OK")
""")
result = subprocess.run(
[sys.executable, "-c", code],
capture_output=True,
text=True
)
self.assertEqual(result.returncode, 0, result.stderr)
self.assertIn("OK", result.stdout)
Copy link
Member

@johnslavik johnslavik Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Less prone to false positives:

Suggested change
code = textwrap.dedent("""
import sys
sys.set_lazy_imports("normal")
lazy from test.test_import.data.lazy_imports.module_with_getattr import dynamic_attr
assert dynamic_attr == "from_getattr"
print("OK")
""")
result = subprocess.run(
[sys.executable, "-c", code],
capture_output=True,
text=True
)
self.assertEqual(result.returncode, 0, result.stderr)
self.assertIn("OK", result.stdout)
code = textwrap.dedent("""
import sys
sys.set_lazy_imports("normal")
lazy from test.test_import.data.lazy_imports.module_with_getattr import dynamic_attr
print(repr(dynamic_attr))
""")
result = subprocess.run(
[sys.executable, "-c", code],
capture_output=True,
text=True
)
self.assertEqual(result.returncode, 0, result.stderr)
self.assertIn("'from_getattr'", result.stdout)

@python python deleted a comment from bedevere-app bot Feb 27, 2026
@python python deleted a comment from bedevere-app bot Feb 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting review skip news tests Tests in the Lib/test dir

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants