Skip to content

Raise consistent NameError in ForwardRef.evaluate()#135646

@Viicos

Description

@Viicos

Feature or enhancement

Proposal:

The new ForwardRef.evaluate() implementation had a fast path introduced in #124337 to not call eval():

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:

#defineNAME_ERROR_MSG "name '%.200s' is not defined"

and raised this way:

cpython/Python/ceval.c

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

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    type-featureA feature request or enhancement

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions