[3.13] gh-127651: Use __file__ in diagnostics if origin is missing (#127660) (#127775)

gh-127651: Use __file__ in diagnostics if origin is missing (#127660)

See the left hand side in https://github.com/python/cpython/pull/123929/files#diff-c22186367cbe20233e843261998dc027ae5f1f8c0d2e778abfa454ae74cc59deL2840-L2849

---------

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
(cherry picked from commit 3983527c3a)
This commit is contained in:
Shantanu 2024-12-09 21:21:55 -08:00 committed by GitHub
parent 310efdabf5
commit 6441d42f92
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 66 additions and 5 deletions

View file

@ -826,6 +826,50 @@ class ImportTests(unittest.TestCase):
self.assertIn("Frozen object named 'x' is invalid",
str(cm.exception))
def test_frozen_module_from_import_error(self):
with self.assertRaises(ImportError) as cm:
from os import this_will_never_exist
self.assertIn(
f"cannot import name 'this_will_never_exist' from 'os' ({os.__file__})",
str(cm.exception),
)
with self.assertRaises(ImportError) as cm:
from sys import this_will_never_exist
self.assertIn(
"cannot import name 'this_will_never_exist' from 'sys' (unknown location)",
str(cm.exception),
)
scripts = [
"""
import os
os.__spec__.has_location = False
os.__file__ = []
from os import this_will_never_exist
""",
"""
import os
os.__spec__.has_location = False
del os.__file__
from os import this_will_never_exist
""",
"""
import os
os.__spec__.origin = []
os.__file__ = []
from os import this_will_never_exist
"""
]
for script in scripts:
with self.subTest(script=script):
expected_error = (
b"cannot import name 'this_will_never_exist' "
b"from 'os' (unknown location)"
)
popen = script_helper.spawn_python("-c", script)
stdout, stderr = popen.communicate()
self.assertIn(expected_error, stdout)
def test_script_shadowing_stdlib(self):
script_errors = [
(
@ -1087,7 +1131,7 @@ try:
except AttributeError as e:
print(str(e))
fractions.__spec__.origin = 0
fractions.__spec__.origin = []
try:
fractions.Fraction
except AttributeError as e:
@ -1111,7 +1155,7 @@ try:
except ImportError as e:
print(str(e))
fractions.__spec__.origin = 0
fractions.__spec__.origin = []
try:
from fractions import Fraction
except ImportError as e:

View file

@ -0,0 +1 @@
When raising :exc:`ImportError` for missing symbols in ``from`` imports, use ``__file__`` in the error message if ``__spec__.origin`` is not a location

View file

@ -2785,6 +2785,20 @@ import_from(PyThreadState *tstate, PyObject *v, PyObject *name)
}
}
if (origin == NULL) {
// Fall back to __file__ for diagnostics if we don't have
// an origin that is a location
origin = PyModule_GetFilenameObject(v);
if (origin == NULL) {
if (!PyErr_ExceptionMatches(PyExc_SystemError)) {
goto done;
}
// PyModule_GetFilenameObject raised "module filename missing"
_PyErr_Clear(tstate);
}
assert(origin == NULL || PyUnicode_Check(origin));
}
if (is_possibly_shadowing_stdlib) {
assert(origin);
errmsg = PyUnicode_FromFormat(
@ -2845,9 +2859,11 @@ import_from(PyThreadState *tstate, PyObject *v, PyObject *name)
}
done_with_errmsg:
/* NULL checks for errmsg, mod_name, origin done by PyErr_SetImportError. */
_PyErr_SetImportErrorWithNameFrom(errmsg, mod_name, origin, name);
Py_DECREF(errmsg);
if (errmsg != NULL) {
/* NULL checks for mod_name and origin done by _PyErr_SetImportErrorWithNameFrom */
_PyErr_SetImportErrorWithNameFrom(errmsg, mod_name, origin, name);
Py_DECREF(errmsg);
}
done:
Py_XDECREF(origin);