← Back to index

constructors_call_init.py

True Positive
False Positive
False Negative
Optional (detected)
Warning or Info
TP: 3
FP: 2
FN: 2
Optional: 0 / 0
1"""
2Tests the evaluation of calls to constructors when there is a __init__
3method defined.
4"""
5
6# Specification: https://typing.readthedocs.io/en/latest/spec/constructors.html#init-method
7
8from typing import Any, Generic, Self, TypeVar, assert_type, overload
9
10T = TypeVar("T")
13class Class1(Generic[T]):
14 def __init__(self, x: T) -> None:
15 pass
18# Constructor calls for specialized classes
19assert_type(Class1[int](1), Class1[int])
20assert_type(Class1[float](1), Class1[float])
21Class1[int](1.0) # E
[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `int`, found `float`
23# Constructor calls for non-specialized classes
24assert_type(Class1(1), Class1[int])
25assert_type(Class1(1.0), Class1[float])
28# > If the self parameter within the __init__ method is not annotated, type
29# > checkers should infer a type of Self.
32class Class2(Generic[T]):
33 def __init__(self, x: Self | None) -> None:
34 pass
37class Class3(Class2[int]):
38 pass
41Class3(Class3(None)) # OK
42Class3(Class2(None)) # E
Expected a ty diagnostic for this line
45# > Regardless of whether the self parameter type is explicit or inferred, a
46# > type checker should bind the class being constructed to this parameter and
47# > report any type errors that arise during binding.
50class Class4(Generic[T]):
51 def __init__(self: "Class4[int]") -> None: ...
54Class4() # OK
55Class4[int]() # OK
56Class4[str]() # E
[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Class4[int]`, found `Class4[str]`
59class Class5(Generic[T]):
60 @overload
61 def __init__(self: "Class5[list[int]]", value: int) -> None: ...
62 @overload
63 def __init__(self: "Class5[set[str]]", value: str) -> None: ...
64 @overload
65 def __init__(self, value: T) -> None:
66 pass
68 def __init__(self, value: Any) -> None:
69 pass
72assert_type(Class5(0), Class5[list[int]])
73assert_type(Class5[int](3), Class5[int])
74assert_type(Class5(""), Class5[set[str]])
75assert_type(Class5(3.0), Class5[float])
77# > Function-scoped type variables can also be used in the self annotation
78# > of an __init__ method to influence the return type of the constructor call.
80T1 = TypeVar("T1")
81T2 = TypeVar("T2")
83V1 = TypeVar("V1")
84V2 = TypeVar("V2")
87class Class6(Generic[T1, T2]):
88 def __init__(self: "Class6[V1, V2]", value1: V1, value2: V2) -> None: ...
91assert_type(Class6(0, ""), Class6[int, str])
Unexpected error [type-assertion-failure] Type `Class6[int, str]` does not match asserted type `Class6[Unknown, Unknown]`
92assert_type(Class6[int, str](0, ""), Class6[int, str])
95class Class7(Generic[T1, T2]):
96 def __init__(self: "Class7[V2, V1]", value1: V1, value2: V2) -> None: ...
99assert_type(Class7(0, ""), Class7[str, int])
Unexpected error [type-assertion-failure] Type `Class7[str, int]` does not match asserted type `Class7[Unknown, Unknown]`
100assert_type(Class7[str, int](0, ""), Class7[str, int])
103# > Class-scoped type variables should not be used in the self annotation.
106class Class8(Generic[T1, T2]):
107 def __init__(self: "Class8[T2, T1]") -> None: # E
Expected a ty diagnostic for this line
108 pass
111# > If a class does not define a __new__ method or __init__ method and does
112# > not inherit either of these methods from a base class other than object,
113# > a type checker should evaluate the argument list using the __new__ and
114# > __init__ methods from the object class.
117class Class9:
118 pass
121class Class10:
122 pass
125class Class11(Class9, Class10):
126 pass
129assert_type(Class11(), Class11)
130Class11(1) # E
[too-many-positional-arguments] Too many positional arguments to bound method `__init__`: expected 1, got 2