Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 34k
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
| ifarg.isidentifier() andnotkeyword.iskeyword(arg): | |
| ifarginlocals: | |
| returnlocals[arg] | |
| elifarginglobals: | |
| returnglobals[arg] | |
| elifhasattr(builtins, arg): | |
| returngetattr(builtins, arg) | |
| elifis_forwardref_format: | |
| returnself | |
| else: | |
| raiseNameError(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
| #defineNAME_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