Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions Doc/library/typing.rst
Original file line numberDiff line numberDiff line change
Expand Up@@ -91,6 +91,8 @@ annotations. These include:
*Introducing* :data:`LiteralString`
* :pep:`681`: Data Class Transforms
*Introducing* the :func:`@dataclass_transform<dataclass_transform>` decorator
* :pep:`698`: Adding an override decorator to typing
*Introducing* the :func:`@override<override>` decorator

.. _type-aliases:

Expand DownExpand Up@@ -2722,6 +2724,42 @@ Functions and decorators
This wraps the decorator with something that wraps the decorated
function in :func:`no_type_check`.


.. decorator:: override

A decorator for methods that indicates to type checkers that this method
should override a method or attribute with the same name on a base class.
This helps prevent bugs that may occur when a base class is changed without
an equivalent change to a child class.

For example::

class Base:
def log_status(self)

class Sub(Base):
@override
def log_status(self) -> None: # Okay: overrides Base.log_status
...

@override
def done(self) -> None: # Error reported by type checker
...

There is no runtime checking of this property.

The decorator will set the ``__override__`` attribute to ``True`` on
the decorated object. Thus, a check like
``if getattr(obj, "__override__", False)`` can be used at runtime to determine
whether an object ``obj`` has been marked as an override. If the decorated object
does not support setting attributes, the decorator returns the object unchanged
without raising an exception.

See :pep:`698` for more details.

.. versionadded:: 3.12


.. decorator:: type_check_only

Decorator to mark a class or function to be unavailable at runtime.
Expand Down
8 changes: 8 additions & 0 deletions Doc/whatsnew/3.12.rst
Original file line numberDiff line numberDiff line change
Expand Up@@ -350,6 +350,14 @@ tempfile
The :class:`tempfile.NamedTemporaryFile` function has a new optional parameter
*delete_on_close* (Contributed by Evgeny Zorin in :gh:`58451`.)

typing
------

* Add :func:`typing.override`, an override decorator telling to static type
checkers to verify that a method overrides some method or attribute of the
same name on a base class, as per :pep:`698`. (Contributed by Steven Troxler in
:gh:`101564`.)

sys
---

Expand Down
38 changes: 38 additions & 0 deletions Lib/test/test_typing.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,6 +23,7 @@
from typing import assert_type, cast, runtime_checkable
from typing import get_type_hints
from typing import get_origin, get_args
from typing import override
from typing import is_typeddict
from typing import reveal_type
from typing import dataclass_transform
Expand DownExpand Up@@ -4166,6 +4167,43 @@ def cached(self): ...
self.assertIs(True, Methods.cached.__final__)


class OverrideDecoratorTests(BaseTestCase):
def test_override(self):
class Base:
def normal_method(self): ...
@staticmethod
def static_method_good_order(): ...
@staticmethod
def static_method_bad_order(): ...
@staticmethod
def decorator_with_slots(): ...

class Derived(Base):
@override
def normal_method(self):
return 42

@staticmethod
@override
def static_method_good_order():
return 42

@override
@staticmethod
def static_method_bad_order():
return 42


self.assertIsSubclass(Derived, Base)
instance = Derived()
self.assertEqual(instance.normal_method(), 42)
self.assertIs(True, instance.normal_method.__override__)
self.assertEqual(Derived.static_method_good_order(), 42)
self.assertIs(True, Derived.static_method_good_order.__override__)
self.assertEqual(Derived.static_method_bad_order(), 42)
self.assertIs(False, hasattr(Derived.static_method_bad_order, "__override__"))


class CastTests(BaseTestCase):

def test_basics(self):
Expand Down
41 changes: 41 additions & 0 deletions Lib/typing.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -138,6 +138,7 @@ def _idfunc(_, x):
'NoReturn',
'NotRequired',
'overload',
'override',
'ParamSpecArgs',
'ParamSpecKwargs',
'Required',
Expand DownExpand Up@@ -2657,6 +2658,7 @@ class Other(Leaf): # Error reported by type checker
# Internal type variable used for Type[].
CT_co = TypeVar('CT_co', covariant=True, bound=type)


# A useful type variable with constraints. This represents string types.
# (This one *is* for export!)
AnyStr = TypeVar('AnyStr', bytes, str)
Expand DownExpand Up@@ -2748,6 +2750,8 @@ def new_user(user_class: Type[U]) -> U:
At this point the type checker knows that joe has type BasicUser.
"""

# Internal type variable for callables. Not for export.
F = TypeVar("F", bound=Callable[..., Any])

@runtime_checkable
class SupportsInt(Protocol):
Expand DownExpand Up@@ -3448,3 +3452,40 @@ def decorator(cls_or_fn):
}
return cls_or_fn
return decorator



def override(method: F, /) -> F:
"""Indicate that a method is intended to override a method in a base class.

Usage:

class Base:
def method(self) -> None: ...
pass

class Child(Base):
@override
def method(self) -> None:
super().method()

When this decorator is applied to a method, the type checker will
validate that it overrides a method or attribute with the same name on a
base class. This helps prevent bugs that may occur when a base class is
changed without an equivalent change to a child class.

There is no runtime checking of this property. The decorator sets the
``__override__`` attribute to ``True`` on the decorated object to allow
runtime introspection.

See PEP 698 for details.

"""
try:
method.__override__ = True
except (AttributeError, TypeError):
# Skip the attribute silently if it is not writable.
# AttributeError happens if the object has __slots__ or a
# read-only property, TypeError if it's a builtin class.
pass
return method
1 change: 1 addition & 0 deletions Misc/ACKS
Original file line numberDiff line numberDiff line change
Expand Up@@ -1848,6 +1848,7 @@ Tom Tromey
John Tromp
Diane Trout
Jason Trowbridge
Steven Troxler
Brent Tubbs
Anthony Tuininga
Erno Tukia
Expand Down
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
Add a new decorator :func:`typing.override`. See :pep:`698` for details. Patch by Steven Troxler.