31
loading...
This website collects cookies to deliver better user experience
How to introduce changes gracefully to your code over time?
from warnings import warn
warn('This is deprecated', DeprecationWarning, stacklevel=2)
DeprecationWarning
as category. To let the warning refer to the caller, so you know exactly where you use deprecated code, you have to set stacklevel=2
.warn
within a function like this.from warnings import warn
def a_deprecated_function():
warn('This method is deprecated.', DeprecationWarning, stacklevel=2)
DeprecationWarning
's withing the method.from warnings import warn
def a_function_with_deprecated_arguments(arg1, *args, kwarg1=None, **kwargs):
# Positional argument `arg1` is going to change its type from (int, str) to (None, str)
if type(arg1) is int:
warn('arg1 of type int is going to be deprecated', DeprecationWarning, stacklevel=2)
# Keyword argument `kwarg2` is going to be dropped completely.
if 'kwarg2' in kwargs.keys():
warn('kwarg2 will be deprecated', DeprecationWarning, stacklevel=2)
__init__
method. In order to throw a warning on subclassing from a deprecated method, you have to override the __init_sublcall__
method instead.from warnings import warn
class ADeprecatedClass(object):
def __init_subclass__(cls, **kwargs):
"""This throws a deprecation warning on subclassing."""
warn(f'{cls.__name__} will be deprecated.', DeprecationWarning, stacklevel=2)
super().__init_subclass__(**kwargs)
def __init__(self, *args, **kwargs):
"""This throws a deprecation warning on initialization."""
warn(f'{self.__class__.__name__} will be deprecated.', DeprecationWarning, stacklevel=2)
super().__init__(*args, **kwargs)
__getattribute__
method of objects metaclass.from warnings import warn
class DeprecatedMetaclass(type):
def __getattribute__(self, item):
if 'a_deprecated_class_variable' == item:
warn(f'{item} class variable is deprecated', DeprecationWarning, stacklevel=2)
return type.__getattribute__(self, item)
class AClass(object, metaclass=DeprecatedMetaclass):
a_class_variable = 'foo'
a_deprecated_class_variable = None # deprecated
EnumMeta.__getattribute__
as a super call instead, as you are subclassing from EnumMeta
.from enum import EnumMeta, Enum
from warnings import warn
class ADeprecatedEnumMeta(EnumMeta):
def __getattribute__(self, item):
if item == 'BAR':
warn('BAR is going to be deprecated', DeprecationWarning, stacklevel=2)
return EnumMeta.__getattribute__(self, item)
class ADeprecatedEnum(Enum, metaclass=ADeprecatedEnumMeta):
FOO = 'foo'
BAR = 'bar' # deprecated
# lib.py
from warnings import warn
warn(f'The module {__name__} is deprecated.', DeprecationWarning, stacklevel=2)
__init__.py
of the package to be deprecated.with
block. Setting record=True
enables you to record the warnings which were emitted during execution of your code and check if the desired warnings where raised as expected. We won't evaluate this in depth, due to it is well documented in Python documentation here.from warnings import catch_warnings
def test_a_deprecated_enum_value():
with catch_warnings(record=True) as w:
# ADeprecatedEnum.FOO is not deprecated and should not throw any warning
ADeprecatedEnum.FOO
assert len(w) == 0
# ADeprecatedEnum.BAR is deprecated and we expect to have a warning raised.
ADeprecatedEnum.BAR
assert len(w) == 1
assert issubclass(w[0].category, DeprecationWarning)
assert str(w[0].message) == 'BAR is deprecated'
message; key=value
. This way, adding meta information is straight forward and can be parsed by other tools easily as well.from warnings import warn
warn("This is deprecated; version=1.0.0", DeprecationWarning, stacklevel=2)
version
or date
for indicating changes in a particular point in time.from warnings import warn
warn("This is deprecated; date=2022-01-01", DeprecationWarning, stacklevel=2)