Skip to content

Commit eb7c098

Browse files
authored
[ty] implement TypedDict structural assignment (#21467)
Closes astral-sh/ty#1387.
1 parent 1b28fc1 commit eb7c098

File tree

11 files changed

+678
-59
lines changed

11 files changed

+678
-59
lines changed

crates/ty_python_semantic/resources/mdtest/assignment/annotations.md

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -482,17 +482,14 @@ class TD2(TypedDict):
482482
x: str
483483

484484
def f(self, dt: dict[str, Any], key: str):
485-
# TODO: This should not error once typed dict assignability is implemented.
486-
# error: [invalid-assignment]
487485
x1: TD = dt.get(key, {})
488-
reveal_type(x1) # revealed: TD
486+
reveal_type(x1) # revealed: Any
489487

490488
x2: TD = dt.get(key, {"x": 0})
491489
reveal_type(x2) # revealed: Any
492490

493491
x3: TD | None = dt.get(key, {})
494-
# TODO: This should reveal `Any` once typed dict assignability is implemented.
495-
reveal_type(x3) # revealed: Any | None
492+
reveal_type(x3) # revealed: Any
496493

497494
x4: TD | None = dt.get(key, {"x": 0})
498495
reveal_type(x4) # revealed: Any

crates/ty_python_semantic/resources/mdtest/diagnostics/same_names.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ import dict_a
265265
import dict_b
266266

267267
def _(b_person: dict_b.Person):
268-
# TODO should be error: [invalid-assignment] "Object of type `dict_b.Person` is not assignable to `dict_a.Person`"
268+
# error: [invalid-assignment] "Object of type `dict_b.Person` is not assignable to `dict_a.Person`"
269269
person_var: dict_a.Person = b_person
270270
```
271271

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ source: crates/ty_test/src/lib.rs
33
expression: snapshot
44
---
55
---
6-
mdtest name: assignment_diagnostics.md - Subscript assignment diagnostics - Unknown key for all elemens of a union
6+
mdtest name: assignment_diagnostics.md - Subscript assignment diagnostics - Unknown key for all elements of a union
77
mdtest path: crates/ty_python_semantic/resources/mdtest/subscript/assignment_diagnostics.md
88
---
99

@@ -16,26 +16,27 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/subscript/assignment_dia
1616
2 |
1717
3 | class Person(TypedDict):
1818
4 | name: str
19-
5 |
20-
6 | class Animal(TypedDict):
21-
7 | name: str
22-
8 | legs: int
23-
9 |
24-
10 | def _(being: Person | Animal) -> None:
25-
11 | # error: [invalid-key]
19+
5 | phone_number: str
20+
6 |
21+
7 | class Animal(TypedDict):
22+
8 | name: str
23+
9 | legs: int
24+
10 |
25+
11 | def _(being: Person | Animal) -> None:
2626
12 | # error: [invalid-key]
27-
13 | being["surname"] = "unknown"
27+
13 | # error: [invalid-key]
28+
14 | being["surname"] = "unknown"
2829
```
2930

3031
# Diagnostics
3132

3233
```
3334
error[invalid-key]: Unknown key "surname" for TypedDict `Person`
34-
--> src/mdtest_snippet.py:13:5
35+
--> src/mdtest_snippet.py:14:5
3536
|
36-
11 | # error: [invalid-key]
3737
12 | # error: [invalid-key]
38-
13 | being["surname"] = "unknown"
38+
13 | # error: [invalid-key]
39+
14 | being["surname"] = "unknown"
3940
| ----- ^^^^^^^^^ Did you mean "name"?
4041
| |
4142
| TypedDict `Person` in union type `Person | Animal`
@@ -46,11 +47,11 @@ info: rule `invalid-key` is enabled by default
4647

4748
```
4849
error[invalid-key]: Unknown key "surname" for TypedDict `Animal`
49-
--> src/mdtest_snippet.py:13:5
50+
--> src/mdtest_snippet.py:14:5
5051
|
51-
11 | # error: [invalid-key]
5252
12 | # error: [invalid-key]
53-
13 | being["surname"] = "unknown"
53+
13 | # error: [invalid-key]
54+
14 | being["surname"] = "unknown"
5455
| ----- ^^^^^^^^^ Did you mean "name"?
5556
| |
5657
| TypedDict `Animal` in union type `Person | Animal`

crates/ty_python_semantic/resources/mdtest/snapshots/assignment_diagnosti…_-_Subscript_assignment…_-_Unknown_key_for_one_…_(b515711c0a451a86).snap

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,24 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/subscript/assignment_dia
1616
2 |
1717
3 | class Person(TypedDict):
1818
4 | name: str
19-
5 |
20-
6 | class Animal(TypedDict):
21-
7 | name: str
22-
8 | legs: int
23-
9 |
24-
10 | def _(being: Person | Animal) -> None:
25-
11 | being["legs"] = 4 # error: [invalid-key]
19+
5 | phone_number: str
20+
6 |
21+
7 | class Animal(TypedDict):
22+
8 | name: str
23+
9 | legs: int
24+
10 |
25+
11 | def _(being: Person | Animal) -> None:
26+
12 | being["legs"] = 4 # error: [invalid-key]
2627
```
2728

2829
# Diagnostics
2930

3031
```
3132
error[invalid-key]: Unknown key "legs" for TypedDict `Person`
32-
--> src/mdtest_snippet.py:11:5
33+
--> src/mdtest_snippet.py:12:5
3334
|
34-
10 | def _(being: Person | Animal) -> None:
35-
11 | being["legs"] = 4 # error: [invalid-key]
35+
11 | def _(being: Person | Animal) -> None:
36+
12 | being["legs"] = 4 # error: [invalid-key]
3637
| ----- ^^^^^^ Unknown key "legs"
3738
| |
3839
| TypedDict `Person` in union type `Person | Animal`

crates/ty_python_semantic/resources/mdtest/subscript/assignment_diagnostics.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ from typing import TypedDict
9595

9696
class Person(TypedDict):
9797
name: str
98+
phone_number: str
9899

99100
class Animal(TypedDict):
100101
name: str
@@ -104,13 +105,14 @@ def _(being: Person | Animal) -> None:
104105
being["legs"] = 4 # error: [invalid-key]
105106
```
106107

107-
## Unknown key for all elemens of a union
108+
## Unknown key for all elements of a union
108109

109110
```py
110111
from typing import TypedDict
111112

112113
class Person(TypedDict):
113114
name: str
115+
phone_number: str
114116

115117
class Animal(TypedDict):
116118
name: str

0 commit comments

Comments
 (0)