From e616215f1da927ac66ea2932ea3a4836507b0615 Mon Sep 17 00:00:00 2001 From: Mikko Korpela Date: Sat, 15 Oct 2022 23:16:48 +0300 Subject: [PATCH] Use defacto @override as the wording instead of @overrides --- README.rst | 37 ++++++++++++---------- mypy_fails/wrong_signature.py | 4 +-- mypy_fails/wrong_signature_forward_ref.py | 4 +-- mypy_passes/passing_override.py | 4 +-- overrides/__init__.py | 2 ++ overrides/enforce.py | 2 +- overrides/final.py | 4 +-- overrides/overrides.py | 2 +- tests/test_decorator_params.py | 4 +-- tests/test_enforce__py38.py | 12 +++---- tests/test_final.py | 38 +++++++++++------------ tests/test_named_and_positional__py38.py | 28 ++++++++--------- tests/test_overrides.py | 28 ++++++++--------- tests/test_signatures.py | 20 ++++++------ tests/test_special_cases.py | 8 ++--- 15 files changed, 101 insertions(+), 96 deletions(-) diff --git a/README.rst b/README.rst index 91f9fa7..012bf8e 100644 --- a/README.rst +++ b/README.rst @@ -7,9 +7,12 @@ overrides .. image:: http://pepy.tech/badge/overrides :target: http://pepy.tech/project/overrides -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, +A decorator ``@override`` 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. @@ -53,11 +56,11 @@ Compatible with Python 3.6+. Usage ----- -Use ``@overrides`` to indicate that a subclass method should override a superclass method. +Use ``@override`` to indicate that a subclass method should override a superclass method. .. code-block:: python - from overrides import overrides + from overrides import override class SuperClass: @@ -70,20 +73,20 @@ Use ``@overrides`` to indicate that a subclass method should override a supercla class SubClass(SuperClass): - @overrides + @override def foo(self): return 2 - @overrides + @override def bar(self, y) -> int: # Raises, because the signature is not compatible. return y - @overrides + @override def zoo(self): # Raises, because does not exist in the super class. return "foobarzoo" Use ``EnforceOverrides`` to require subclass methods that shadow superclass methods to be decorated -with ``@overrides``. +with ``@override``. .. code-block:: python @@ -96,14 +99,14 @@ with ``@overrides``. class SubClass(SuperClass): - def foo(self): # Raises, because @overrides is missing. + def foo(self): # Raises, because @override is missing. return 2 Use ``@final`` to indicate that a superclass method cannot be overriden. Note that this is not the same as ``typing.final`` from PEP 591. .. code-block:: python - from overrides import EnforceOverrides, final + from overrides import EnforceOverrides, final, override class SuperClass(EnforceOverrides): @@ -113,15 +116,15 @@ Use ``@final`` to indicate that a superclass method cannot be overriden. Note th class SubClass(SuperClass): - @overrides + @override def foo(self): # Raises, because overriding a final method is forbidden. return 2 -Note that ``@classmethod`` and ``@staticmethod`` must be declared before ``@overrides``. +Note that ``@classmethod`` and ``@staticmethod`` must be declared before ``@override``. .. code-block:: python - from overrides import overrides + from overrides import override class SuperClass: @@ -132,7 +135,7 @@ Note that ``@classmethod`` and ``@staticmethod`` must be declared before ``@over class SubClass(SuperClass): @staticmethod - @overrides + @override def foo(x): return 2 @@ -143,12 +146,12 @@ Flags of control .. code-block:: python # To prevent all signature checks do: - @overrides(check_signature=False) + @override(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 some forward reference problems - @overrides(check_at_runtime=True) + @override(check_at_runtime=True) def some_other_method(self, ..) -> "SomethingDefinedLater": pass diff --git a/mypy_fails/wrong_signature.py b/mypy_fails/wrong_signature.py index ad5a318..2e20f57 100644 --- a/mypy_fails/wrong_signature.py +++ b/mypy_fails/wrong_signature.py @@ -1,4 +1,4 @@ -from overrides import overrides +from overrides import override class Parent: @@ -7,6 +7,6 @@ def metodi(self, x: int) -> str: class Child(Parent): - @overrides + @override def metodi(self, x: str) -> int: return int(x) diff --git a/mypy_fails/wrong_signature_forward_ref.py b/mypy_fails/wrong_signature_forward_ref.py index 2b07e32..fcf45ab 100644 --- a/mypy_fails/wrong_signature_forward_ref.py +++ b/mypy_fails/wrong_signature_forward_ref.py @@ -1,4 +1,4 @@ -from overrides import overrides +from overrides import override class Parent: @@ -7,6 +7,6 @@ def metoda(self) -> None: class Child(Parent): - @overrides + @override def metoda(self) -> "Child": return self diff --git a/mypy_passes/passing_override.py b/mypy_passes/passing_override.py index 8025a75..16120eb 100644 --- a/mypy_passes/passing_override.py +++ b/mypy_passes/passing_override.py @@ -1,6 +1,6 @@ from typing import Tuple -from overrides import overrides +from overrides import override class Parent: @@ -9,6 +9,6 @@ def execute(self, x: int, y: str, z: bool, *args, **kwargs) -> Tuple[str, int]: class Child(Parent): - @overrides + @override def execute(self, *args, **kwargs) -> Tuple[str, int]: return "moi", 1 diff --git a/overrides/__init__.py b/overrides/__init__.py index b2a1197..ed32dfb 100644 --- a/overrides/__init__.py +++ b/overrides/__init__.py @@ -6,9 +6,11 @@ else: from typing import final from overrides.overrides import __VERSION__, overrides +override = overrides __all__ = [ "__VERSION__", + "override", "overrides", "final", "EnforceOverrides", diff --git a/overrides/enforce.py b/overrides/enforce.py index 8901c3d..e3e5dd9 100644 --- a/overrides/enforce.py +++ b/overrides/enforce.py @@ -31,7 +31,7 @@ def _check_if_overrides_without_overrides_decorator(name, value, bases): continue if not is_override: raise TypeError( - f"Method {name} overrides method from {base} but does not have @overrides decorator" + f"Method {name} overrides method from {base} but does not have @override decorator" ) @staticmethod diff --git a/overrides/final.py b/overrides/final.py index 14dde3c..9ab9511 100644 --- a/overrides/final.py +++ b/overrides/final.py @@ -23,7 +23,7 @@ def final(method: _WrappedMethod) -> _WrappedMethod: """Decorator to indicate that the decorated method is finalized and cannot be overridden. The decorator code is executed while loading class. Using this method should have minimal runtime performance implications. - Currently, only methods with @overrides are checked. + Currently, only methods with @override are checked. How to use: from overrides import final @@ -34,7 +34,7 @@ def method(self): return 2 class SubClass(SuperClass): - @overrides + @override def method(self): #causes an error return 1 diff --git a/overrides/overrides.py b/overrides/overrides.py index b0bfea3..4a1e958 100644 --- a/overrides/overrides.py +++ b/overrides/overrides.py @@ -74,7 +74,7 @@ def method(self): class SubClass(SuperClass): - @overrides + @override def method(self): return 1 diff --git a/tests/test_decorator_params.py b/tests/test_decorator_params.py index 279c97f..63554fa 100644 --- a/tests/test_decorator_params.py +++ b/tests/test_decorator_params.py @@ -1,5 +1,5 @@ from typing import Callable, Type -from overrides import overrides +from overrides import override class SuperClass: @@ -24,6 +24,6 @@ def test_my_func() -> None: @my_decorator(my_object.my_name) class SubClass(SuperClass): - @overrides + @override def method(self) -> int: return 1 diff --git a/tests/test_enforce__py38.py b/tests/test_enforce__py38.py index 78fb2c1..c012c59 100644 --- a/tests/test_enforce__py38.py +++ b/tests/test_enforce__py38.py @@ -1,7 +1,7 @@ import unittest from typing import Optional, TypeVar, Union -from overrides import EnforceOverrides, final, overrides +from overrides import EnforceOverrides, final, override from overrides.signature import ensure_signature_is_compatible @@ -40,7 +40,7 @@ def test_enforcing_when_all_ok(self): class Subclazz(Enforcing): classVariableIsOk = "OK!" - @overrides + @override def nonfinal1(self, param: int) -> str: return "2" @@ -74,7 +74,7 @@ def nonfinal2(self): def test_enforcing_when_property_overriden(self): class PropertyOverrider(Enforcing): @property - @overrides + @override def nonfinal_property(self): return "subclass_property" @@ -86,14 +86,14 @@ def test_enforcing_when_incompatible(self): with self.assertRaises(TypeError): class Incompatible(Enforcing): - @overrides + @override def nonfinal1(self, param: str): pass def test_enforcing_when_staticmethod_overriden(self): class StaticMethodOverrider(Enforcing): @staticmethod - @overrides + @override def nonfinal_staticmethod(): return "subclass_staticmethod" @@ -105,7 +105,7 @@ def nonfinal_staticmethod(): def test_enforcing_when_classmethod_overriden(self): class ClassMethodOverrider(Enforcing): @classmethod - @overrides + @override def nonfinal_classmethod(cls): return "subclass_classmethod" diff --git a/tests/test_final.py b/tests/test_final.py index eb76a0f..588f085 100644 --- a/tests/test_final.py +++ b/tests/test_final.py @@ -1,5 +1,5 @@ import unittest -from overrides import overrides, final +from overrides import override, final import test_somefinalpackage @@ -18,7 +18,7 @@ class SomeFinalClass: class SubClass(SuperClass): - @overrides + @override def some_method(self): return "sub" @@ -28,11 +28,11 @@ def another_finalized(self): class Sub2(test_somefinalpackage.SomeClass, SuperClass): - @overrides + @override def somewhat_fun_method(self): return "foo" - @overrides + @override def some_method(self): pass @@ -55,11 +55,11 @@ def test_final_fails_simple(self): try: class SubClassFail(SuperClass): - @overrides + @override def some_method(self): return "subfail" - @overrides + @override def some_finalized_method(self): pass @@ -71,7 +71,7 @@ def test_final_fails_inner_class(self): try: class SubClassFail(SuperClass): - @overrides + @override class SomeFinalClass: pass @@ -83,15 +83,15 @@ def test_final_fails_another_package(self): try: class Sub2Fail(test_somefinalpackage.SomeClass, SuperClass): - @overrides + @override def somewhat_fun_method(self): return "foo" - @overrides + @override def some_method(self): pass - @overrides + @override def some_finalized_method(self): pass @@ -103,15 +103,15 @@ def test_final_fails_deep(self): try: class Sub3Fail(test_somefinalpackage.SomeClass, SubClass): - @overrides + @override def somewhat_fun_method(self): return "foo" - @overrides + @override def some_method(self): pass - @overrides + @override def some_finalized_method(self): pass @@ -123,15 +123,15 @@ def test_final_fails_in_middle(self): try: class Sub4Fail(test_somefinalpackage.SomeClass, SubClass): - @overrides + @override def somewhat_fun_method(self): return "foo" - @overrides + @override def some_method(self): pass - @overrides + @override def another_finalized(self): pass @@ -143,15 +143,15 @@ def test_final_fails_from_another_package(self): try: class Sub5Fail(test_somefinalpackage.SomeClass, SubClass): - @overrides + @override def somewhat_fun_method(self): return "foo" - @overrides + @override def some_method(self): pass - @overrides + @override def some_finalized_method(self): pass diff --git a/tests/test_named_and_positional__py38.py b/tests/test_named_and_positional__py38.py index 1b0b938..c70d5aa 100644 --- a/tests/test_named_and_positional__py38.py +++ b/tests/test_named_and_positional__py38.py @@ -1,7 +1,7 @@ from abc import abstractmethod, ABC from typing import Literal -from overrides import overrides, EnforceOverrides +from overrides import override, EnforceOverrides class A(EnforceOverrides): @@ -19,7 +19,7 @@ def foo(self): def test_should_pass(): class B(A): - @overrides + @override def methoda(self, y=1, **kwargs): print(y) super().methoda(**kwargs) @@ -27,7 +27,7 @@ def methoda(self, y=1, **kwargs): def test_should_also_pass(): class B(A): - @overrides + @override def methoda(self, z=1, x=1, **kwargs): pass @@ -40,12 +40,12 @@ def method(self, str: Literal["max", "min"]): def test_literal_passes(): class B(Abs): - @overrides + @override def method(self, str: Literal["max", "min"]): return class C(Abs): - @overrides + @override def method(self, str: Literal["max", "min", "half"]): return @@ -54,7 +54,7 @@ def test_literal_failure(): try: class D(Abs): - @overrides + @override def method(self, str: Literal["a", "b", "c"]): pass @@ -67,7 +67,7 @@ def test_literal_failure_not_accepting_all(): try: class D(Abs): - @overrides + @override def method(self, str: Literal["min"]): pass @@ -80,7 +80,7 @@ def test_can_not_override_with_positional_only(): try: class C(A): - @overrides + @override def methoda(self, x=0, /): pass @@ -91,14 +91,14 @@ def methoda(self, x=0, /): def test_can_override_positional_only(): class PositionalOnly1(A): - @overrides + @override def methodb(self, x: int, /, y: str) -> str: return "OK" def test_can_override_positional_only_with_new_name(): class PositionalOnly2(A): - @overrides + @override def methodb(self, new_name_is_ok: int, /, y: str) -> str: return "OK2" @@ -107,7 +107,7 @@ def test_can_not_override_positional_only_with_new_type(): try: class PositionalOnly3(A): - @overrides + @override def methodb(self, x: str, /, y: str) -> str: return "NOPE" @@ -120,7 +120,7 @@ def test_can_not_override_with_keyword_only(): try: class C2(A): - @overrides + @override def methoda(self, *, x=0): pass @@ -131,10 +131,10 @@ def methoda(self, *, x=0): def test_multiple_inheritance(): class Multi(A, Other): - @overrides + @override def methoda(self, y=2, **kwargs): pass - @overrides + @override def foo(self) -> int: pass diff --git a/tests/test_overrides.py b/tests/test_overrides.py index 0ce55c0..5cc5452 100644 --- a/tests/test_overrides.py +++ b/tests/test_overrides.py @@ -4,7 +4,7 @@ from typing import Generic, TypeVar import test_somepackage -from overrides import overrides +from overrides import override TObject = TypeVar("TObject", bound="Foo") @@ -21,7 +21,7 @@ def some_method(self): class SubSubClassOfGeneric(SubClassOfGeneric["SubSubClassOfGeneric"]): - @overrides + @override def some_method(self): return 17 @@ -43,49 +43,49 @@ def check(self): class SubClass(SuperClass): - @overrides + @override def some_method(self): return "sub" class Subber(SuperClass): - @overrides + @override def some_method(self): """Subber""" return 1 class Sub2(test_somepackage.SomeClass, SuperClass): - @overrides + @override def somewhat_fun_method(self): return "foo" - @overrides + @override def some_method(self): pass class SubclassOfInt(int): - @overrides + @override def __str__(self): return "subclass of int" class CheckAtRuntime(SuperClass): - @overrides(check_at_runtime=True) + @override(check_at_runtime=True) def some_method(self, x): pass class StaticMethodOverridePass(SuperClass): @staticmethod - @overrides + @override def this_is_static(x, y, z, *args): pass class InnerClassOverride(SuperClass): - @overrides + @override class SomeClass: def check(self): return 1 @@ -118,7 +118,7 @@ def test_assertion_error_is_thrown_when_method_not_in_superclass(self): try: class ShouldFail(SuperClass): - @overrides + @override def somo_method(self): pass @@ -131,7 +131,7 @@ def test_static_method(self): class StaticMethodOverrideFail(SuperClass): @staticmethod - @overrides + @override def this_is_static(k, y, z): pass @@ -154,7 +154,7 @@ def test_overrides_check_at_runtime(self): def test_overrides_builtin_method_correct_signature(self): class SubclassOfInt(int): - @overrides + @override def bit_length(self): return super().bit_length() @@ -172,7 +172,7 @@ def test_overrides_builtin_method_incorrect_signature(self): with expected_error: class SubclassOfInt(int): - @overrides + @override def bit_length(self, _): "This will fail, bit_length takes in no arguments" diff --git a/tests/test_signatures.py b/tests/test_signatures.py index 2bd7f4f..02998a4 100644 --- a/tests/test_signatures.py +++ b/tests/test_signatures.py @@ -1,6 +1,6 @@ from typing import Any, Type, Union -from overrides import overrides +from overrides import override class SuperbClass: @@ -29,44 +29,44 @@ def foo(self, x) -> None: class ForwardReferencer(SuperbClass): - @overrides + @override def foo(self, x: "ForwardReferencer") -> "ForwardReferencer": pass class ClassMethodOverrider(SuperbClass): @classmethod - @overrides + @override def class_method(cls): pass class StaticMethodOverrider(SuperbClass): @staticmethod - @overrides + @override def static_method(param: Union[str, bool]) -> int: return 3 if param == "bar" else 2 class NormalMethodOverrider(SuperbClass): - @overrides + @override def normal_method(self, x: int, y: str = "zoo", *args, **kwargs) -> bool: return x % 3 == 1 or y in kwargs or x == len(args) class OverridesWithSignatureIgnore(SuperbClass): - @overrides(check_signature=False) + @override(check_signature=False) def normal_method(self, x: int) -> bool: return x % 2 == 1 class SelfTypedOverride(SuperbClass): - @overrides(check_at_runtime=True) + @override(check_at_runtime=True) def self_typed_method(self: "SelfTypedOverride") -> "SelfTypedOverride": return self @classmethod - @overrides(check_at_runtime=True) + @override(check_at_runtime=True) def self_typed_class_method(cls: "Type[SelfTypedOverride]") -> None: return None @@ -77,7 +77,7 @@ def foo(self: int): class B(A): - @overrides + @override def foo(self: str): pass @@ -91,7 +91,7 @@ def test_typed_subclass_in_same_package_is_an_error(): try: class TypedSubclass(UntypedBaseClass): - @overrides + @override def do_something(self, arg1: str, arg2: Any = None) -> Any: pass diff --git a/tests/test_special_cases.py b/tests/test_special_cases.py index 61ec0b2..d78e60d 100644 --- a/tests/test_special_cases.py +++ b/tests/test_special_cases.py @@ -3,7 +3,7 @@ from concurrent.futures import Future from typing import Callable, Any -from overrides import overrides +from overrides import override class MyInterface(ABC): @@ -20,14 +20,14 @@ def run(self, callback: Callable[[str], None]): def test_future_is_fine(): class FutureWorks(MyInterface): - @overrides + @override def run(self) -> "Future[str]": pass def test_callable_is_fine(): class CallableWorks(MyInterface2): - @overrides + @override def run(self, callback: Callable[[str], None]): pass @@ -36,7 +36,7 @@ def test_overriding_untyped_from_other_package_is_fine(): class Params(MutableMapping): DEFAULT = object() - @overrides + @override def pop( self, key: str, default: Any = DEFAULT, keep_as_dict: bool = False ) -> Any: