mirror of https://github.com/astral-sh/ruff
[ty] Baseline for subscript assignment diagnostics (#21404)
## Summary Add (snapshot) tests for subscript assignment diagnostics. This is mainly intended to establish a baseline before I hope to improve some of these messages.
This commit is contained in:
parent
e8e8180888
commit
84c3cecad6
|
|
@ -0,0 +1,31 @@
|
||||||
|
---
|
||||||
|
source: crates/ty_test/src/lib.rs
|
||||||
|
expression: snapshot
|
||||||
|
---
|
||||||
|
---
|
||||||
|
mdtest name: assignment_diagnostics.md - Subscript assignment diagnostics - Invalid key type
|
||||||
|
mdtest path: crates/ty_python_semantic/resources/mdtest/subscript/assignment_diagnostics.md
|
||||||
|
---
|
||||||
|
|
||||||
|
# Python source files
|
||||||
|
|
||||||
|
## mdtest_snippet.py
|
||||||
|
|
||||||
|
```
|
||||||
|
1 | config: dict[str, int] = {}
|
||||||
|
2 | config[0] = 3 # error: [invalid-assignment]
|
||||||
|
```
|
||||||
|
|
||||||
|
# Diagnostics
|
||||||
|
|
||||||
|
```
|
||||||
|
error[invalid-assignment]: Method `__setitem__` of type `bound method dict[str, int].__setitem__(key: str, value: int, /) -> None` cannot be called with a key of type `Literal[0]` and a value of type `Literal[3]` on object of type `dict[str, int]`
|
||||||
|
--> src/mdtest_snippet.py:2:1
|
||||||
|
|
|
||||||
|
1 | config: dict[str, int] = {}
|
||||||
|
2 | config[0] = 3 # error: [invalid-assignment]
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
info: rule `invalid-assignment` is enabled by default
|
||||||
|
|
||||||
|
```
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
---
|
||||||
|
source: crates/ty_test/src/lib.rs
|
||||||
|
expression: snapshot
|
||||||
|
---
|
||||||
|
---
|
||||||
|
mdtest name: assignment_diagnostics.md - Subscript assignment diagnostics - Invalid key type for `TypedDict`
|
||||||
|
mdtest path: crates/ty_python_semantic/resources/mdtest/subscript/assignment_diagnostics.md
|
||||||
|
---
|
||||||
|
|
||||||
|
# Python source files
|
||||||
|
|
||||||
|
## mdtest_snippet.py
|
||||||
|
|
||||||
|
```
|
||||||
|
1 | from typing import TypedDict
|
||||||
|
2 |
|
||||||
|
3 | class Config(TypedDict):
|
||||||
|
4 | retries: int
|
||||||
|
5 |
|
||||||
|
6 | def _(config: Config) -> None:
|
||||||
|
7 | config[0] = 3 # error: [invalid-key]
|
||||||
|
```
|
||||||
|
|
||||||
|
# Diagnostics
|
||||||
|
|
||||||
|
```
|
||||||
|
error[invalid-key]: Cannot access `Config` with a key of type `Literal[0]`. Only string literals are allowed as keys on TypedDicts.
|
||||||
|
--> src/mdtest_snippet.py:7:12
|
||||||
|
|
|
||||||
|
6 | def _(config: Config) -> None:
|
||||||
|
7 | config[0] = 3 # error: [invalid-key]
|
||||||
|
| ^
|
||||||
|
|
|
||||||
|
info: rule `invalid-key` is enabled by default
|
||||||
|
|
||||||
|
```
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
---
|
||||||
|
source: crates/ty_test/src/lib.rs
|
||||||
|
expression: snapshot
|
||||||
|
---
|
||||||
|
---
|
||||||
|
mdtest name: assignment_diagnostics.md - Subscript assignment diagnostics - Invalid value type
|
||||||
|
mdtest path: crates/ty_python_semantic/resources/mdtest/subscript/assignment_diagnostics.md
|
||||||
|
---
|
||||||
|
|
||||||
|
# Python source files
|
||||||
|
|
||||||
|
## mdtest_snippet.py
|
||||||
|
|
||||||
|
```
|
||||||
|
1 | config: dict[str, int] = {}
|
||||||
|
2 | config["retries"] = "three" # error: [invalid-assignment]
|
||||||
|
```
|
||||||
|
|
||||||
|
# Diagnostics
|
||||||
|
|
||||||
|
```
|
||||||
|
error[invalid-assignment]: Method `__setitem__` of type `bound method dict[str, int].__setitem__(key: str, value: int, /) -> None` cannot be called with a key of type `Literal["retries"]` and a value of type `Literal["three"]` on object of type `dict[str, int]`
|
||||||
|
--> src/mdtest_snippet.py:2:1
|
||||||
|
|
|
||||||
|
1 | config: dict[str, int] = {}
|
||||||
|
2 | config["retries"] = "three" # error: [invalid-assignment]
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
info: rule `invalid-assignment` is enabled by default
|
||||||
|
|
||||||
|
```
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
---
|
||||||
|
source: crates/ty_test/src/lib.rs
|
||||||
|
expression: snapshot
|
||||||
|
---
|
||||||
|
---
|
||||||
|
mdtest name: assignment_diagnostics.md - Subscript assignment diagnostics - Invalid value type for `TypedDict`
|
||||||
|
mdtest path: crates/ty_python_semantic/resources/mdtest/subscript/assignment_diagnostics.md
|
||||||
|
---
|
||||||
|
|
||||||
|
# Python source files
|
||||||
|
|
||||||
|
## mdtest_snippet.py
|
||||||
|
|
||||||
|
```
|
||||||
|
1 | from typing import TypedDict
|
||||||
|
2 |
|
||||||
|
3 | class Config(TypedDict):
|
||||||
|
4 | retries: int
|
||||||
|
5 |
|
||||||
|
6 | def _(config: Config) -> None:
|
||||||
|
7 | config["retries"] = "three" # error: [invalid-assignment]
|
||||||
|
```
|
||||||
|
|
||||||
|
# Diagnostics
|
||||||
|
|
||||||
|
```
|
||||||
|
error[invalid-assignment]: Invalid assignment to key "retries" with declared type `int` on TypedDict `Config`
|
||||||
|
--> src/mdtest_snippet.py:7:5
|
||||||
|
|
|
||||||
|
6 | def _(config: Config) -> None:
|
||||||
|
7 | config["retries"] = "three" # error: [invalid-assignment]
|
||||||
|
| ------ --------- ^^^^^^^ value of type `Literal["three"]`
|
||||||
|
| | |
|
||||||
|
| | key has declared type `int`
|
||||||
|
| TypedDict `Config`
|
||||||
|
|
|
||||||
|
info: Item declaration
|
||||||
|
--> src/mdtest_snippet.py:4:5
|
||||||
|
|
|
||||||
|
3 | class Config(TypedDict):
|
||||||
|
4 | retries: int
|
||||||
|
| ------------ Item declared here
|
||||||
|
5 |
|
||||||
|
6 | def _(config: Config) -> None:
|
||||||
|
|
|
||||||
|
info: rule `invalid-assignment` is enabled by default
|
||||||
|
|
||||||
|
```
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
---
|
||||||
|
source: crates/ty_test/src/lib.rs
|
||||||
|
expression: snapshot
|
||||||
|
---
|
||||||
|
---
|
||||||
|
mdtest name: assignment_diagnostics.md - Subscript assignment diagnostics - Misspelled key for `TypedDict`
|
||||||
|
mdtest path: crates/ty_python_semantic/resources/mdtest/subscript/assignment_diagnostics.md
|
||||||
|
---
|
||||||
|
|
||||||
|
# Python source files
|
||||||
|
|
||||||
|
## mdtest_snippet.py
|
||||||
|
|
||||||
|
```
|
||||||
|
1 | from typing import TypedDict
|
||||||
|
2 |
|
||||||
|
3 | class Config(TypedDict):
|
||||||
|
4 | retries: int
|
||||||
|
5 |
|
||||||
|
6 | def _(config: Config) -> None:
|
||||||
|
7 | config["Retries"] = 30.0 # error: [invalid-key]
|
||||||
|
```
|
||||||
|
|
||||||
|
# Diagnostics
|
||||||
|
|
||||||
|
```
|
||||||
|
error[invalid-key]: Invalid key for TypedDict `Config`
|
||||||
|
--> src/mdtest_snippet.py:7:5
|
||||||
|
|
|
||||||
|
6 | def _(config: Config) -> None:
|
||||||
|
7 | config["Retries"] = 30.0 # error: [invalid-key]
|
||||||
|
| ------ ^^^^^^^^^ Unknown key "Retries" - did you mean "retries"?
|
||||||
|
| |
|
||||||
|
| TypedDict `Config`
|
||||||
|
|
|
||||||
|
info: rule `invalid-key` is enabled by default
|
||||||
|
|
||||||
|
```
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
---
|
||||||
|
source: crates/ty_test/src/lib.rs
|
||||||
|
expression: snapshot
|
||||||
|
---
|
||||||
|
---
|
||||||
|
mdtest name: assignment_diagnostics.md - Subscript assignment diagnostics - No `__setitem__` method
|
||||||
|
mdtest path: crates/ty_python_semantic/resources/mdtest/subscript/assignment_diagnostics.md
|
||||||
|
---
|
||||||
|
|
||||||
|
# Python source files
|
||||||
|
|
||||||
|
## mdtest_snippet.py
|
||||||
|
|
||||||
|
```
|
||||||
|
1 | class ReadOnlyDict:
|
||||||
|
2 | def __getitem__(self, key: str) -> int:
|
||||||
|
3 | return 42
|
||||||
|
4 |
|
||||||
|
5 | config = ReadOnlyDict()
|
||||||
|
6 | config["retries"] = 3 # error: [invalid-assignment]
|
||||||
|
```
|
||||||
|
|
||||||
|
# Diagnostics
|
||||||
|
|
||||||
|
```
|
||||||
|
error[invalid-assignment]: Cannot assign to object of type `ReadOnlyDict` with no `__setitem__` method
|
||||||
|
--> src/mdtest_snippet.py:6:1
|
||||||
|
|
|
||||||
|
5 | config = ReadOnlyDict()
|
||||||
|
6 | config["retries"] = 3 # error: [invalid-assignment]
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
info: rule `invalid-assignment` is enabled by default
|
||||||
|
|
||||||
|
```
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
---
|
||||||
|
source: crates/ty_test/src/lib.rs
|
||||||
|
expression: snapshot
|
||||||
|
---
|
||||||
|
---
|
||||||
|
mdtest name: assignment_diagnostics.md - Subscript assignment diagnostics - Possibly missing `__setitem__` method
|
||||||
|
mdtest path: crates/ty_python_semantic/resources/mdtest/subscript/assignment_diagnostics.md
|
||||||
|
---
|
||||||
|
|
||||||
|
# Python source files
|
||||||
|
|
||||||
|
## mdtest_snippet.py
|
||||||
|
|
||||||
|
```
|
||||||
|
1 | def _(config: dict[str, int] | None) -> None:
|
||||||
|
2 | config["retries"] = 3 # error: [possibly-missing-implicit-call]
|
||||||
|
```
|
||||||
|
|
||||||
|
# Diagnostics
|
||||||
|
|
||||||
|
```
|
||||||
|
warning[possibly-missing-implicit-call]: Method `__setitem__` of type `dict[str, int] | None` may be missing
|
||||||
|
--> src/mdtest_snippet.py:2:5
|
||||||
|
|
|
||||||
|
1 | def _(config: dict[str, int] | None) -> None:
|
||||||
|
2 | config["retries"] = 3 # error: [possibly-missing-implicit-call]
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
info: rule `possibly-missing-implicit-call` is enabled by default
|
||||||
|
|
||||||
|
```
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
---
|
||||||
|
source: crates/ty_test/src/lib.rs
|
||||||
|
expression: snapshot
|
||||||
|
---
|
||||||
|
---
|
||||||
|
mdtest name: assignment_diagnostics.md - Subscript assignment diagnostics - Unknown key for all elemens of a union
|
||||||
|
mdtest path: crates/ty_python_semantic/resources/mdtest/subscript/assignment_diagnostics.md
|
||||||
|
---
|
||||||
|
|
||||||
|
# Python source files
|
||||||
|
|
||||||
|
## mdtest_snippet.py
|
||||||
|
|
||||||
|
```
|
||||||
|
1 | from typing import TypedDict
|
||||||
|
2 |
|
||||||
|
3 | class Person(TypedDict):
|
||||||
|
4 | name: str
|
||||||
|
5 |
|
||||||
|
6 | class Animal(TypedDict):
|
||||||
|
7 | name: str
|
||||||
|
8 | legs: int
|
||||||
|
9 |
|
||||||
|
10 | def _(being: Person | Animal) -> None:
|
||||||
|
11 | being["surname"] = "unknown" # error: [invalid-assignment]
|
||||||
|
```
|
||||||
|
|
||||||
|
# Diagnostics
|
||||||
|
|
||||||
|
```
|
||||||
|
error[invalid-assignment]: Method `__setitem__` of type `(key: Literal["name"], value: str, /) -> None` cannot be called with a key of type `Literal["surname"]` and a value of type `Literal["unknown"]` on object of type `Person | Animal`
|
||||||
|
--> src/mdtest_snippet.py:11:5
|
||||||
|
|
|
||||||
|
10 | def _(being: Person | Animal) -> None:
|
||||||
|
11 | being["surname"] = "unknown" # error: [invalid-assignment]
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
info: rule `invalid-assignment` is enabled by default
|
||||||
|
|
||||||
|
```
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
---
|
||||||
|
source: crates/ty_test/src/lib.rs
|
||||||
|
expression: snapshot
|
||||||
|
---
|
||||||
|
---
|
||||||
|
mdtest name: assignment_diagnostics.md - Subscript assignment diagnostics - Unknown key for one element of a union
|
||||||
|
mdtest path: crates/ty_python_semantic/resources/mdtest/subscript/assignment_diagnostics.md
|
||||||
|
---
|
||||||
|
|
||||||
|
# Python source files
|
||||||
|
|
||||||
|
## mdtest_snippet.py
|
||||||
|
|
||||||
|
```
|
||||||
|
1 | from typing import TypedDict
|
||||||
|
2 |
|
||||||
|
3 | class Person(TypedDict):
|
||||||
|
4 | name: str
|
||||||
|
5 |
|
||||||
|
6 | class Animal(TypedDict):
|
||||||
|
7 | name: str
|
||||||
|
8 | legs: int
|
||||||
|
9 |
|
||||||
|
10 | def _(being: Person | Animal) -> None:
|
||||||
|
11 | being["legs"] = 4 # error: [invalid-assignment]
|
||||||
|
```
|
||||||
|
|
||||||
|
# Diagnostics
|
||||||
|
|
||||||
|
```
|
||||||
|
error[invalid-assignment]: Method `__setitem__` of type `(key: Literal["name"], value: str, /) -> None` cannot be called with a key of type `Literal["legs"]` and a value of type `Literal[4]` on object of type `Person | Animal`
|
||||||
|
--> src/mdtest_snippet.py:11:5
|
||||||
|
|
|
||||||
|
10 | def _(being: Person | Animal) -> None:
|
||||||
|
11 | being["legs"] = 4 # error: [invalid-assignment]
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
info: rule `invalid-assignment` is enabled by default
|
||||||
|
|
||||||
|
```
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
---
|
||||||
|
source: crates/ty_test/src/lib.rs
|
||||||
|
expression: snapshot
|
||||||
|
---
|
||||||
|
---
|
||||||
|
mdtest name: assignment_diagnostics.md - Subscript assignment diagnostics - Wrong value type for one element of a union
|
||||||
|
mdtest path: crates/ty_python_semantic/resources/mdtest/subscript/assignment_diagnostics.md
|
||||||
|
---
|
||||||
|
|
||||||
|
# Python source files
|
||||||
|
|
||||||
|
## mdtest_snippet.py
|
||||||
|
|
||||||
|
```
|
||||||
|
1 | def _(config: dict[str, int] | dict[str, str]) -> None:
|
||||||
|
2 | config["retries"] = 3 # error: [invalid-assignment]
|
||||||
|
```
|
||||||
|
|
||||||
|
# Diagnostics
|
||||||
|
|
||||||
|
```
|
||||||
|
error[invalid-assignment]: Method `__setitem__` of type `(bound method dict[str, int].__setitem__(key: str, value: int, /) -> None) | (bound method dict[str, str].__setitem__(key: str, value: str, /) -> None)` cannot be called with a key of type `Literal["retries"]` and a value of type `Literal[3]` on object of type `dict[str, int] | dict[str, str]`
|
||||||
|
--> src/mdtest_snippet.py:2:5
|
||||||
|
|
|
||||||
|
1 | def _(config: dict[str, int] | dict[str, str]) -> None:
|
||||||
|
2 | config["retries"] = 3 # error: [invalid-assignment]
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
info: rule `invalid-assignment` is enabled by default
|
||||||
|
|
||||||
|
```
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
---
|
||||||
|
source: crates/ty_test/src/lib.rs
|
||||||
|
expression: snapshot
|
||||||
|
---
|
||||||
|
---
|
||||||
|
mdtest name: assignment_diagnostics.md - Subscript assignment diagnostics - Wrong value type for all elements of a union
|
||||||
|
mdtest path: crates/ty_python_semantic/resources/mdtest/subscript/assignment_diagnostics.md
|
||||||
|
---
|
||||||
|
|
||||||
|
# Python source files
|
||||||
|
|
||||||
|
## mdtest_snippet.py
|
||||||
|
|
||||||
|
```
|
||||||
|
1 | def _(config: dict[str, int] | dict[str, str]) -> None:
|
||||||
|
2 | config["retries"] = 3.0 # error: [invalid-assignment]
|
||||||
|
```
|
||||||
|
|
||||||
|
# Diagnostics
|
||||||
|
|
||||||
|
```
|
||||||
|
error[invalid-assignment]: Method `__setitem__` of type `(bound method dict[str, int].__setitem__(key: str, value: int, /) -> None) | (bound method dict[str, str].__setitem__(key: str, value: str, /) -> None)` cannot be called with a key of type `Literal["retries"]` and a value of type `float` on object of type `dict[str, int] | dict[str, str]`
|
||||||
|
--> src/mdtest_snippet.py:2:5
|
||||||
|
|
|
||||||
|
1 | def _(config: dict[str, int] | dict[str, str]) -> None:
|
||||||
|
2 | config["retries"] = 3.0 # error: [invalid-assignment]
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
info: rule `invalid-assignment` is enabled by default
|
||||||
|
|
||||||
|
```
|
||||||
|
|
@ -0,0 +1,117 @@
|
||||||
|
# Subscript assignment diagnostics
|
||||||
|
|
||||||
|
<!-- snapshot-diagnostics -->
|
||||||
|
|
||||||
|
## Invalid value type
|
||||||
|
|
||||||
|
```py
|
||||||
|
config: dict[str, int] = {}
|
||||||
|
config["retries"] = "three" # error: [invalid-assignment]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Invalid key type
|
||||||
|
|
||||||
|
```py
|
||||||
|
config: dict[str, int] = {}
|
||||||
|
config[0] = 3 # error: [invalid-assignment]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Invalid value type for `TypedDict`
|
||||||
|
|
||||||
|
```py
|
||||||
|
from typing import TypedDict
|
||||||
|
|
||||||
|
class Config(TypedDict):
|
||||||
|
retries: int
|
||||||
|
|
||||||
|
def _(config: Config) -> None:
|
||||||
|
config["retries"] = "three" # error: [invalid-assignment]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Invalid key type for `TypedDict`
|
||||||
|
|
||||||
|
```py
|
||||||
|
from typing import TypedDict
|
||||||
|
|
||||||
|
class Config(TypedDict):
|
||||||
|
retries: int
|
||||||
|
|
||||||
|
def _(config: Config) -> None:
|
||||||
|
config[0] = 3 # error: [invalid-key]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Misspelled key for `TypedDict`
|
||||||
|
|
||||||
|
```py
|
||||||
|
from typing import TypedDict
|
||||||
|
|
||||||
|
class Config(TypedDict):
|
||||||
|
retries: int
|
||||||
|
|
||||||
|
def _(config: Config) -> None:
|
||||||
|
config["Retries"] = 30.0 # error: [invalid-key]
|
||||||
|
```
|
||||||
|
|
||||||
|
## No `__setitem__` method
|
||||||
|
|
||||||
|
```py
|
||||||
|
class ReadOnlyDict:
|
||||||
|
def __getitem__(self, key: str) -> int:
|
||||||
|
return 42
|
||||||
|
|
||||||
|
config = ReadOnlyDict()
|
||||||
|
config["retries"] = 3 # error: [invalid-assignment]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Possibly missing `__setitem__` method
|
||||||
|
|
||||||
|
```py
|
||||||
|
def _(config: dict[str, int] | None) -> None:
|
||||||
|
config["retries"] = 3 # error: [possibly-missing-implicit-call]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Unknown key for one element of a union
|
||||||
|
|
||||||
|
```py
|
||||||
|
from typing import TypedDict
|
||||||
|
|
||||||
|
class Person(TypedDict):
|
||||||
|
name: str
|
||||||
|
|
||||||
|
class Animal(TypedDict):
|
||||||
|
name: str
|
||||||
|
legs: int
|
||||||
|
|
||||||
|
def _(being: Person | Animal) -> None:
|
||||||
|
being["legs"] = 4 # error: [invalid-assignment]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Unknown key for all elemens of a union
|
||||||
|
|
||||||
|
```py
|
||||||
|
from typing import TypedDict
|
||||||
|
|
||||||
|
class Person(TypedDict):
|
||||||
|
name: str
|
||||||
|
|
||||||
|
class Animal(TypedDict):
|
||||||
|
name: str
|
||||||
|
legs: int
|
||||||
|
|
||||||
|
def _(being: Person | Animal) -> None:
|
||||||
|
being["surname"] = "unknown" # error: [invalid-assignment]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Wrong value type for one element of a union
|
||||||
|
|
||||||
|
```py
|
||||||
|
def _(config: dict[str, int] | dict[str, str]) -> None:
|
||||||
|
config["retries"] = 3 # error: [invalid-assignment]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Wrong value type for all elements of a union
|
||||||
|
|
||||||
|
```py
|
||||||
|
def _(config: dict[str, int] | dict[str, str]) -> None:
|
||||||
|
config["retries"] = 3.0 # error: [invalid-assignment]
|
||||||
|
```
|
||||||
|
|
@ -526,10 +526,20 @@ class Person(TypedDict):
|
||||||
name: str
|
name: str
|
||||||
age: int | None
|
age: int | None
|
||||||
|
|
||||||
|
class Animal(TypedDict):
|
||||||
|
name: str
|
||||||
|
|
||||||
NAME_FINAL: Final = "name"
|
NAME_FINAL: Final = "name"
|
||||||
AGE_FINAL: Final[Literal["age"]] = "age"
|
AGE_FINAL: Final[Literal["age"]] = "age"
|
||||||
|
|
||||||
def _(person: Person, literal_key: Literal["age"], union_of_keys: Literal["age", "name"], str_key: str, unknown_key: Any) -> None:
|
def _(
|
||||||
|
person: Person,
|
||||||
|
being: Person | Animal,
|
||||||
|
literal_key: Literal["age"],
|
||||||
|
union_of_keys: Literal["age", "name"],
|
||||||
|
str_key: str,
|
||||||
|
unknown_key: Any,
|
||||||
|
) -> None:
|
||||||
reveal_type(person["name"]) # revealed: str
|
reveal_type(person["name"]) # revealed: str
|
||||||
reveal_type(person["age"]) # revealed: int | None
|
reveal_type(person["age"]) # revealed: int | None
|
||||||
|
|
||||||
|
|
@ -548,18 +558,30 @@ def _(person: Person, literal_key: Literal["age"], union_of_keys: Literal["age",
|
||||||
|
|
||||||
# No error here:
|
# No error here:
|
||||||
reveal_type(person[unknown_key]) # revealed: Unknown
|
reveal_type(person[unknown_key]) # revealed: Unknown
|
||||||
|
|
||||||
|
reveal_type(being["name"]) # revealed: str
|
||||||
|
|
||||||
|
# TODO: A type of `int | None | Unknown` might be better here. The `str` is mixed in
|
||||||
|
# because `Animal.__getitem__` can only return `str`.
|
||||||
|
# error: [invalid-key] "Invalid key for TypedDict `Animal`"
|
||||||
|
reveal_type(being["age"]) # revealed: int | None | str
|
||||||
```
|
```
|
||||||
|
|
||||||
### Writing
|
### Writing
|
||||||
|
|
||||||
```py
|
```py
|
||||||
from typing_extensions import TypedDict, Final, Literal, LiteralString, Any
|
from typing_extensions import TypedDict, Final, Literal, LiteralString, Any
|
||||||
|
from ty_extensions import Intersection
|
||||||
|
|
||||||
class Person(TypedDict):
|
class Person(TypedDict):
|
||||||
name: str
|
name: str
|
||||||
surname: str
|
surname: str
|
||||||
age: int | None
|
age: int | None
|
||||||
|
|
||||||
|
class Animal(TypedDict):
|
||||||
|
name: str
|
||||||
|
legs: int
|
||||||
|
|
||||||
NAME_FINAL: Final = "name"
|
NAME_FINAL: Final = "name"
|
||||||
AGE_FINAL: Final[Literal["age"]] = "age"
|
AGE_FINAL: Final[Literal["age"]] = "age"
|
||||||
|
|
||||||
|
|
@ -583,6 +605,23 @@ def _(person: Person, union_of_keys: Literal["name", "surname"]):
|
||||||
# error: [invalid-assignment] "Cannot assign value of type `Literal[1]` to key of type `Literal["name", "surname"]` on TypedDict `Person`"
|
# error: [invalid-assignment] "Cannot assign value of type `Literal[1]` to key of type `Literal["name", "surname"]` on TypedDict `Person`"
|
||||||
person[union_of_keys] = 1
|
person[union_of_keys] = 1
|
||||||
|
|
||||||
|
def _(being: Person | Animal):
|
||||||
|
being["name"] = "Being"
|
||||||
|
|
||||||
|
# error: [invalid-assignment] "Method `__setitem__` of type `(Overload[(key: Literal["name"], value: str, /) -> None, (key: Literal["surname"], value: str, /) -> None, (key: Literal["age"], value: int | None, /) -> None]) | (Overload[(key: Literal["name"], value: str, /) -> None, (key: Literal["legs"], value: int, /) -> None])` cannot be called with a key of type `Literal["name"]` and a value of type `Literal[1]` on object of type `Person | Animal`"
|
||||||
|
being["name"] = 1
|
||||||
|
|
||||||
|
# error: [invalid-assignment] "Method `__setitem__` of type `(Overload[(key: Literal["name"], value: str, /) -> None, (key: Literal["surname"], value: str, /) -> None, (key: Literal["age"], value: int | None, /) -> None]) | (Overload[(key: Literal["name"], value: str, /) -> None, (key: Literal["legs"], value: int, /) -> None])` cannot be called with a key of type `Literal["surname"]` and a value of type `Literal["unknown"]` on object of type `Person | Animal`"
|
||||||
|
being["surname"] = "unknown"
|
||||||
|
|
||||||
|
def _(centaur: Intersection[Person, Animal]):
|
||||||
|
centaur["name"] = "Chiron"
|
||||||
|
centaur["age"] = 100
|
||||||
|
centaur["legs"] = 4
|
||||||
|
|
||||||
|
# TODO: This should be an `invalid-key` error
|
||||||
|
centaur["unknown"] = "value"
|
||||||
|
|
||||||
def _(person: Person, union_of_keys: Literal["name", "age"], unknown_value: Any):
|
def _(person: Person, union_of_keys: Literal["name", "age"], unknown_value: Any):
|
||||||
person[union_of_keys] = unknown_value
|
person[union_of_keys] = unknown_value
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue