gh-154196: Improve `AttributeError` messages from unresolved lazy imports (#154688)
pablogsal <[email protected]>
| Newsgroups | gmane.comp.python.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://github.com/python/cpython/commit/125ca2699228379c9be80ad8a9d5c3631fcac44f commit: 125ca2699228379c9be80ad8a9d5c3631fcac44f branch: main author: Bartosz Sławecki <[email protected]> committer: pablogsal <[email protected]> date: 2026-08-16T14:25:03+01:00 summary: gh-154196: Improve `AttributeError` messages from unresolved lazy imports (#154688) files: A Misc/NEWS.d/next/Core_and_Builtins/2026-07-25-12-43-42.gh-issue-154196.0rAdob.rst M Lib/test/test_lazy_import/__init__.py M Objects/lazyimportobject.c diff --git a/Lib/test/test_lazy_import/__init__.py b/Lib/test/test_lazy_import/__init__.py index b12e209707a9de3..9147e788d7a81f2 100644 --- a/Lib/test/test_lazy_import/__init__.py +++ b/Lib/test/test_lazy_import/__init__.py @@ -277,6 +277,23 @@ def test_lazy_import_type_attributes_accessible(self): proc = assert_python_ok("-c", code) self.assertIn(b"<built-in method resolve of lazy_import object at", proc.out) + @support.requires_subprocess() + def test_lazy_import_type_attribute_error_message(self): + """Check that LazyImportType attribute error message is helpful.""" + code = textwrap.dedent(""" + lazy import asyncio + try: + globals()["asyncio"].Task + except AttributeError as exc: + assert str(exc) == ( + "cannot access attribute 'Task' " + "on unresolved lazy import 'asyncio'" + ), repr(str(exc)) + else: + assert False, 'AttributeError is not raised' + """) + assert_python_ok("-c", code) + class SyntaxRestrictionTests(LazyImportTestCase): """Tests for syntax restrictions on lazy imports.""" diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-07-25-12-43-42.gh-issue-154196.0rAdob.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-25-12-43-42.gh-issue-154196.0rAdob.rst new file mode 100644 index 000000000000000..8f55e76a5c0dcd4 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-25-12-43-42.gh-issue-154196.0rAdob.rst @@ -0,0 +1,2 @@ +Improve :exc:`AttributeError` messages from unresolved lazy imports. Patch +by Bartosz Sławecki. diff --git a/Objects/lazyimportobject.c b/Objects/lazyimportobject.c index fa1eb25047d9617..8f7f3f98c291289 100644 --- a/Objects/lazyimportobject.c +++ b/Objects/lazyimportobject.c @@ -81,6 +81,29 @@ lazy_import_dealloc(PyObject *op) Py_TYPE(op)->tp_free(op); } +/* Specialize the error message for failed attribute lookups. */ +static PyObject * +lazy_import_getattro(PyObject *op, PyObject *name) +{ + PyObject *value = _PyObject_GenericGetAttrWithDict(op, name, NULL, /* suppress */1); + if (value == NULL) { + if (PyErr_Occurred()) { + // pass up non-AttributeError exception + return NULL; + } + PyObject *lz_name = _PyLazyImport_GetName(op); + if (lz_name == NULL) { + return NULL; + } + PyErr_Format(PyExc_AttributeError, + "cannot access attribute %R on unresolved lazy import %R", + name, lz_name); + Py_DECREF(lz_name); + return NULL; + } + return value; +} + static PyObject * lazy_import_name(PyLazyImportObject *m) { @@ -149,6 +172,7 @@ PyTypeObject PyLazyImport_Type = { .tp_repr = lazy_import_repr, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, .tp_doc = lazy_import_doc, + .tp_getattro = lazy_import_getattro, .tp_traverse = lazy_import_traverse, .tp_clear = lazy_import_clear, .tp_methods = lazy_import_methods, _______________________________________________ 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]