Source code for diffpy.utils._deprecator

import functools
import warnings

# Deprecated decorator is available for Python 3.13+, once
# Support for earlier versions is dropped, this custom
# implementation can be removed.
try:
    from warnings import deprecated as _builtin_deprecated
except ImportError:
    _builtin_deprecated = None


[docs] def deprecated(message, *, category=DeprecationWarning, stacklevel=1): """Deprecation decorator for functions and classes that is compatible with Python versions prior to 3.13. Examples -------- Basic usage with a deprecated function: .. code-block:: python from diffpy.utils._deprecator import ( deprecated, build_deprecation_message ) deprecation_warning = build_deprecation_message("diffpy.utils", "old_function", "new_function", "4.0.0") @deprecated(deprecation_warning) def old_function(x, y): '''This function is deprecated and will be removed in version 4.0.0. Please use new_function instead''' return new_function(x, y) def new_function(x, y): return x + y old_function(1, 2) # Works but emits DeprecationWarning new_function(1, 2) # Works, no warning Deprecating a class: .. code-block:: python from diffpy.utils._deprecator import ( deprecated, build_deprecation_message ) deprecation_warning = build_deprecation_message("diffpy.utils", "OldAtom", "NewAtom", "4.0.0") @deprecated(deprecation_warning) class OldAtom: def __new__(cls, *args, **kwargs): warnings.warn( "OldAtom is deprecated and will be removed in version 4.0.0. Use NewClass instead.", DeprecationWarning, stacklevel=2, ) return NewAtom(*args, **kwargs) class NewAtom: def __init__(self, symbol): self.symbol = symbol a = OldAtom("C") # Works but emits DeprecationWarning b = NewAtom("C") # Works with no warning """ if _builtin_deprecated is not None: return _builtin_deprecated( message, category=category, stacklevel=stacklevel ) if not isinstance(message, str): raise TypeError( f"Expected an object of type str for 'message', not " f"{type(message).__name__!r}" ) def decorator(obj): setattr(obj, "__deprecated__", message) if callable(obj): @functools.wraps(obj) def wrapper(*args, **kwargs): warnings.warn(message, category, stacklevel=stacklevel + 1) return obj(*args, **kwargs) return wrapper raise TypeError( "deprecated decorator can only be applied to functions or classes" ) return decorator
[docs] def build_deprecation_message( old_base, old_name, new_name, removal_version, new_base=None ): """Generate a deprecation message. Parameters ---------- old_base : str The base module or class where the deprecated item resides. This will look like the import statement used in the code currently old_name : str The name of the deprecated item. new_name : str The name of the new item to use. removal_version : str The version when the deprecated item will be removed. new_base : str Optional. Defaults to old_base. The base module or class where the new item resides. This will look like the import statement that will be used in the code moving forward. If not specified, the new base defaults to the old one. Returns ------- str A formatted deprecation message. """ if new_base is None: new_base = old_base return ( f"'{old_base}.{old_name}' is deprecated and will be removed in " f"version {removal_version}. Please use '{new_base}.{new_name}' " f"instead." )
[docs] def generate_deprecation_docstring(new_name, removal_version, new_base=None): """Generate a docstring for copy-pasting into a deprecated function. This function will print the text to the terminal for copy-pasting. Parameters ---------- new_name : str The name of the new function or class to replace the existing one. removal_version : str The version when the deprecated item is targeted for removal, e.g., 4.0.0. new_base : str, optional The new base for importing. The new import statement would look like "from new_base import new_name". Defaults to None. Example ------- >>> from diffpy.utils._deprecator import generate_deprecation_docstring >>> generate_deprecation_docstring("new_name", "4.0.0") The message looks like: This function has been deprecated and will be removed in version {removal_version}. Please use {new_base}.{new_name} instead. Returns ------- None """ if new_base is None: function_location = new_name else: function_location = f"{new_base}.{new_name}" print( f"This function has been deprecated and will be removed in version " f"{removal_version}.\n" f"Please use {function_location} instead." ) return