A decorator to automatically detect mismatch when overriding a method.
Project description
A decorator that verifies that a method that should override an inherited method actually does, and that copies the docstring of the inherited method to the overridden method. Since signature validation and docstring inheritance are performed on class creation and not on class instantiation, this library significantly improves the safety and experience of creating class hierarchies in Python without significantly impacting performance. See https://stackoverflow.com/q/1167617 for the initial inspiration for this library.
Motivation
Python has no standard mechanism by which to guarantee that (1) a method that previously overrode an inherited method continues to do so, and (2) a method that previously did not override an inherited will not override now. This opens the door for subtle problems as class hierarchies evolve over time. For example,
A method that is added to a superclass is shadowed by an existing method with the same name in a subclass.
A method of a superclass that is overridden by a subclass is renamed in the superclass but not in the subclass.
A method of a superclass that is overridden by a subclass is removed in the superclass but not in the subclass.
A method of a superclass that is overridden by a subclass but the signature of the overridden method is incompatible with that of the inherited one.
These can be only checked by explicitly marking method override in the code.
Python also has no standard mechanism by which to inherit docstrings in overridden methods. Because most standard linters (e.g., flake8) have rules that require all public methods to have a docstring, this inevitably leads to a proliferation of See parent class for usage docstrings on overridden methods, or, worse, to a disabling of these rules altogether. In addition, mediocre or missing docstrings degrade the quality of tooltips and completions that can be provided by an editor.
Installation
Compatible with Python 3.6+.
$ pip install overrides
Usage
Use @overrides to indicate that a subclass method should override a superclass method.
from overrides import overrides
class SuperClass:
def foo(self):
"""This docstring will be inherited by any method that overrides this!"""
return 1
def bar(self, x) -> str:
return x
class SubClass(SuperClass):
@overrides
def foo(self):
return 2
@overrides
def bar(self, y) -> int: # Raises, because the signature is not compatible.
return y
Use EnforceOverrides to require subclass methods that shadow superclass methods to be decorated with @overrides.
from overrides import EnforceOverrides
class SuperClass(EnforceOverrides):
def foo(self):
return 1
class SubClass(SuperClass):
def foo(self): # Raises, because @overrides is missing.
return 2
Use @final to indicate that a superclass method cannot be overriden.
from overrides import EnforceOverrides, final
class SuperClass(EnforceOverrides):
@final
def foo(self):
return 1
class SubClass(SuperClass):
@overrides
def foo(self): # Raises, because overriding a final method is forbidden.
return 2
Note that @classmethod and @staticmethod must be declared before @overrides.
from overrides import overrides
class SuperClass:
@staticmethod
def foo(x):
return 1
class SubClass(SuperClass):
@staticmethod
@overrides
def foo(x):
return 2
Flags of control
# To prevent all signature checks do:
@overrides(check_signature=False)
def some_method(self, now_this_can_be_funny_and_wrong: str, what_ever: int) -> "Dictirux":
pass
# To do the check only at runtime and solve forward references
@overrides(check_at_runtime=True)
def some_other_method(self, ..) -> "SomethingDefinedLater":
pass
a.some_other_method() # Kaboom if not SomethingDefinedLater
Contributors
This project exists only through the work of all the people who contribute.
mkorpela, drorasaf, ngoodman90, TylerYep, leeopop, donpatrice, jayvdb, joelgrus, lisyarus, soulmerge, rkr-at-dbx, ashwin153, brentyi
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for overrides-6.3.0-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | e39f57a90c37b03bb88dd58ca9706449af9ceb9dc6c7b56fee647f3df4f32364 |
|
MD5 | ae4430c9eb8748971e20a1c9c436945b |
|
BLAKE2b-256 | 7b2aff0970bece4f8f7b8a4905358555e83c0d7b6f5233e6d81192236f857218 |