← Back to index

overloads_definitions_stub.pyi

True Positive
False Positive
False Negative
Optional (detected)
Warning or Info
TP: 8
FP: 0
FN: 0
Optional: 0 / 0
1"""
2Tests valid/invalid definition of overloaded functions in stub files, where the
3rules differ from non-stubs, since an implementation is not required.
4"""
5
6from typing import (
7 final,
8 overload,
9 override,
10)
12# > At least two @overload-decorated definitions must be present.
13@overload # E[func1]
14def func1() -> None: # E[func1]: At least two overloads must be present
Tag 'func1' [invalid-overload] Overloaded function `func1` requires at least two overloads: Only one overload defined here
15 ...
17# > The ``@overload``-decorated definitions must be followed by an overload
18# > implementation, which does not include an ``@overload`` decorator. Type
19# > checkers should report an error or warning if an implementation is missing.
20# > Overload definitions within stub files, protocols, and on abstract methods
21# > within abstract base classes are exempt from this check.
22@overload
23def func2(x: int) -> int: ...
24@overload
25def func2(x: str) -> str: ...
27# > If one overload signature is decorated with ``@staticmethod`` or
28# > ``@classmethod``, all overload signatures must be similarly decorated. The
29# > implementation, if present, must also have a consistent decorator. Type
30# > checkers should report an error if these conditions are not met.
31class C:
32 @overload # E[func5]
33 def func5(self, x: int, /) -> int: # E[func5]
34 ...
35 @overload
36 @staticmethod
37 def func5(x: str, /) -> str: # E[func5]
Tag 'func5' [invalid-overload] Overloaded function `func5` does not use the `@staticmethod` decorator consistently
38 ...
39 @overload # E[func6]
40 @classmethod
41 def func6(cls, x: int, /) -> int: # E[func6]
42 ...
43 @overload
44 def func6(self, *args: str) -> str: # E[func6]
Tag 'func6' [invalid-overload] Overloaded function `func6` does not use the `@classmethod` decorator consistently
45 ...
47# > If a ``@final`` or ``@override`` decorator is supplied for a function with
48# > overloads, the decorator should be applied only to the overload
49# > implementation if it is present. If an overload implementation isn't present
50# > (for example, in a stub file), the ``@final`` or ``@override`` decorator
51# > should be applied only to the first overload. Type checkers should enforce
52# > these rules and generate an error when they are violated. If a ``@final`` or
53# > ``@override`` decorator follows these rules, a type checker should treat the
54# > decorator as if it is present on all overloads.
55class Base:
56 # This is a good definition of an overloaded final method in a stub (@final
57 # decorator on first overload only):
59 @overload
60 @final
61 def final_method(self, x: int) -> int: ...
62 @overload
63 def final_method(self, x: str) -> str: ...
65 # The @final decorator should not be on multiple overloads:
67 @overload # E[invalid_final] @final should be on first overload
68 @final
69 def invalid_final(self, x: int) -> int: # E[invalid_final]
70 ...
71 @overload # E[invalid_final]
72 @final # E[invalid_final]
73 def invalid_final(self, x: str) -> str: # E[invalid_final]
Tag 'invalid_final' [invalid-overload] `@final` decorator should be applied only to the first overload
74 ...
75 @overload
76 def invalid_final(self, x: bytes) -> bytes: ...
78 # The @final decorator should not be on all overloads:
80 @overload # E[invalid_final_2] @final should be on first overload
81 @final
82 def invalid_final_2(self, x: int) -> int: # E[invalid_final_2]
83 ...
84 @overload # E[invalid_final_2]
85 @final # E[invalid_final_2]
86 def invalid_final_2(self, x: str) -> str: ... # E[invalid_final_2]
Tag 'invalid_final_2' [invalid-overload] `@final` decorator should be applied only to the first overload
88 # These methods are just here for the @override test below. We use an
89 # overload because mypy doesn't like overriding a non-overloaded method
90 # with an overloaded one, even if LSP isn't violated. That could be its own
91 # specification question, but it's not what we're trying to test here:
93 @overload
94 def good_override(self, x: int) -> int: ...
95 @overload
96 def good_override(self, x: str) -> str: ...
97 @overload
98 def to_override(self, x: int) -> int: ...
99 @overload
100 def to_override(self, x: str) -> str: ...
102class Child(Base): # E[override-final]
103 # The correctly-decorated @final method `Base.final_method` should cause an
104 # error if overridden in a child class (we use an overload here to avoid
105 # questions of override LSP compatibility and focus only on the override):
107 @overload # E[override-final]
108 def final_method(self, x: int) -> int: # E[override-final]
109 ...
110 @overload
111 def final_method( # E[override-final] can't override final method
Tag 'override-final' [override-of-final-method] Cannot override final member `final_method` from superclass `Base`
112 self, x: str
113 ) -> str: # E[override-final] can't override final method
114 ...
116 # This is the right way to mark an overload as @override (decorate first
117 # overload only), so the use of @override should cause an error (because
118 # there's no `Base.bad_override` method):
120 @overload # E[bad_override] marked as override but doesn't exist in base
121 @override # E[bad_override]
122 def bad_override(self, x: int) -> int: # E[bad_override]
Tag 'bad_override' [invalid-explicit-override] Method `bad_override` is decorated with `@override` but does not override anything
123 ...
124 @overload
125 def bad_override(self, x: str) -> str: ...
127 # This is also a correctly-decorated overloaded @override, which is
128 # overriding a method that does exist in the base, so there should be no
129 # error. We need both this test and the previous one, because in the
130 # previous test, an incorrect error about the use of @override decorator
131 # could appear on the same line as the expected error about overriding a
132 # method that doesn't exist in base:
134 @overload
135 @override
136 def good_override(self, x: int) -> int: ...
137 @overload
138 def good_override(self, x: str) -> str: ...
140 # This is the wrong way to use @override with an overloaded method, and
141 # should emit an error:
143 @overload # E[override_impl]: @override should appear only on first overload
144 def to_override(self, x: int) -> int: ...
145 @overload
146 @override # E[override_impl]: @override should appear only on first overload
147 def to_override( # E[override_impl]: @override should appear only on first overload
Tag 'override_impl' [invalid-overload] `@override` decorator should be applied only to the first overload
148 self, x: str
149 ) -> str: # E[override_impl]: @override should appear only on first overload
150 ...