Skip to content

Commit 3c21f33

Browse files
JelleZijlstrastroxlerAlexWaygood
authored
Add @typing.override (#78)
Co-authored-by: Steven Troxler <[email protected]> Co-authored-by: Alex Waygood <[email protected]>
1 parent ba776ea commit 3c21f33

File tree

3 files changed

+49
-0
lines changed

3 files changed

+49
-0
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
and Jelle Zijlstra). Patch by James Hilton-Balfe (@Gobot1234).
66
- Add initial support for TypeVarLike `default` parameter, PEP 696.
77
Patch by Marc Mueller (@cdce8p).
8+
- Runtime support for PEP 698, adding `typing_extensions.override`. Patch by
9+
Jelle Zijlstra.
810
- Add the `infer_variance` parameter to `TypeVar`, as specified in PEP 695.
911
Patch by Jelle Zijlstra.
1012

src/test_typing_extensions.py

+16
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
from typing_extensions import assert_type, get_type_hints, get_origin, get_args
3030
from typing_extensions import clear_overloads, get_overloads, overload
3131
from typing_extensions import NamedTuple
32+
from typing_extensions import override
3233
from _typed_dict_test_helper import FooGeneric
3334

3435
# Flags used to mark tests that only apply after a specific
@@ -160,6 +161,21 @@ def test_exception(self):
160161
assert_never(None)
161162

162163

164+
class OverrideTests(BaseTestCase):
165+
def test_override(self):
166+
class Base:
167+
def foo(self): ...
168+
169+
class Derived(Base):
170+
@override
171+
def foo(self):
172+
return 42
173+
174+
self.assertIsSubclass(Derived, Base)
175+
self.assertEqual(Derived().foo(), 42)
176+
self.assertEqual(dir(Base.foo), dir(Derived.foo))
177+
178+
163179
class AnyTests(BaseTestCase):
164180
def test_can_subclass(self):
165181
class Mock(Any): pass

src/typing_extensions.py

+31
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
'Literal',
6363
'NewType',
6464
'overload',
65+
'override',
6566
'Protocol',
6667
'reveal_type',
6768
'runtime',
@@ -2078,6 +2079,36 @@ def decorator(cls_or_fn):
20782079
return decorator
20792080

20802081

2082+
if hasattr(typing, "override"):
2083+
override = typing.override
2084+
else:
2085+
_F = typing.TypeVar("_F", bound=typing.Callable[..., typing.Any])
2086+
2087+
def override(__arg: _F) -> _F:
2088+
"""Indicate that a method is intended to override a method in a base class.
2089+
2090+
Usage:
2091+
2092+
class Base:
2093+
def method(self) -> None: ...
2094+
pass
2095+
2096+
class Child(Base):
2097+
@override
2098+
def method(self) -> None:
2099+
super().method()
2100+
2101+
When this decorator is applied to a method, the type checker will
2102+
validate that it overrides a method with the same name on a base class.
2103+
This helps prevent bugs that may occur when a base class is changed
2104+
without an equivalent change to a child class.
2105+
2106+
See PEP 698 for details.
2107+
2108+
"""
2109+
return __arg
2110+
2111+
20812112
# We have to do some monkey patching to deal with the dual nature of
20822113
# Unpack/TypeVarTuple:
20832114
# - We want Unpack to be a kind of TypeVar so it gets accepted in

0 commit comments

Comments
 (0)