I am refactoring parts of an API and wish to add deprecation warnings to parts that will eventually be removed. However I have stumbled into an issue where I would like to replace a function call with a property sharing a name.
Is there a hack where I can support both calling the .length
as a property and as a function? I have thinkered with __getattribute__
and __getattr__
and can't think of a way.
import warnings
class A:
@property
def length(self):
return 1
def length(self):
warnings.warn(".length function is deprecated. Use the .length property", DeprecationWarning)
return 1
P.S.
Preferably I would like the solution to be python 2.7 compatible.
The only "kind of" solution I have thought of is to overwrite the return value and skip the properties for now and add them in later when the deprecation warnings are removed. This solution would work for my case, if there really isn't any other way, but I would prefer a solution that is a lot less hacky.
import warnings
class F(float):
def __init__(self, v):
self.v = v
def __new__(cls, value):
return float.__new__(cls, value)
def __call__(self, *args, **kwargs):
warnings.warn(".length function is deprecated. Use the .length property", DeprecationWarning)
return self.v
class A(object):
def __getattribute__(self, item):
if item == "length":
# This is a hack to enable a deprecation warning when calling .length()
# Remove this in favor for the @property, when the deprecation warnings are removed.
return F(1)
return super(A, self).__getattribute__(item)
# @property
# def length(self):
# # type: () -> float
# return 1.0
One workaround is to make the property return a proxy object of a subtype of the value to be returned. The proxy object can then produce the warning when called:
import warnings
def warning_property(message, warning_type=DeprecationWarning):
class _property(property):
def __get__(self, obj, obj_type=None):
value = super().__get__(obj, obj_type)
class _proxy(type(value)):
def __call__(self):
warnings.warn(message, warning_type)
return value
return _proxy(value)
return _property
so that:
class A:
@warning_property(".length function is deprecated. Use the .length property")
def length(self):
return 1
print(A().length)
print(A().length())
outputs:
1
1
DeprecationWarning: .length function is deprecated. Use the .length property
Demo: https://ideone.com/PWkLN9
Note that the above assumes that the constructor of the type of the returning value of the property can take an instance as an argument, which is the case for all built-in types. If the constructor has a different signature then you should modify return _proxy(value)
accordingly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With