diff --git a/Lib/ast.py b/Lib/ast.py index ba4ee0197b85d2..a7997c4b740635 100644 --- a/Lib/ast.py +++ b/Lib/ast.py @@ -21,7 +21,6 @@ :license: Python License. """ from _ast import * -lazy from _colorize import can_colorize, get_theme def parse(source, filename='', mode='exec', *, @@ -142,6 +141,8 @@ def dump( If show_empty is False, then empty lists and fields that are None will be omitted from the output for better readability. """ + from _colorize import get_theme + t = get_theme(force_color=color, force_no_color=not color).ast def _format(node, level=0): @@ -708,6 +709,7 @@ def main(args=None): tree = parse(source, name, args.mode, type_comments=args.no_type_comments, feature_version=feature_version, optimize=args.optimize) + from _colorize import can_colorize print(dump(tree, include_attributes=args.include_attributes, color=can_colorize(file=sys.stdout), indent=args.indent, show_empty=args.show_empty)) diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index e9810d6bd5d57b..11ba7d4fda6d0d 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -6,7 +6,6 @@ import abc from reprlib import recursive_repr lazy import copy -lazy import inspect lazy import re @@ -992,6 +991,7 @@ def __get__(self, _obj, cls): try: # In some cases fetching a signature is not possible. # But, we surely should not fail in this case. + import inspect text_sig = str(inspect.signature( cls, annotation_format=annotationlib.Format.FORWARDREF, @@ -1401,6 +1401,7 @@ def _add_slots(cls, is_frozen, weakref_slot, defined_fields): # If this is a wrapped function, unwrap it. if not isinstance(member, type) and hasattr(member, '__wrapped__'): + import inspect member = inspect.unwrap(member) if isinstance(member, types.FunctionType): diff --git a/Lib/test/test_lazy_import/__init__.py b/Lib/test/test_lazy_import/__init__.py index a9a8cd143e0d75..1d1d2e00bd733f 100644 --- a/Lib/test/test_lazy_import/__init__.py +++ b/Lib/test/test_lazy_import/__init__.py @@ -1034,6 +1034,50 @@ def test_cli_lazy_imports_none_forces_all_imports_eager(self): self.assertEqual(result.returncode, 0, f"stderr: {result.stderr}") self.assertIn("EAGER", result.stdout) + @support.requires_resource("cpu") + def test_cli_lazy_imports_modes_import_stdlib_modules(self): + """-X lazy_imports modes should import available stdlib modules.""" + # Do not smoke-test modules with intentional import-time effects. + import_side_effect_modules = {"antigravity", "this"} + importable = [] + + for module in sorted(sys.stdlib_module_names): + if module in import_side_effect_modules: + continue + + with self.subTest(module=module): + code = f"import {module}; print({module})" + baseline = subprocess.run( + [sys.executable, "-I", "-c", code], + capture_output=True, + text=True, + timeout=60, + ) + if baseline.returncode: + # sys.stdlib_module_names includes modules for other + # platforms and optional extension modules not built here. + continue + importable.append(module) + + for mode in ("normal", "none"): + with self.subTest(module=module, mode=mode): + result = subprocess.run( + [ + sys.executable, + "-I", + "-X", + f"lazy_imports={mode}", + "-c", + code, + ], + capture_output=True, + text=True, + timeout=60, + ) + self.assertEqual(result.returncode, 0, result.stderr) + + self.assertGreater(len(importable), 100) + def test_cli_lazy_imports_normal_respects_lazy_keyword_only(self): """-X lazy_imports=normal should respect lazy keyword only.""" # Note: Use test modules instead of stdlib modules to avoid diff --git a/Misc/NEWS.d/next/Library/2026-05-03-12-00-00.gh-issue-149321.fUaxrz.rst b/Misc/NEWS.d/next/Library/2026-05-03-12-00-00.gh-issue-149321.fUaxrz.rst new file mode 100644 index 00000000000000..8fd4bf60cf32a7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-03-12-00-00.gh-issue-149321.fUaxrz.rst @@ -0,0 +1,2 @@ +Fix import cycles exposed by running standard library modules with +``-X lazy_imports=none``.