← Back to index
constructors_call_new.py
True Positive
False Positive
False Negative
Optional (detected)
Warning or Info
TP: 2
FP: 0
FN: 0
Optional: 0 / 0
1
"""
2
Tests
the
evaluation
of
calls
to
constructors
when
there
is
a
__new__
3
method
defined
.
4
"""
5
6
# Specification: https://typing.readthedocs.io/en/latest/spec/constructors.html#new-method
7
8
9
from
typing
import
Any
,
Generic
,
NoReturn
,
Self
,
TypeVar
,
assert_type
10
11
T
=
TypeVar
(
"T"
)
12
13
14
class
Class1
(
Generic
[
T
]):
15
def
__new__
(
cls
,
x
:
T
)
->
Self
:
16
return
super
()
.
__new__
(
cls
)
17
18
19
assert_type
(
Class1
[
int
](
1
),
Class1
[
int
])
20
assert_type
(
Class1
[
float
](
1
),
Class1
[
float
])
21
Class1
[
int
](
1.0
)
# E
[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `int`, found `float`
22
23
assert_type
(
Class1
(
1
),
Class1
[
int
])
24
assert_type
(
Class1
(
1.0
),
Class1
[
float
])
25
26
27
class
Class2
(
Generic
[
T
]):
28
def
__new__
(
cls
,
*
args
,
**
kwargs
)
->
Self
:
29
return
super
()
.
__new__
(
cls
)
30
31
def
__init__
(
self
,
x
:
T
)
->
None
:
32
pass
33
34
35
assert_type
(
Class2
(
1
),
Class2
[
int
])
36
assert_type
(
Class2
(
""
),
Class2
[
str
])
37
38
39
class
Class3
:
40
def
__new__
(
cls
)
->
int
:
41
return
0
42
43
# In this case, the __init__ method should not be considered
44
# by the type checker when evaluating a constructor call.
45
def
__init__
(
self
,
x
:
int
):
46
pass
47
48
49
assert_type
(
Class3
(),
int
)
50
51
# > For purposes of this test, an explicit return type of Any (or a union
52
# > containing Any) should be treated as a type that is not an instance of
53
# > the class being constructed.
54
55
56
class
Class4
:
57
def
__new__
(
cls
)
->
"Class4 | Any"
:
58
return
0
59
60
def
__init__
(
self
,
x
:
int
):
61
pass
62
63
64
assert_type
(
Class4
(),
Class4
|
Any
)
65
66
67
class
Class5
:
68
def
__new__
(
cls
)
->
NoReturn
:
69
raise
NotImplementedError
70
71
def
__init__
(
self
,
x
:
int
):
72
pass
73
74
75
try
:
76
assert_type
(
Class5
(),
NoReturn
)
77
except
:
78
pass
79
80
81
class
Class6
:
82
def
__new__
(
cls
)
->
"int | Class6"
:
83
return
0
84
85
def
__init__
(
self
,
x
:
int
):
86
pass
87
88
89
assert_type
(
Class6
(),
int
|
Class6
)
90
91
# > If the return type of __new__ is not annotated, a type checker may assume
92
# > that the return type is Self and proceed with the assumption that the
93
# > __init__ method will be called.
94
95
96
class
Class7
:
97
def
__new__
(
cls
,
*
args
,
**
kwargs
):
98
return
super
()
.
__new__
(
cls
,
*
args
,
**
kwargs
)
99
100
def
__init__
(
self
,
x
:
int
):
101
pass
102
103
104
assert_type
(
Class7
(
1
),
Class7
)
105
106
107
# > If the class is generic, it is possible for a __new__ method to override
108
# > the specialized class type and return a class instance that is specialized
109
# > with different type arguments.
110
111
112
class
Class8
(
Generic
[
T
]):
113
def
__new__
(
cls
,
*
args
,
**
kwargs
)
->
"Class8[list[T]]"
:
114
raise
NotImplementedError
115
116
117
assert_type
(
Class8
[
int
](),
Class8
[
list
[
int
]])
118
assert_type
(
Class8
[
str
](),
Class8
[
list
[
str
]])
119
120
121
# > If the cls parameter within the __new__ method is not annotated,
122
# > type checkers should infer a type of type[Self].
123
124
125
class
Class9
(
Generic
[
T
]):
126
def
__new__
(
cls
,
*
args
,
**
kwargs
)
->
Self
:
127
raise
NotImplementedError
128
129
130
class
Class10
(
Class9
[
int
]):
131
pass
132
133
134
c10
:
Class9
[
int
]
=
Class10
()
135
136
# > Regardless of whether the type of the cls parameter is explicit or
137
# > inferred, the type checker should bind the class being constructed to
138
# > the cls parameter and report any type errors that arise during binding.
139
140
141
class
Class11
(
Generic
[
T
]):
142
def
__new__
(
cls
:
"type[Class11[int]]"
)
->
"Class11[int]"
:
143
raise
NotImplementedError
144
145
146
Class11
()
# OK
147
Class11
[
int
]()
# OK
148
Class11
[
str
]()
# E
[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `type[Class11[int]]`, found `<class 'Class11[str]'>`