I have renamed a python class that is part of a library. I am willing to leave a possibility to use its previous name for some time but would like to warn user that it\'s de
Use inspect module to add placeholder for OldClass, then OldClsName is NewClsName check will pass, and a linter like pylint will inform this as error.
deprecate.py
import inspect
import warnings
from functools import wraps
def renamed(old_name):
"""Return decorator for renamed callable.
Args:
old_name (str): This name will still accessible,
but call it will result a warn.
Returns:
decorator: this will do the setting about `old_name`
in the caller's module namespace.
"""
def _wrap(obj):
assert callable(obj)
def _warn():
warnings.warn('Renamed: {} -> {}'
.format(old_name, obj.__name__),
DeprecationWarning, stacklevel=3)
def _wrap_with_warn(func, is_inspect):
@wraps(func)
def _func(*args, **kwargs):
if is_inspect:
# XXX: If use another name to call,
# you will not get the warning.
frame = inspect.currentframe().f_back
code = inspect.getframeinfo(frame).code_context
if [line for line in code
if old_name in line]:
_warn()
else:
_warn()
return func(*args, **kwargs)
return _func
# Make old name available.
frame = inspect.currentframe().f_back
assert old_name not in frame.f_globals, (
'Name already in use.', old_name)
if inspect.isclass(obj):
obj.__init__ = _wrap_with_warn(obj.__init__, True)
placeholder = obj
else:
placeholder = _wrap_with_warn(obj, False)
frame.f_globals[old_name] = placeholder
return obj
return _wrap
test.py
from __future__ import print_function
from deprecate import renamed
@renamed('test1_old')
def test1():
return 'test1'
@renamed('Test2_old')
class Test2(object):
pass
def __init__(self):
self.data = 'test2_data'
def method(self):
return self.data
# pylint: disable=undefined-variable
# If not use this inline pylint option,
# there will be E0602 for each old name.
assert(test1() == test1_old())
assert(Test2_old is Test2)
print('# Call new name')
print(Test2())
print('# Call old name')
print(Test2_old())
then run python -W all test.py:
test.py:22: DeprecationWarning: Renamed: test1_old -> test1
# Call new name
<__main__.Test2 object at 0x0000000007A147B8>
# Call old name
test.py:27: DeprecationWarning: Renamed: Test2_old -> Test2
<__main__.Test2 object at 0x0000000007A147B8>