-
-
Notifications
You must be signed in to change notification settings - Fork 33.2k
Description
Feature or enhancement
Proposal:
The new ForwardRef.evaluate() implementation had a fast path introduced in #124337 to not call eval():
Lines 177 to 187 in cb39410
| if arg.isidentifier() and not keyword.iskeyword(arg): | |
| if arg in locals: | |
| return locals[arg] | |
| elif arg in globals: | |
| return globals[arg] | |
| elif hasattr(builtins, arg): | |
| return getattr(builtins, arg) | |
| elif is_forwardref_format: | |
| return self | |
| else: | |
| raise NameError(arg) |
However, when the NameError is raised, the format is different from the one raised by eval():
The exception message is defined as:
Line 308 in cb39410
| #define NAME_ERROR_MSG "name '%.200s' is not defined" |
and raised this way:
Lines 3339 to 3351 in cb39410
| _PyErr_Format(tstate, exc, format_str, obj_str); | |
| if (exc == PyExc_NameError) { | |
| // Include the name in the NameError exceptions to offer suggestions later. | |
| PyObject *exc = PyErr_GetRaisedException(); | |
| if (PyErr_GivenExceptionMatches(exc, PyExc_NameError)) { | |
| if (((PyNameErrorObject*)exc)->name == NULL) { | |
| // We do not care if this fails because we are going to restore the | |
| // NameError anyway. | |
| (void)PyObject_SetAttr(exc, &_Py_ID(name), obj); | |
| } | |
| } | |
| PyErr_SetRaisedException(exc); |
To have consistent exceptions raised, would it be possible to change the Python fast path implementation to match the C eval code?
diff --git a/Lib/annotationlib.py b/Lib/annotationlib.py
index 731817a9973..c83a1573ccd 100644
--- a/Lib/annotationlib.py
+++ b/Lib/annotationlib.py
@@ -27,6 +27,9 @@ class Format(enum.IntEnum):
_sentinel = object()
+# Following `NAME_ERROR_MSG` in `ceval_macros.h`:
+_NAME_ERROR_MSG = "name '{name:.200}' is not defined"
+
# Slots shared by ForwardRef and _Stringifier. The __forward__ names must be
# preserved for compatibility with the old typing.ForwardRef class. The remaining
@@ -184,7 +187,7 @@ def evaluate(
elif is_forwardref_format:
return self
else:
- raise NameError(arg)
+ raise NameError(_NAME_ERROR_MSG.format(name=arg), name=arg)
else:
code = self.__forward_code__
try:This requires _NAME_ERROR_MSG to be in sync with the one from ceval_macros.h.
Or at least, the NameError should have its name property set (especially as type stubs shows NameError.name as str currently).
cc @JelleZijlstra.
Has this already been discussed elsewhere?
This is a minor feature, which does not need previous discussion elsewhere
Links to previous discussion of this feature:
No response