Skip to content

Commit 1cacf06

Browse files
committed
Implement closed support in get method
1 parent 64e329b commit 1cacf06

2 files changed

Lines changed: 41 additions & 3 deletions

File tree

mypy/plugins/default.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -293,9 +293,10 @@ def typed_dict_get_callback(ctx: MethodContext) -> Type:
293293
for key in keys:
294294
value_type: Type | None = ctx.type.items.get(key)
295295
if value_type is None:
296-
return ctx.default_return_type
297-
298-
if key in ctx.type.required_keys:
296+
if not ctx.type.is_closed:
297+
return ctx.default_return_type
298+
output_types.append(default_type)
299+
elif key in ctx.type.required_keys:
299300
output_types.append(value_type)
300301
else:
301302
# HACK to deal with get(key, {})

test-data/unit/check-typeddict.test

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5424,6 +5424,43 @@ reveal_type(meet(fD4C)) # N: Revealed type is "TypedDict({'a'=: builtins.int},
54245424
[builtins fixtures/dict.pyi]
54255425
[typing fixtures/typing-typeddict.pyi]
54265426

5427+
[case testTypedDictGetMethodClosed]
5428+
from typing import TypedDict, Literal
5429+
class Unrelated: pass
5430+
D = TypedDict('D', {'x': int, 'y': str}, closed=True)
5431+
d: D
5432+
u: Unrelated
5433+
x: Literal['x']
5434+
y: Literal['y']
5435+
z: Literal['z']
5436+
x_or_y: Literal['x', 'y']
5437+
x_or_z: Literal['x', 'z']
5438+
x_or_y_or_z: Literal['x', 'y', 'z']
5439+
5440+
# test with literal expression
5441+
reveal_type(d.get('x')) # N: Revealed type is "builtins.int"
5442+
reveal_type(d.get('y')) # N: Revealed type is "builtins.str"
5443+
reveal_type(d.get('z')) # N: Revealed type is "None"
5444+
reveal_type(d.get('z', u)) # N: Revealed type is "__main__.Unrelated"
5445+
5446+
# test with literal type / union of literal types with implicit default
5447+
reveal_type(d.get(x)) # N: Revealed type is "builtins.int"
5448+
reveal_type(d.get(y)) # N: Revealed type is "builtins.str"
5449+
reveal_type(d.get(z)) # N: Revealed type is "None"
5450+
reveal_type(d.get(x_or_y)) # N: Revealed type is "builtins.int | builtins.str"
5451+
reveal_type(d.get(x_or_z)) # N: Revealed type is "builtins.int | None"
5452+
reveal_type(d.get(x_or_y_or_z)) # N: Revealed type is "builtins.int | builtins.str | None"
5453+
5454+
# test with literal type / union of literal types with explicit default
5455+
reveal_type(d.get(x, u)) # N: Revealed type is "builtins.int"
5456+
reveal_type(d.get(y, u)) # N: Revealed type is "builtins.str"
5457+
reveal_type(d.get(z, u)) # N: Revealed type is "__main__.Unrelated"
5458+
reveal_type(d.get(x_or_y, u)) # N: Revealed type is "builtins.int | builtins.str"
5459+
reveal_type(d.get(x_or_z, u)) # N: Revealed type is "builtins.int | __main__.Unrelated"
5460+
reveal_type(d.get(x_or_y_or_z, u)) # N: Revealed type is "builtins.int | builtins.str | __main__.Unrelated"
5461+
[builtins fixtures/dict.pyi]
5462+
[typing fixtures/typing-typeddict.pyi]
5463+
54275464
[case testOperatorContainsNarrowsTypedDicts_unionWithList_closed]
54285465
from __future__ import annotations
54295466
from typing import assert_type, TypedDict, Union

0 commit comments

Comments
 (0)