-
Notifications
You must be signed in to change notification settings - Fork 297
Expand file tree
/
Copy pathconstructors_call_new.py
More file actions
148 lines (88 loc) · 3.17 KB
/
constructors_call_new.py
File metadata and controls
148 lines (88 loc) · 3.17 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
"""
Tests the evaluation of calls to constructors when there is a __new__
method defined.
"""
# Specification: https://typing.readthedocs.io/en/latest/spec/constructors.html#new-method
from typing import Any, Generic, NoReturn, Self, TypeVar, assert_type
T = TypeVar("T")
class Class1(Generic[T]):
def __new__(cls, x: T) -> Self:
return super().__new__(cls)
assert_type(Class1[int](1), Class1[int])
assert_type(Class1[float](1), Class1[float])
Class1[int](1.0) # E
assert_type(Class1(1), Class1[int])
assert_type(Class1(1.0), Class1[float])
class Class2(Generic[T]):
def __new__(cls, *args, **kwargs) -> Self:
return super().__new__(cls)
def __init__(self, x: T) -> None:
pass
assert_type(Class2(1), Class2[int])
assert_type(Class2(""), Class2[str])
class Class3:
def __new__(cls) -> int:
return 0
# In this case, the __init__ method should not be considered
# by the type checker when evaluating a constructor call.
def __init__(self, x: int):
pass
assert_type(Class3(), int)
# > For purposes of this test, an explicit return type of Any (or a union
# > containing Any) should be treated as a type that is not an instance of
# > the class being constructed.
class Class4:
def __new__(cls) -> "Class4 | Any":
return 0
def __init__(self, x: int):
pass
assert_type(Class4(), Class4 | Any)
class Class5:
def __new__(cls) -> NoReturn:
raise NotImplementedError
def __init__(self, x: int):
pass
try:
assert_type(Class5(), NoReturn)
except:
pass
class Class6:
def __new__(cls) -> "int | Class6":
return 0
def __init__(self, x: int):
pass
assert_type(Class6(), int | Class6)
# > If the return type of __new__ is not annotated, a type checker may assume
# > that the return type is Self and proceed with the assumption that the
# > __init__ method will be called.
class Class7:
def __new__(cls, *args, **kwargs):
return super().__new__(cls, *args, **kwargs)
def __init__(self, x: int):
pass
assert_type(Class7(1), Class7)
# > If the class is generic, it is possible for a __new__ method to override
# > the specialized class type and return a class instance that is specialized
# > with different type arguments.
class Class8(Generic[T]):
def __new__(cls, *args, **kwargs) -> "Class8[list[T]]":
raise NotImplementedError
assert_type(Class8[int](), Class8[list[int]])
assert_type(Class8[str](), Class8[list[str]])
# > If the cls parameter within the __new__ method is not annotated,
# > type checkers should infer a type of type[Self].
class Class9(Generic[T]):
def __new__(cls, *args, **kwargs) -> Self:
raise NotImplementedError
class Class10(Class9[int]):
pass
c10: Class9[int] = Class10()
# > Regardless of whether the type of the cls parameter is explicit or
# > inferred, the type checker should bind the class being constructed to
# > the cls parameter and report any type errors that arise during binding.
class Class11(Generic[T]):
def __new__(cls: "type[Class11[int]]") -> "Class11[int]":
raise NotImplementedError
Class11() # OK
Class11[int]() # OK
Class11[str]() # E