From 0273665e9001fd4cf929a048c3abfe63029b4a50 Mon Sep 17 00:00:00 2001 From: Xwz Date: Sun, 26 Apr 2026 21:10:07 +0800 Subject: [PATCH 1/2] gh-149013: extend test_lazy_import coverage for reload() and sys.modules deletion --- Lib/test/test_lazy_import/__init__.py | 60 +++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/Lib/test/test_lazy_import/__init__.py b/Lib/test/test_lazy_import/__init__.py index a9a8cd143e0d75..a0a12ea67de286 100644 --- a/Lib/test/test_lazy_import/__init__.py +++ b/Lib/test/test_lazy_import/__init__.py @@ -1554,6 +1554,66 @@ def test_lazy_import_before_eager_resolves_to_same_module(self): self.assertEqual(result.returncode, 0, f"stdout: {result.stdout}, stderr: {result.stderr}") self.assertIn("OK", result.stdout) + def test_reload_after_lazy_reification_keeps_single_module_object(self): + """Reloading a reified lazy module should keep identity with globals/sys.modules.""" + code = textwrap.dedent(""" + import importlib + import sys + + lazy import json as lazy_json + + # Trigger reification. + assert lazy_json.dumps({"x": 1}) == '{"x": 1}' + before_reload = lazy_json + assert before_reload is sys.modules["json"] + + reloaded = importlib.reload(lazy_json) + assert reloaded is before_reload + assert lazy_json is sys.modules["json"] + print("OK") + """) + result = subprocess.run( + [sys.executable, "-c", code], + capture_output=True, + text=True + ) + self.assertEqual(result.returncode, 0, f"stdout: {result.stdout}, stderr: {result.stderr}") + self.assertIn("OK", result.stdout) + + def test_reimport_after_deleting_sys_modules_entry_creates_new_module(self): + """Deleting sys.modules entry should force a fresh module on next import.""" + code = textwrap.dedent(""" + import sys + + lazy import json as lazy_json + assert "json" not in sys.modules + + # Reify lazy binding. + assert lazy_json.dumps({"x": 1}) == '{"x": 1}' + first_obj = lazy_json + first_id = id(first_obj) + assert first_obj is sys.modules["json"] + + # Remove import cache entry; existing binding should still work. + del sys.modules["json"] + assert "json" not in sys.modules + assert lazy_json.dumps({"x": 2}) == '{"x": 2}' + + import json as second_obj + second_id = id(second_obj) + assert "json" in sys.modules + assert second_obj is sys.modules["json"] + assert first_id != second_id + print("OK") + """) + result = subprocess.run( + [sys.executable, "-c", code], + capture_output=True, + text=True + ) + self.assertEqual(result.returncode, 0, f"stdout: {result.stdout}, stderr: {result.stderr}") + self.assertIn("OK", result.stdout) + class RelativeImportTests(unittest.TestCase): """Tests for relative imports with lazy keyword.""" From 0043778cd264742de9371372b086a136e2656bb7 Mon Sep 17 00:00:00 2001 From: XiaoWan-zi Date: Tue, 19 May 2026 12:21:44 +0800 Subject: [PATCH 2/2] gh-149013: address review feedback for lazy import reload tests Use lazy from json import ... instead of lazy import json so reload tests cover fresh bindings after reification, per review feedback. --- Lib/test/test_lazy_import/__init__.py | 35 ++++++++++++++++----------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_lazy_import/__init__.py b/Lib/test/test_lazy_import/__init__.py index 8d46b5a8644dac..8d62ee5aa21019 100644 --- a/Lib/test/test_lazy_import/__init__.py +++ b/Lib/test/test_lazy_import/__init__.py @@ -1688,21 +1688,28 @@ def test_lazy_import_before_eager_resolves_to_same_module(self): self.assertIn("OK", result.stdout) def test_reload_after_lazy_reification_keeps_single_module_object(self): - """Reloading a reified lazy module should keep identity with globals/sys.modules.""" + """Reload after lazy from-import: sys.modules identity and fresh lazy bindings.""" code = textwrap.dedent(""" import importlib import sys - lazy import json as lazy_json + lazy from json import dumps + lazy from json import loads as loads_before + + assert "json" not in sys.modules - # Trigger reification. - assert lazy_json.dumps({"x": 1}) == '{"x": 1}' - before_reload = lazy_json - assert before_reload is sys.modules["json"] + # Reify via from-import bindings (not top-level lazy import json). + assert dumps({"x": 1}) == '{"x": 1}' + assert loads_before("[1]") == [1] - reloaded = importlib.reload(lazy_json) + before_reload = sys.modules["json"] + reloaded = importlib.reload(before_reload) assert reloaded is before_reload - assert lazy_json is sys.modules["json"] + assert sys.modules["json"] is before_reload + + # A new lazy from-import after reload should bind to reloaded attributes. + lazy from json import loads as loads_after + assert loads_after is not loads_before print("OK") """) result = subprocess.run( @@ -1718,19 +1725,19 @@ def test_reimport_after_deleting_sys_modules_entry_creates_new_module(self): code = textwrap.dedent(""" import sys - lazy import json as lazy_json + lazy from json import dumps + assert "json" not in sys.modules - # Reify lazy binding. - assert lazy_json.dumps({"x": 1}) == '{"x": 1}' - first_obj = lazy_json + # Reify lazy from-import binding. + assert dumps({"x": 1}) == '{"x": 1}' + first_obj = sys.modules["json"] first_id = id(first_obj) - assert first_obj is sys.modules["json"] # Remove import cache entry; existing binding should still work. del sys.modules["json"] assert "json" not in sys.modules - assert lazy_json.dumps({"x": 2}) == '{"x": 2}' + assert dumps({"x": 2}) == '{"x": 2}' import json as second_obj second_id = id(second_obj)