summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShantanu <12621235+hauntsaninja@users.noreply.github.com>2024-12-10 04:55:20 (GMT)
committerGitHub <noreply@github.com>2024-12-10 04:55:20 (GMT)
commit3983527c3a6b389e373a233e514919555853ccb3 (patch)
tree7a9bbb49fc4b6e8b6996f25635db330978bde525
parent58c753827ac7aa3d7f1495ac206c28bf2f6c67e8 (diff)
downloadcpython-3983527c3a6b389e373a233e514919555853ccb3.zip
cpython-3983527c3a6b389e373a233e514919555853ccb3.tar.gz
cpython-3983527c3a6b389e373a233e514919555853ccb3.tar.bz2
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>
-rw-r--r--Lib/test/test_import/__init__.py48
-rw-r--r--Misc/NEWS.d/next/Core_and_Builtins/2024-12-06-01-09-40.gh-issue-127651.80cm6j.rst1
-rw-r--r--Python/ceval.c22
3 files changed, 66 insertions, 5 deletions
diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py
index c52b7f3..83efbc1 100644
--- a/Lib/test/test_import/__init__.py
+++ b/Lib/test/test_import/__init__.py
@@ -807,6 +807,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 = [
(
@@ -1068,7 +1112,7 @@ try:
except AttributeError as e:
print(str(e))
-fractions.__spec__.origin = 0
+fractions.__spec__.origin = []
try:
fractions.Fraction
except AttributeError as e:
@@ -1092,7 +1136,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:
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-12-06-01-09-40.gh-issue-127651.80cm6j.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-12-06-01-09-40.gh-issue-127651.80cm6j.rst
new file mode 100644
index 0000000..92b18b0
--- /dev/null
+++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-12-06-01-09-40.gh-issue-127651.80cm6j.rst
@@ -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
diff --git a/Python/ceval.c b/Python/ceval.c
index 6795a16..5eda033 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -2859,6 +2859,20 @@ _PyEval_ImportFrom(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(
@@ -2919,9 +2933,11 @@ _PyEval_ImportFrom(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);