https://github.com/python/cpython/commit/dffac6163e693cf80ed42cdc8e2cb5c0cb9577d7
commit: dffac6163e693cf80ed42cdc8e2cb5c0cb9577d7
branch: main
author: Dino Viehland <[email protected]>
committer: DinoV <[email protected]>
date: 2026-08-14T14:17:23-07:00
summary:
gh-155194: Fix not raising on non-module import (#155189)
* Fix not raising on non-module import
* Fix traceback tests
* Fix doc string and add new test
* Fix up feedback on tests
* Add test case for lazy import dotted.name as name
files:
A Lib/test/test_lazy_import/data/lazypkg/__init__.py
A Lib/test/test_lazy_import/data/lazypkg/bar.py
M Lib/test/test_lazy_import/__init__.py
M Lib/test/test_traceback.py
M Makefile.pre.in
M Python/import.c
diff --git a/Lib/test/test_lazy_import/__init__.py
b/Lib/test/test_lazy_import/__init__.py
index 899ecec1ba2afa4..b12e209707a9de3 100644
--- a/Lib/test/test_lazy_import/__init__.py
+++ b/Lib/test/test_lazy_import/__init__.py
@@ -678,17 +678,53 @@ def test_lazy_modules_tracks_lazy_imports(self):
class ErrorHandlingTests(LazyImportTestCase):
"""Tests for error handling during lazy import reification."""
- def test_missing_lazy_submodule_raises_attribute_error(self):
- """Accessing a nonexistent lazy submodule via parent attr raises
AttributeError."""
+ def test_missing_lazy_submodule_raises_module_not_found_error(self):
+ """Accessing a nonexistent lazy submodule via parent attr raises
ModuleNotFoundError."""
code = textwrap.dedent("""
lazy import test.test_lazy_import.data.nonexistent_module
try:
_ = test.test_lazy_import.data.nonexistent_module
- except AttributeError:
+ except ModuleNotFoundError:
pass
else:
- raise AssertionError("AttributeError was not raised")
+ raise AssertionError("ModuleNotFoundError was not raised")
+ """)
+ assert_python_ok("-c", code)
+
+ def test_non_package_lazily_imported(self):
+ """Accessing a nonexistent lazy name via parent attr raises
ModuleNotFoundError."""
+ code = textwrap.dedent("""
+ lazy import math.pi
+
+ try:
+ _ = math.pi
+ except ModuleNotFoundError:
+ pass
+ else:
+ raise AssertionError("ModuleNotFoundError was not raised")
+ """)
+ assert_python_ok("-c", code)
+
+ def test_non_package_lazily_imported_as(self):
+ """Doing a dotted lazy import as still works"""
+ code = textwrap.dedent("""
+ lazy import math.pi as pi
+ pi
+ """)
+ assert_python_ok("-c", code)
+
+ def test_missing_attribute_raises_import_error(self):
+ """Accessing a nonexistent lazy name via from import raises
ImportError."""
+ code = textwrap.dedent("""
+ lazy from sys import doesnotexist
+
+ try:
+ _ = doesnotexist
+ except ImportError:
+ pass
+ else:
+ raise AssertionError("ImportError was not raised")
""")
assert_python_ok("-c", code)
diff --git a/Lib/test/test_lazy_import/data/lazypkg/__init__.py
b/Lib/test/test_lazy_import/data/lazypkg/__init__.py
new file mode 100644
index 000000000000000..276b51823fee32a
--- /dev/null
+++ b/Lib/test/test_lazy_import/data/lazypkg/__init__.py
@@ -0,0 +1 @@
+lazy from . import bar
diff --git a/Lib/test/test_lazy_import/data/lazypkg/bar.py
b/Lib/test/test_lazy_import/data/lazypkg/bar.py
new file mode 100644
index 000000000000000..b8d8b60b886b88a
--- /dev/null
+++ b/Lib/test/test_lazy_import/data/lazypkg/bar.py
@@ -0,0 +1,2 @@
+print("BAR_MODULE_LOADED")
+def f(): pass
diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py
index e38d0942e463e9c..8e4c28562a6cbe5 100644
--- a/Lib/test/test_traceback.py
+++ b/Lib/test/test_traceback.py
@@ -5611,11 +5611,11 @@ class TestLazyImportSuggestions(unittest.TestCase):
def test_attribute_error_does_not_reify_lazy_imports(self):
"""Printing an AttributeError should not trigger lazy import
reification."""
- # pkg.bar prints "BAR_MODULE_LOADED" when imported.
+ # lazypkg.bar prints "BAR_MODULE_LOADED" when imported.
# If lazy import is reified during suggestion computation, we'll see
it.
code = textwrap.dedent("""
- lazy import test.test_lazy_import.data.pkg.bar
- test.test_lazy_import.data.pkg.nonexistent
+ lazy import test.test_lazy_import.data.lazypkg
+ test.test_lazy_import.data.lazypkg.nonexistent
""")
rc, stdout, stderr = assert_python_failure('-c', code)
self.assertNotIn(b"BAR_MODULE_LOADED", stdout)
@@ -5624,9 +5624,9 @@ def
test_traceback_formatting_does_not_reify_lazy_imports(self):
"""Formatting a traceback should not trigger lazy import
reification."""
code = textwrap.dedent("""
import traceback
- lazy import test.test_lazy_import.data.pkg.bar
+ lazy import test.test_lazy_import.data.lazypkg
try:
- test.test_lazy_import.data.pkg.nonexistent
+ test.test_lazy_import.data.lazypkg.nonexistent
except AttributeError:
traceback.format_exc()
print("OK")
@@ -5638,9 +5638,9 @@ def
test_traceback_formatting_does_not_reify_lazy_imports(self):
def test_suggestion_still_works_for_non_lazy_attributes(self):
"""Suggestions should still work for non-lazy module attributes."""
code = textwrap.dedent("""
- lazy import test.test_lazy_import.data.pkg.bar
+ lazy import test.test_lazy_import.data.lazypkg
# Typo for __name__
- test.test_lazy_import.data.pkg.__nme__
+ test.test_lazy_import.data.lazypkg.__nme__
""")
rc, stdout, stderr = assert_python_failure('-c', code)
self.assertIn(b"__name__", stderr)
diff --git a/Makefile.pre.in b/Makefile.pre.in
index 46fa26e01572cc2..d3d24a13898d992 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -2690,6 +2690,7 @@ TESTSUBDIRS= idlelib/idle_test \
test/test_lazy_import/data/pkg \
test/test_lazy_import/data/badsyntax \
test/test_lazy_import/data/circular_import_pkg \
+ test/test_lazy_import/data/lazypkg \
test/test_lazy_import/data/metasyntactic \
test/test_lazy_import/data/metasyntactic/foo \
test/test_lazy_import/data/metasyntactic/foo/ack \
diff --git a/Python/import.c b/Python/import.c
index 5ca78a971fa54c6..47d5296a2fec9b1 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -3940,19 +3940,6 @@ _PyImport_LoadLazyImportTstate(PyThreadState *tstate,
PyObject *lazy_import)
goto error;
}
- Py_ssize_t dot = -1;
- int full = 0;
- if (lz->lz_attr != NULL) {
- full = 1;
- }
- if (!full) {
- dot = PyUnicode_FindChar(lz->lz_from, '.', 0,
- PyUnicode_GET_LENGTH(lz->lz_from), 1);
- }
- if (dot < 0) {
- full = 1;
- }
-
if (lz->lz_attr != NULL) {
if (PyUnicode_Check(lz->lz_attr)) {
fromlist = PyTuple_New(1);
@@ -3978,23 +3965,10 @@ _PyImport_LoadLazyImportTstate(PyThreadState *tstate,
PyObject *lazy_import)
PyErr_SetString(PyExc_ImportError, "__import__ not found");
goto error;
}
- if (full) {
- obj = _PyEval_ImportNameWithImport(
- tstate, import_func, globals, globals,
- lz->lz_from, fromlist, _PyLong_GetZero()
- );
- }
- else {
- PyObject *name = PyUnicode_Substring(lz->lz_from, 0, dot);
- if (name == NULL) {
- goto error;
- }
- obj = _PyEval_ImportNameWithImport(
- tstate, import_func, globals, globals,
- name, fromlist, _PyLong_GetZero()
- );
- Py_DECREF(name);
- }
+ obj = _PyEval_ImportNameWithImport(
+ tstate, import_func, globals, globals,
+ lz->lz_from, fromlist, _PyLong_GetZero()
+ );
if (obj == NULL) {
goto error;
}
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]