diff --git a/plum/resolver.py b/plum/resolver.py index e5de7dc..a4bf564 100644 --- a/plum/resolver.py +++ b/plum/resolver.py @@ -1,5 +1,6 @@ import pydoc import sys +import warnings from functools import wraps from typing import Callable, Optional, Tuple, Union @@ -14,6 +15,10 @@ __all__ = ["AmbiguousLookupError", "NotFoundLookupError"] +class MethodRedefinitionWarning(Warning): + """A method is redefined.""" + + def _render_function_call(f: str, target: Union[Tuple, Signature]) -> str: """Render a function call. @@ -260,6 +265,12 @@ def register(self, method: Method) -> None: f"The added method `{method}` is equal to {sum(existing)} " f"existing methods. This should never happen." ) + previous_method = self.methods[existing.index(True)] + warnings.warn( + f"`{method}` overwrites the earlier definition `{previous_method}`.", + category=MethodRedefinitionWarning, + stacklevel=0, + ) self.methods[existing.index(True)] = method else: self.methods.append(method) diff --git a/tests/test_resolver.py b/tests/test_resolver.py index 0db521e..ee379a0 100644 --- a/tests/test_resolver.py +++ b/tests/test_resolver.py @@ -1,13 +1,16 @@ import sys import textwrap import typing +import warnings import pytest import plum.resolver +from plum.dispatcher import Dispatcher from plum.method import Method from plum.resolver import ( AmbiguousLookupError, + MethodRedefinitionWarning, NotFoundLookupError, Resolver, _document, @@ -242,3 +245,29 @@ def f(x): assert r.resolve(m_c1.signature) == m_b1 m_b2.signature.precedence = 2 assert r.resolve(m_c1.signature) == m_b2 + + +def test_redefinition_warning(): + dispatch = Dispatcher() + + with warnings.catch_warnings(): + warnings.simplefilter("error") + + @dispatch + def f(x: int): + pass + + @dispatch + def f(x: str): + pass + + # Warnings are only emitted when all registrations are resolved. + f._resolve_pending_registrations() + + with pytest.warns(MethodRedefinitionWarning): + + @dispatch + def f(x: int): + pass + + f._resolve_pending_registrations()