← Back to index

typeddicts_readonly_inheritance.py

True Positive
False Positive
False Negative
Optional (detected)
Warning or Info
TP: 5
FP: 0
FN: 6
Optional: 0 / 0
1"""
2Tests inheritance rules involving typing.ReadOnly.
3"""
4
5# Specification: https://typing.readthedocs.io/en/latest/spec/typeddict.html#read-only-items
6
7from typing import Collection, NotRequired, Required, TypedDict
8from typing_extensions import ReadOnly
9
10# > Subclasses can redeclare read-only items as non-read-only, allowing them
11# > to be mutated.
14class NamedDict(TypedDict):
15 name: ReadOnly[str]
18class Album1(NamedDict):
19 name: str
20 year: int
23a1: Album1 = {"name": "Flood", "year": 1990}
24a1["year"] = 1973 # OK
25a1["name"] = "Dark Side Of The Moon" # OK
28# > If a read-only item is not redeclared, it remains read-only.
31class Album2(NamedDict):
32 year: int
35a2: Album2 = {"name": "Flood", "year": 1990}
36a2["name"] = "Dark Side Of The Moon" # E
[invalid-assignment] Cannot assign to key "name" on TypedDict `Album2`: key is marked read-only
39# > Subclasses can narrow value types of read-only items.
42class AlbumCollection(TypedDict):
43 albums: ReadOnly[Collection[Album1]]
44 alt: ReadOnly[list[str | int]]
47class RecordShop(AlbumCollection):
48 name: str
49 albums: ReadOnly[list[Album1]] # OK
50 alt: ReadOnly[list[str]] # E
Expected a ty diagnostic for this line
53# > Subclasses can require items that are read-only but not required in the
54# > superclass.
57class OptionalName(TypedDict):
58 name: ReadOnly[NotRequired[str]]
61class RequiredName(OptionalName):
62 name: ReadOnly[Required[str]] # OK
65d: RequiredName = {} # E
[missing-typed-dict-key] Missing required key 'name' in TypedDict `RequiredName` constructor
68# > Subclasses can combine these rules.
71class OptionalIdent(TypedDict):
72 ident: ReadOnly[NotRequired[str | int]]
75class User(OptionalIdent):
76 ident: str # Required, mutable, and not an int
79u: User
80u = {"ident": ""} # OK
81u["ident"] = "" # OK
82u["ident"] = 3 # E
[invalid-assignment] Invalid assignment to key "ident" with declared type `str` on TypedDict `User`: value of type `Literal[3]`
83u = {"ident": 3} # E
[invalid-argument-type] Invalid argument to key "ident" with declared type `str` on TypedDict `User`: value of type `Literal[3]`
84u = {} # E
[missing-typed-dict-key] Missing required key 'ident' in TypedDict `User` constructor
87class F1(TypedDict):
88 a: Required[int]
89 b: ReadOnly[NotRequired[int]]
90 c: ReadOnly[Required[int]]
93class F3(F1):
94 a: ReadOnly[int] # E
Expected a ty diagnostic for this line
97class F4(F1):
98 a: NotRequired[int] # E
Expected a ty diagnostic for this line
101class F5(F1):
102 b: ReadOnly[Required[int]] # OK
105class F6(F1):
106 c: ReadOnly[NotRequired[int]] # E
Expected a ty diagnostic for this line
109class TD_A1(TypedDict):
110 x: int
111 y: ReadOnly[int]
114class TD_A2(TypedDict):
115 x: float
116 y: ReadOnly[float]
119class TD_A(TD_A1, TD_A2): ... # E: x is incompatible
Expected a ty diagnostic for this line
122class TD_B1(TypedDict):
123 x: ReadOnly[NotRequired[int]]
124 y: ReadOnly[Required[int]]
127class TD_B2(TypedDict):
128 x: ReadOnly[Required[int]]
129 y: ReadOnly[NotRequired[int]]
132class TD_B(TD_B1, TD_B2): ... # E: x is incompatible
Expected a ty diagnostic for this line