deprecate abstract method
This is a feature request (I think): I would like deprecated to be able to yield warnings on a method call, even when overriding the implementation in a subclass. In particular, I would like to be able to deprecate abstract methods.
Expected Behavior
Running…
from deprecated import deprecated
class Parent:
@deprecated(reason='try not to laugh')
def fun(self, arg):
raise NotImplementedError()
class Child(Parent):
def fun(self, arg):
print(arg)
print('yaye!')
some = Child()
some.fun('whoops')
…I would like to see…
DeprecationWarning: Call to deprecated method fun. (try not to laugh)
some.fun('whoops')
whoops
yaye!
Actual Behavior
However, since the method is overriden, I can see no warning:
whoops
yaye!
Environment
- Python version: 3.9
- Deprecated version: 1.2.14
To elaborate: the use-case is quite simple: I have a library with an abstract method, which gets deprecated at some point. Inheriting code (not under my control) should see the deprecation warning when their implemented method gets called.
As a workaround, of course I can place the following in the superclass' constructor:
class Parent:
def __init__(self, ...)
...
setattr(self, 'fun', deprecated(reason='try not to laugh')(getattr(self, 'fun')))
But of course it would be much nicer if deprecated would offer something along those lines itself.
You're correct; the previous solution won't work here. When a subclass overrides an abstract method, it completely replaces it, so the decorated parent method (with the deprecation warning) is never actually called. The decorator only issues a warning if the decorated method itself is called, which doesn’t happen with overridden abstract methods.
Possible Approach: Introspection with __mro__
To emit a warning when calling the overridden method in the subclass, one option is to add introspection logic to the decorator. This would involve checking the class's Method Resolution Order (__mro__) each time the method is called, to see if any superclass has a deprecated method with the same name. The __mro__ attribute lists the method resolution path in Python, allowing the decorator to detect deprecated methods up the inheritance chain.
This approach introduces extra processing time, as each method call would require scanning the __mro__ for a deprecated method in the parent classes.
Currently, there isn’t a straightforward way to make deprecated warnings propagate to overridden abstract methods in subclasses, as the subclass method bypasses the parent method entirely. An introspective approach could work but would add significant overhead.