8000 Fix TypedDict init from Type with optional keys (#17068) · python/mypy@4310586 · GitHub
[go: up one dir, main page]

Skip to content

Commit 4310586

Browse files
authored
Fix TypedDict init from Type with optional keys (#17068)
Followup to #16963 Correctly set optional and required keys for the TypedDict init callable. Ref: #11644
1 parent bebd278 commit 4310586

File tree

3 files changed

+34
-5
lines changed

3 files changed

+34
-5
lines changed

mypy/checkexpr.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -949,7 +949,10 @@ def typeddict_callable(self, info: TypeInfo) -> CallableType:
949949
def typeddict_callable_from_context(self, callee: TypedDictType) -> CallableType:
950950
return CallableType(
951951
list(callee.items.values()),
952-
[ArgKind.ARG_NAMED] * len(callee.items),
952+
[
953+
ArgKind.ARG_NAMED if name in callee.required_keys else ArgKind.ARG_NAMED_OPT
954+
for name in callee.items
955+
],
953956
list(callee.items.keys()),
954957
callee,
955958
self.named_type("builtins.type"),

test-data/unit/check-typeddict.test

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3450,16 +3450,40 @@ reveal_type(p) # N: Revealed type is "TypedDict('__main__.Params', {'x': builtin
34503450

34513451
[case testInitTypedDictFromType]
34523452
from typing import TypedDict, Type
3453+
from typing_extensions import Required
34533454

3454-
class Point(TypedDict):
3455-
x: int
3455+
class Point(TypedDict, total=False):
3456+
x: Required[int]
34563457
y: int
34573458

34583459
def func(cls: Type[Point]) -> None:
3459-
reveal_type(cls) # N: Revealed type is "Type[TypedDict('__main__.Point', {'x': builtins.int, 'y': builtins.int})]"
3460+
reveal_type(cls) # N: Revealed type is "Type[TypedDict('__main__.Point', {'x': builtins.int, 'y'?: builtins.int})]"
34603461
cls(x=1, y=2)
34613462
cls(1, 2) # E: Too many positional arguments
3462-
cls(x=1) # E: Missing named argument "y"
3463+
cls(x=1)
3464+
cls(y=2) # E: Missing named argument "x"
34633465
cls(x=1, y=2, error="") # E: Unexpected keyword argument "error"
34643466
[typing fixtures/typing-full.pyi]
34653467
[builtins fixtures/tuple.pyi]
3468+
3469+
[case testInitTypedDictFromTypeGeneric]
3470+
from typing import Generic, TypedDict, Type, TypeVar
3471+
from typing_extensions import Required
3472+
3473+
class Point(TypedDict, total=False):
3474+
x: Required[int]
3475+
y: int
3476+
3477+
T = TypeVar("T", bound=Point)
3478+
3479+
class A(Generic[T]):
3480+
def __init__(self, a: Type[T]) -> None:
3481+
self.a = a
3482+
3483+
def func(self) -> T:
3484+
reveal_type(self.a) # N: Revealed type is "Type[T`1]"
3485+
self.a(x=1, y=2)
3486+
self.a(y=2) # E: Missing named argument "x"
3487+
return self.a(x=1)
3488+
[typing fixtures/typing-full.pyi]
3489+
[builtins fixtures/tuple.pyi]

test-data/unit/lib-stub/typing_extensions.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ Never: _SpecialForm
3939

4040
TypeVarTuple: _SpecialForm
4141
Unpack: _SpecialForm
42+
Required: _SpecialForm
43+
NotRequired: _SpecialForm
4244

4345
@final
4446
class TypeAliasType:

0 commit comments

Comments
 (0)
0