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

2 participants