Skip to content

Commit 4d3a7b0

Browse files
committed
Implement closed support in get method
1 parent ca5a13f commit 4d3a7b0

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
@@ -5422,6 +5422,43 @@ reveal_type(meet(fD4C)) # N: Revealed type is "TypedDict({'a'=: builtins.int},
54225422
[builtins fixtures/dict.pyi]
54235423
[typing fixtures/typing-typeddict.pyi]
54245424

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

0 commit comments

Comments
 (0)