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
Since Python 3.7, you can provide a customization of module attribute access using __getattr__
(and __dir__
). Everything is explained in PEP 562.
In the bellow example, I implemented __getattr__
and __dir__
in order to deprecate the “OldClsName” in favor of “NewClsNam”:
# your_lib.py
import warnings
__all__ = ["NewClsName"]
DEPRECATED_NAMES = [('OldClsName', 'NewClsName')]
class NewClsName:
@classmethod
def create_variant1(cls):
return cls()
def __getattr__(name):
for old_name, new_name in DEPRECATED_NAMES:
if name == old_name:
warnings.warn(f"The '{old_name}' class or function is renamed '{new_name}'",
DeprecationWarning,
stacklevel=2)
return globals()[new_name]
raise AttributeError(f"module {__name__} has no attribute {name}")
def __dir__():
return sorted(__all__ + [names[0] for names in DEPRECATED_NAMES])
In the __getattr__
function, if a deprecated class or function name is found, a warning message is emitted, showing the source file and line number of the caller (with stacklevel=2
).
In the user code, we could have:
# your_lib_usage.py
from your_lib import NewClsName
from your_lib import OldClsName
def use_new_class():
obj = NewClsName.create_variant1()
print(obj.__class__.__name__ + " is created in use_new_class")
def use_old_class():
obj = OldClsName.create_variant1()
print(obj.__class__.__name__ + " is created in use_old_class")
if __name__ == '__main__':
use_new_class()
use_old_class()
When the user run his script your_lib_usage.py
, it will get something like this:
NewClsName is created in use_new_class
NewClsName is created in use_old_class
/path/to/your_lib_usage.py:3: DeprecationWarning: The 'OldClsName' class or function is renamed 'NewClsName'
from your_lib import OldClsName
Note: the stack trace is usually written in STDERR.
To see the error warnings, you may need to add a “-W” flag in the Python command line, for instance:
python -W always your_lib_usage.py