Skip to content

Commit

Permalink
Fix TypedDict init from Type with optional keys (#17068)
Browse files Browse the repository at this point in the history
Followup to #16963
Correctly set optional and required keys for the TypedDict init
callable.

Ref: #11644
  • Loading branch information
cdce8p authored Mar 27, 2024
1 parent bebd278 commit 4310586
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 5 deletions.
5 changes: 4 additions & 1 deletion mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -949,7 +949,10 @@ def typeddict_callable(self, info: TypeInfo) -> CallableType:
def typeddict_callable_from_context(self, callee: TypedDictType) -> CallableType:
return CallableType(
list(callee.items.values()),
[ArgKind.ARG_NAMED] * len(callee.items),
[
ArgKind.ARG_NAMED if name in callee.required_keys else ArgKind.ARG_NAMED_OPT
for name in callee.items
],
list(callee.items.keys()),
callee,
self.named_type("builtins.type"),
Expand Down
32 changes: 28 additions & 4 deletions test-data/unit/check-typeddict.test
Original file line number Diff line number Diff line change
Expand Up @@ -3450,16 +3450,40 @@ reveal_type(p) # N: Revealed type is "TypedDict('__main__.Params', {'x': builtin

[case testInitTypedDictFromType]
from typing import TypedDict, Type
from typing_extensions import Required

class Point(TypedDict):
x: int
class Point(TypedDict, total=False):
x: Required[int]
y: int

def func(cls: Type[Point]) -> None:
reveal_type(cls) # N: Revealed type is "Type[TypedDict('__main__.Point', {'x': builtins.int, 'y': builtins.int})]"
reveal_type(cls) # N: Revealed type is "Type[TypedDict('__main__.Point', {'x': builtins.int, 'y'?: builtins.int})]"
cls(x=1, y=2)
cls(1, 2) # E: Too many positional arguments
cls(x=1) # E: Missing named argument "y"
cls(x=1)
cls(y=2) # E: Missing named argument "x"
cls(x=1, y=2, error="") # E: Unexpected keyword argument "error"
[typing fixtures/typing-full.pyi]
[builtins fixtures/tuple.pyi]

[case testInitTypedDictFromTypeGeneric]
from typing import Generic, TypedDict, Type, TypeVar
from typing_extensions import Required

class Point(TypedDict, total=False):
x: Required[int]
y: int

T = TypeVar("T", bound=Point)

class A(Generic[T]):
def __init__(self, a: Type[T]) -> None:
self.a = a

def func(self) -> T:
reveal_type(self.a) # N: Revealed type is "Type[T`1]"
self.a(x=1, y=2)
self.a(y=2) # E: Missing named argument "x"
return self.a(x=1)
[typing fixtures/typing-full.pyi]
[builtins fixtures/tuple.pyi]
2 changes: 2 additions & 0 deletions test-data/unit/lib-stub/typing_extensions.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ Never: _SpecialForm

TypeVarTuple: _SpecialForm
Unpack: _SpecialForm
Required: _SpecialForm
NotRequired: _SpecialForm

@final
class TypeAliasType:
Expand Down

0 comments on commit 4310586

Please sign in to comment.