Skip to content

Allow building type qualifiers like NotRequired[...] at runtime - #5450

Open
MarcoGorelli wants to merge 1 commit into
meta:mainfrom
MarcoGorelli:fix-qualifier-runtime-value
Open

MarcoGorelli wants to merge 1 commit into
meta:mainfrom
MarcoGorelli:fix-qualifier-runtime-value

Conversation

@MarcoGorelli

@MarcoGorelli MarcoGorelli commented Oct 29, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

The idea is:

  • If we have a subscript expression, like x = my_list[0] where we know that my_list is a list[int], then x gets inferred as int. That's what
    self.subscript_infer(
    &base,
    &x.slice,
    x.range(),
    type_form_context.unwrap_or(TypeFormContext::TypeExpression),
    errors,
    )
    does
  • If however we have a subscript assignment like x = NotRequired[int], then NotRequired is a _SpecialForm which is typed to return object for __getitem__, so we need to infer x as object rather than reporting it as an invalid annotation
  • For cases in class definitions, like class MyClass(TypedDict, total=False), however, we want to preserve the current behaviour and raise on something like extra_items=NotRequired[int], which is why in fn expr_class_keyword we need to pass down Some(TypeFormContext::ClassKeyword) so that if type_form_context.is_none() in expr_infer_without_shape_comment doesn't evaluate to true

Note that x: NotRequired[int] still gets checked as-before, as this change only covers the if type_form_context.is_none() case, and in the x: NotRequired[int] case, there is a type form context

Fixes #5429

  • I am a human, and I fully understand the code I am submitting.

I used Claude to generate the code, but the description here is fully written by me

Test Plan

@meta-codesync

meta-codesync Bot commented Oct 29, 2026

Copy link
Copy Markdown
Contributor

This pull request has been imported. If you are a Meta employee, you can view this in D128312510. (Because this pull request was imported automatically, there will not be any future comments.)

@github-actions

This comment has been minimized.

Code that builds qualifiers dynamically, such as
`{key: NotRequired[hint] for key, hint in hints.items()}` (used by
huggingface-hub), was rejected with "`NotRequired` is not allowed in this
context". A plain value expression was checked as if it were a type
expression, so the subscript was treated as a misplaced annotation.

Fixes meta#5429.

A subscript of `ClassVar`, `Final`, `ReadOnly`, `Required`, or `NotRequired`
that has no type-form context is now a runtime value of type `object`, which
matches typeshed's `_SpecialForm.__getitem__`. Misuse is still caught: using
such a value as an annotation reports "Expected a type form", and class
keywords like `extra_items=NotRequired[int]` are now checked as type forms,
so they keep their existing error.
@MarcoGorelli
MarcoGorelli force-pushed the fix-qualifier-runtime-value branch from f228845 to 5ced393 Compare October 29, 2026 14:49
@github-actions github-actions Bot added size/s and removed size/s labels Oct 29, 2026
@MarcoGorelli
MarcoGorelli marked this pull request as ready for review October 29, 2026 14:59
@github-actions

Copy link
Copy Markdown

According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅

This branch has not been deployed

No deployments
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.

NotRequired[...] built at runtime for introspection reported as invalid-annotation

2 participants