← Back to index

qualifiers_final_decorator.py

True Positive
False Positive
False Negative
Optional (detected)
Warning or Info
TP: 9
FP: 0
FN: 2
Optional: 0 / 0
1"""
2Tests the @final decorator.
3"""
4
5# Specification: https://typing.readthedocs.io/en/latest/spec/qualifiers.html#final
6
7from typing import final, overload
8from _qualifiers_final_decorator import Base3, Base4
9
10# > A type checker should prohibit any class decorated with @final from being
11# > subclassed and any method decorated with @final from being overridden in a
12# > subclass. The method decorator version may be used with all of instance
13# > methods, class methods, static methods, and properties.
16@final
17class Base1:
18 ...
21class Derived1(Base1): # E: Cannot inherit from final class "Base"
[subclass-of-final-class] Class `Derived1` cannot inherit from final class `Base1`
22 ...
25class Base2:
26 @final
27 def method1(self) -> None:
28 pass
30 @final
31 @classmethod
32 def method2(cls) -> None:
33 pass
35 @final
36 @staticmethod
37 def method3() -> None:
38 pass
40 # > For overloaded methods, @final should be placed on the implementation.
42 @overload
43 def method4(self, x: int) -> int:
44 ...
46 @overload
47 def method4(self, x: str) -> str:
48 ...
50 @final
51 def method4(self, x: int | str) -> int | str:
52 return 0
55class Derived2(Base2):
56 def method1(self) -> None: # E
[override-of-final-method] Cannot override final member `method1` from superclass `Base2`
57 pass
59 @classmethod # E[method2]
60 def method2(cls) -> None: # E[method2]
Tag 'method2' [override-of-final-method] Cannot override final member `method2` from superclass `Base2`
61 pass
63 @staticmethod # E[method3]
64 def method3() -> None: # E[method3]
Tag 'method3' [override-of-final-method] Cannot override final member `method3` from superclass `Base2`
65 pass
67 @overload # E[method4]
68 def method4(self, x: int) -> int: # E[method4]
69 ...
71 @overload
72 def method4(self, x: str) -> str:
73 ...
75 def method4(self, x: int | str) -> int | str: # E[method4]
Tag 'method4' [override-of-final-method] Cannot override final member `method4` from superclass `Base2`
76 return 0
79class Derived3(Base3):
80 @overload # E[Derived3]
81 def method(self, x: int) -> int: # E[Derived3]
82 ...
84 @overload # E[Derived3-2]
85 @final # E[Derived3-2]: should be applied only to implementation
86 def method(self, x: str) -> str: # E[Derived3-2]
Tag 'Derived3-2' [invalid-overload] `@final` decorator should be applied only to the overload implementation
87 ...
89 def method(self, x: int | str) -> int | str: # E[Derived3]
Tag 'Derived3' [override-of-final-method] Cannot override final member `method` from superclass `Base3`
90 return 0
93class Derived4(Base4):
94 @overload # E[Derived4]
95 def method(self, x: int) -> int: # E[Derived4]
96 ...
98 @overload
99 def method(self, x: str) -> str:
100 ...
102 def method(self, x: int | str) -> int | str: # E[Derived4]
Tag 'Derived4' [override-of-final-method] Cannot override final member `method` from superclass `Base4`
103 return 0
106class Base5_1:
107 ...
110class Base5_2:
111 @final
112 def method(self, v: int) -> None:
113 ...
116# Test multiple inheritance case.
117class Derived5(Base5_1, Base5_2):
118 def method(self) -> None: # E
[invalid-method-override] Invalid override of method `method`: Definition is incompatible with `Base5_2.method` [override-of-final-method] Cannot override final member `method` from superclass `Base5_2`
119 ...
122# > It is an error to use @final on a non-method function.
125@final # E[func]: not allowed on non-method function.
Expected a ty diagnostic for this line (tag 'func')
126def func1() -> int: # E[func]
Expected a ty diagnostic for this line (tag 'func')
127 return 0