-
Notifications
You must be signed in to change notification settings - Fork 303
Expand file tree
/
Copy pathclasses_override.py
More file actions
150 lines (103 loc) · 3.79 KB
/
Copy pathclasses_override.py
File metadata and controls
150 lines (103 loc) · 3.79 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
149
150
"""
Tests the typing.override decorator.
"""
# Specification: https://typing.readthedocs.io/en/latest/spec/class-compat.html#override
from typing import Any, Callable, overload, override
def wrapper(func: Callable[..., Any], /) -> Any:
def wrapped(*args: Any, **kwargs: Any) -> Any:
raise NotImplementedError
return wrapped
class ParentA:
def method1(self) -> int:
return 1
@overload
def method2(self, x: int) -> int:
...
@overload
def method2(self, x: str) -> str:
...
def method2(self, x: int | str) -> int | str:
return 0
def method5(self):
pass
class ChildA(ParentA):
@override
def method1(self) -> int: # OK
return 2
@overload
def method2(self, x: int) -> int:
...
@overload
def method2(self, x: str) -> str:
...
def method2(self, x: int | str) -> int | str: # OK
return 0
@override # E[method3]
def method3(self) -> int: # E[method3]: no matching signature in ancestor
return 1
@overload # E[method4]
def method4(self, x: int) -> int: # E[method4]
...
@overload
def method4(self, x: str) -> str:
...
@override # E[method4]
def method4(self, x: int | str) -> int | str: # E[method4]: no matching signature in ancestor
return 0
@override
@wrapper
def method5(self): # OK
pass
# > The @override decorator should be permitted anywhere a type checker
# > considers a method to be a valid override, which typically includes not
# > only normal methods but also @property, @staticmethod, and @classmethod.
@staticmethod
@override # E[static_method1]
def static_method1() -> int: # E[static_method1]: no matching signature in ancestor
return 1
@classmethod
@override # E[class_method1]
def class_method1(cls) -> int: # E[class_method1]: no matching signature in ancestor
return 1
@property
@override # E[property1]
def property1(self) -> int: # E[property1]: no matching signature in ancestor
return 1
# Test the case where the parent derives from Any
class ParentB(Any):
pass
class ChildB(ParentB):
@override
def method1(self) -> None: # OK
pass
# > When type checkers encounter a method decorated with @typing.override they
# > should treat it as a type error unless that method is overriding a method or
# > attribute in some ancestor class, and the type of the overriding method is
# > assignable to the type of the overridden method.
# ``__init__`` and ``__new__`` are normally exempt from override compatibility
# checks, since constructors are not subject to the Liskov substitution
# principle. However, when they are explicitly decorated with ``@override`` the
# decorator's assignability check should still be honored.
# See https://github.com/python/typing/issues/2222
class ParentC:
def __init__(self, x: int) -> None: ...
def __new__(cls, x: int) -> "ParentC":
raise NotImplementedError
class ChildC1(ParentC):
@override
def __init__(self, x: int) -> None: ... # OK
@override
def __new__(cls, x: int) -> "ChildC1": # OK
raise NotImplementedError
class ChildC2(ParentC):
@override # E[init]
def __init__(self, x: str) -> None: ... # E[init]: not assignable to "ParentC.__init__"
@override # E[new]
def __new__(cls, x: str) -> "ChildC2": # E[new]: not assignable to "ParentC.__new__"
raise NotImplementedError
# Without ``@override`` an incompatible constructor signature is allowed, since
# ``__init__`` and ``__new__`` are exempt from the usual override checks.
class ChildC3(ParentC):
def __init__(self, x: str) -> None: ... # OK
def __new__(cls, x: str) -> "ChildC3": # OK
raise NotImplementedError