Skip to content

Commit 6e72c09

Browse files
authored
Add __override__ attribute to @OverRide (PEP 698) (#86)
Add `__override__` attribute to @OverRide As per discussion in https://mail.python.org/archives/list/[email protected]/thread/TOIYZ3SNPBJZDBRU3ZSBREXV2NNHF4KW/, we believe this is a good feature to have (as best-effort: it will not work in all cases if the user does not understand decorator implementations enough to get the right order, and it will alwasys fail if a decorator output does not support dynamic attributes). We decided to support this for two reasons: - it was a direct request from the `overrides` library owner - `typing_extensions.final` has similar behavior Tests: ``` cd src python -m unittest test_typing_extensions.py ``` Lints: ``` flake8 flake8 --config=.flake8-tests src/test_typing_extensions.py ```
1 parent 3a54ef1 commit 6e72c09

File tree

2 files changed

+37
-4
lines changed

2 files changed

+37
-4
lines changed

src/test_typing_extensions.py

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,16 +164,38 @@ def test_exception(self):
164164
class OverrideTests(BaseTestCase):
165165
def test_override(self):
166166
class Base:
167-
def foo(self): ...
167+
def normal_method(self): ...
168+
@staticmethod
169+
def static_method_good_order(): ...
170+
@staticmethod
171+
def static_method_bad_order(): ...
172+
@staticmethod
173+
def decorator_with_slots(): ...
168174

169175
class Derived(Base):
170176
@override
171-
def foo(self):
177+
def normal_method(self):
178+
return 42
179+
180+
@staticmethod
181+
@override
182+
def static_method_good_order():
183+
return 42
184+
185+
@override
186+
@staticmethod
187+
def static_method_bad_order():
172188
return 42
173189

190+
174191
self.assertIsSubclass(Derived, Base)
175-
self.assertEqual(Derived().foo(), 42)
176-
self.assertEqual(dir(Base.foo), dir(Derived.foo))
192+
instance = Derived()
193+
self.assertEqual(instance.normal_method(), 42)
194+
self.assertIs(True, instance.normal_method.__override__)
195+
self.assertEqual(Derived.static_method_good_order(), 42)
196+
self.assertIs(True, Derived.static_method_good_order.__override__)
197+
self.assertEqual(Derived.static_method_bad_order(), 42)
198+
self.assertIs(False, hasattr(Derived.static_method_bad_order, "__override__"))
177199

178200

179201
class AnyTests(BaseTestCase):

src/typing_extensions.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2102,9 +2102,20 @@ def method(self) -> None:
21022102
This helps prevent bugs that may occur when a base class is changed
21032103
without an equivalent change to a child class.
21042104
2105+
There is no runtime checking of these properties. The decorator
2106+
sets the ``__override__`` attribute to ``True`` on the decorated object
2107+
to allow runtime introspection.
2108+
21052109
See PEP 698 for details.
21062110
21072111
"""
2112+
try:
2113+
__arg.__override__ = True
2114+
except (AttributeError, TypeError):
2115+
# Skip the attribute silently if it is not writable.
2116+
# AttributeError happens if the object has __slots__ or a
2117+
# read-only property, TypeError if it's a builtin class.
2118+
pass
21082119
return __arg
21092120

21102121

0 commit comments

Comments
 (0)