"""Implementation of deprecation utilities."""# -*- coding: utf-8 -*-## This file is subject to the terms and conditions defined in# file 'LICENSE.txt', which is part of this source code package.### %% ImportsimportfunctoolsimportwarningsfromtypingimportOptionaltry:fromwarningsimportdeprecatedasdeprecated_builtin# Python 3.13+exceptImportError:
[docs]defdeprecated(reason:str,version:Optional[str]=None,removal:Optional[str]=None):"""Decorator to mark a function, method, or class as deprecated. Uses built-in `warnings.deprecated` when running on Python 3.13+, otherwise falls back to a custom warning wrapper. Args: reason (str): Explanation and suggested replacement. version (str, optional): Version since deprecation. removal (str, optional): Planned removal version. """message_parts=[reason]ifversion:message_parts.append(f"[since v{version}]")ifremoval:message_parts.append(f"(will be removed in v{removal})")full_message=" ".join(message_parts)ifdeprecated_builtinisnotNone:# pragma: no coverdefdecorator(obj):returndeprecated_builtin(full_message,category=DeprecationWarning,stacklevel=2)(obj)returndecoratordefdecorator(obj):ifisinstance(obj,type):orig_init=obj.__init__@functools.wraps(orig_init)defnew_init(self,*args,**kwargs):warnings.warn(full_message,DeprecationWarning,stacklevel=2)returnorig_init(self,*args,**kwargs)obj.__init__=new_initreturnobjelifcallable(obj):@functools.wraps(obj)defwrapper(*args,**kwargs):warnings.warn(full_message,DeprecationWarning,stacklevel=2)returnobj(*args,**kwargs)returnwrapperelse:raiseTypeError("@deprecated decorator with non-None category must be applied to "f"a class or callable, not {obj!r}")returndecorator
[docs]defdeprecated_argument(old_arg:str,new_arg:str,converter=lambdax:x,version:Optional[str]=None,removal:Optional[str]=None,):"""Decorator to mark a function argument as deprecated and redirect it to a new argument. Args: old_arg (str): Name of the old argument. new_arg (str): Name of the new argument. converter (callable): Function to convert the old value into the new format. version (str, optional): Version since deprecation. removal (str, optional): Planned removal version. """message_parts=[f"Argument `{old_arg}` is deprecated, use `{new_arg}` instead."]ifversion:message_parts.append(f"[since v{version}]")ifremoval:message_parts.append(f"(will be removed in v{removal})")full_message=" ".join(message_parts)defdecorator(func):@functools.wraps(func)defwrapper(*args,**kwargs):ifold_arginkwargs:# Emit deprecation warningifdeprecated_builtinisnotNone:# pragma: no cover# In Python 3.13+, link warning to the function itselfdecorated=deprecated_builtin(full_message,category=DeprecationWarning,stacklevel=2)(func)returndecorated(*args,**{new_arg:converter(kwargs.pop(old_arg)),**kwargs})else:warnings.warn(full_message,DeprecationWarning,stacklevel=2)kwargs[new_arg]=converter(kwargs.pop(old_arg))returnfunc(*args,**kwargs)returnwrapperreturndecorator