forked from python/typing
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclasses_classvar.py
More file actions
167 lines (115 loc) · 4.15 KB
/
classes_classvar.py
File metadata and controls
167 lines (115 loc) · 4.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
"""
Tests the typing.ClassVar special form.
"""
# Specification: https://typing.readthedocs.io/en/latest/spec/class-compat.html#classvar
from typing import (
Annotated,
Any,
Callable,
ClassVar,
Final,
Generic,
ParamSpec,
Protocol,
TypeAlias,
TypeVar,
TypeVarTuple,
assert_type,
cast,
)
from typing import ClassVar as CV
var1 = 3
P = ParamSpec("P")
T = TypeVar("T")
Ts = TypeVarTuple("Ts")
# This is currently commented out because it causes mypy to crash.
# class ClassA(Generic[T, P, Unpack[Ts]]):
class ClassA(Generic[T, P]):
# > ClassVar accepts only a single argument that should be a valid type
bad1: ClassVar[int, str] = cast(Any, 0) # E: too many arguments
bad2: CV[3] = cast(Any, 0) # E: invalid type
bad3: CV[var] = cast(Any, 0) # E: invalid type
# > Note that a ClassVar parameter cannot include any type variables,
# > regardless of the level of nesting.
bad4: ClassVar[T] = cast(Any, 0) # E: cannot use TypeVar
bad5: ClassVar[list[T]] = cast(Any, 0) # E: cannot use TypeVar
bad6: ClassVar[Callable[P, Any]] = cast(Any, 0) # E: cannot use ParamSpec
# This is currently commented out because it causes mypy to crash.
# bad7: ClassVar[tuple[*Ts]] # E: cannot use TypeVarTuple
bad8: ClassVar[list[str]] = {} # E: type violation in initialization
bad9: Final[ClassVar[int]] = 3 # E: ClassVar cannot be nested with Final
bad10: list[ClassVar[int]] = [] # E: ClassVar cannot be nested
good1: CV[int] = 1
good2: ClassVar[list[str]] = []
good3: ClassVar[Any] = 1
# > If an assigned value is available, the type should be inferred as some type
# > to which this value is assignable.
# Here, type checkers could infer good4 as `float` or `Any`, for example.
good4: ClassVar = 3.1
# > If the `ClassVar` qualifier is used without any assigned value, the type
# > should be inferred as `Any`:
good5: ClassVar #E? Type checkers may error on uninitialized ClassVar
good6: Annotated[ClassVar[list[int]], ""] = []
def method1(self, a: ClassVar[int]): # E: ClassVar not allowed here
x: ClassVar[str] = "" # E: ClassVar not allowed here
self.xx: ClassVar[str] = "" # E: ClassVar not allowed here
def method2(self) -> ClassVar[int]: # E: ClassVar not allowed here
return 3
bad11: ClassVar[int] = 3 # E: ClassVar not allowed here
bad12: TypeAlias = ClassVar[str] # E: ClassVar not allowed here
assert_type(ClassA.good1, int)
assert_type(ClassA.good2, list[str])
assert_type(ClassA.good3, Any)
assert_type(ClassA.good5, Any)
class BasicStarship:
captain: str = "Picard" # Instance variable with default
damage: int # Instance variable without default
stats: ClassVar[dict[str, int]] = {} # Class variable
def __init__(self, damage: int) -> None:
self.damage = damage
class Starship:
captain: str = "Picard"
damage: int
stats: ClassVar[dict[str, int]] = {}
def __init__(self, damage: int, captain: str | None = None):
self.damage = damage
if captain:
self.captain = captain
def hit(self):
Starship.stats["hits"] = Starship.stats.get("hits", 0) + 1
enterprise_d = Starship(3000)
enterprise_d.stats = {} # E: cannot access via instance
Starship.stats = {} # OK
# > As a matter of convenience (and convention), instance variables can be
# > annotated in __init__ or other methods, rather than in the class.
class Box(Generic[T]):
def __init__(self, content) -> None:
self.content: T = content
# Tests for ClassVar in Protocol
class ProtoA(Protocol):
x: ClassVar[str]
y: ClassVar[str]
z: CV = [""]
class ProtoAImpl:
x = ""
def __init__(self) -> None:
self.y = ""
a: ProtoA = ProtoAImpl() # E: y is not a ClassVar
class ProtoB(Protocol):
x: int = 3
y: int
z: ClassVar[int]
@classmethod
def method1(cls) -> None:
return None
@staticmethod
def method2() -> None:
return None
class ProtoBImpl(ProtoB):
y = 0
z = 0
b_x: int = ProtoBImpl.x
b_y: int = ProtoBImpl.y
b_z: int = ProtoBImpl.z
b_m1 = ProtoBImpl.method1
b_m2 = ProtoBImpl.method2