microsoft / pyright

Static Type Checker for Python
Other
13.04k stars 1.39k forks source link

Regression: typing.NotRequired not working in typing.TypedDict #8375

Closed runfalk closed 1 month ago

runfalk commented 1 month ago

Describe the bug typing.NotRequired no longer seem to be allowed in typing.TypedDict. The same seems to be true for typing.Required when total=False.

Code or Screenshots This is an example from the standard library docs (https://docs.python.org/3/library/typing.html#typing.TypedDict).

import typing as t

class Point2D(t.TypedDict):
    x: int
    y: int
    label: t.NotRequired[str]

class Point2DReversed(t.TypedDict, total=False):
    x: t.Required[int]
    y: t.Required[int]
    label: str
test.py
  test.py:6:12 - error: Variable not allowed in type expression (reportInvalidTypeForm)
  test.py:6:12 - error: Type of "NotRequired" is unknown (reportUnknownMemberType)
  test.py:9:8 - error: Variable not allowed in type expression (reportInvalidTypeForm)
  test.py:9:8 - error: Type of "Required" is unknown (reportUnknownMemberType)
  test.py:10:8 - error: Variable not allowed in type expression (reportInvalidTypeForm)
  test.py:10:8 - error: Type of "Required" is unknown (reportUnknownMemberType)
6 errors, 0 warnings, 0 informations

VS Code extension or command-line Versions:

pyright 1.1.371 (worked in 1.1.370)
Python 3.11.9

Pyright config:

[tool.pyright]
typeCheckingMode = "strict"
useLibraryCodeForTypes = true
pythonVersion = "3.11"
reportUnnecessaryTypeIgnoreComment = true
reportMissingTypeStubs = false
reportUnusedImport = false
sblask commented 1 month ago

I don't think it's because or Required or NotRequired, but because of using typing.. For:

import typing

class Something(typing.TypedDict):
    One: typing.NotRequired[str]
    Two: typing.NotRequired[float]

I get error: Variable not allowed in type expression (reportInvalidTypeForm) for One and Two. No such errors for:

import typing
from typing import NotRequired

class Something(typing.TypedDict):
    One: NotRequired[str]
    Two: NotRequired[float]
erictraut commented 1 month ago

Apologies for the regression. This will be fixed in the next release.

This bug is specific to the fully-qualified form (typing.Required) and doesn't appear with just Required. Most developers use the latter form (via a from typing import Required statement). The fully-qualified form didn't previously appear in our unit tests nor did it appear in the 120 or so public repositories that we use for regression testing. I've updated our unit tests to include this form.

There is some special-casing that's required for Required and similar special forms because they are defined in typing.pyi and typing_extensions.pyi using a statement form that looks like a variable declaration (Required: _SpecialForm).

erictraut commented 1 month ago

This is addressed in pyright 1.1.372.