Skip to content

gh-144361: Fix NameError when type parameter default refers to a forward name#152208

Open
tangyuan0821 wants to merge 3 commits into
python:mainfrom
tangyuan0821:144361
Open

gh-144361: Fix NameError when type parameter default refers to a forward name#152208
tangyuan0821 wants to merge 3 commits into
python:mainfrom
tangyuan0821:144361

Conversation

@tangyuan0821

@tangyuan0821 tangyuan0821 commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Fix #144361: PEP 696 + PEP 749 — delayed evaluation of type parameter defaults.

Three call sites in Lib/typing.py eagerly evaluate default (Format.VALUE),
which fails when the default references a name defined later in the module.
Catch NameError and fall back to annotationlib.call_evaluate_function
with Format.FORWARDREF.

@tangyuan0821 tangyuan0821 changed the title gh-144361: Fix NameError when type parameter default refers to a forw… gh-144361: Fix NameError when type parameter default refers to a forward name Jun 25, 2026

@JelleZijlstra JelleZijlstra left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, please add tests covering the new behavior.

Comment thread Lib/typing.py Outdated
args = prepare(cls, args)
try:
args = prepare(cls, args)
except NameError:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this part, why do we have to add default here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The C implementation of TypeVar.typing_prepare_subst doesn't catch NameError
when the default is a forward ref — it just raises and returns NULL, so it never
gets a chance to add the default to args. I do both in the except block.

For TypeVarTuple/ParamSpec, their C code delegates to the Python prepare
functions which already handle this themselves, so the outer catch is redundant
for those but harmless.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm, is that always the right solution? Should we fix the C code instead?

@tangyuan0821 tangyuan0821 Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should merge this for now. The Python fallback only activates when __default__ raises NameError, so existing behavior stays intact. I'll follow up with a C fix for Objects/typetype.c under the same issue(#144361). Bundling both changes here makes the PR harder to review.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, let's fix it in one PR. The change here risks introducing new bugs.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in typevar_typing_prepare_subst_impl. Removed the outer try/except.
TypeVarTuple and ParamSpec delegate to Python functions that already catch this. Worth moving to C too?

tangyuan0821 and others added 2 commits June 26, 2026 09:46
Instead of catching NameError in Python's _generic_class_getitem, fix the
C implementation of TypeVar.__typing_prepare_subst__ to fall back to
FORWARDREF format when typevar_default() raises NameError.

Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PEP696 + PEP749: Defer evaluation of defaults when parametrizing

2 participants