From 0728a448cc9785e4ec456810be88d1eaeaeda7e8 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 24 Nov 2025 11:00:16 -0500 Subject: [PATCH 1/5] update deprecator to exactly match 3.13 deprecated decorator --- src/diffpy/utils/_deprecator.py | 85 +++++++++------------------------ 1 file changed, 23 insertions(+), 62 deletions(-) diff --git a/src/diffpy/utils/_deprecator.py b/src/diffpy/utils/_deprecator.py index 099e371..55593c9 100644 --- a/src/diffpy/utils/_deprecator.py +++ b/src/diffpy/utils/_deprecator.py @@ -10,79 +10,40 @@ _builtin_deprecated = None -def deprecated(*, alt_name=None, message=None): - """Marks a function or class as deprecated. +def deprecated(message, *, category=DeprecationWarning, stacklevel=1): + """Compatibility wrapper for Python <3.13. - Emits a DeprecationWarning whenever the decorated function is called - or the decorated class is instantiated. - - Parameters - ---------- - alt_name : str, optional - Name of the recommended alternative. - message : str, optional - Custom deprecation message. If None, a default message is generated. - - Returns - ------- - decorator : function - Decorator that wraps the deprecated object. - - Examples - -------- - .. code-block:: python - - from diffpy._deprecations import deprecated - - # ------------------------------ - # Deprecated function - # ------------------------------ - @deprecated(alt_name="new_function") - def old_function(x, y): - return x + y - - def new_function(x, y): - return x + y - - # Usage - old_function(1, 2) # Emits DeprecationWarning - new_function(1, 2) # No warning - - # ------------------------------ - # Deprecated class - # ------------------------------ - @deprecated(alt_name="NewAtom") - class OldAtom: - def __init__(self, symbol): - self.symbol = symbol - - # Usage - a = OldAtom("C") # Emits DeprecationWarning - atom = NewAtom("C") # No warning + Matches the Python 3.13 warnings.deprecated API exactly. """ - if _builtin_deprecated: - return _builtin_deprecated + # If Python 3.13 implementation exists, delegate to it + if _builtin_deprecated is not None: + return _builtin_deprecated( + message, category=category, stacklevel=stacklevel + ) - def decorator(obj): - name = getattr(obj, "__name__", repr(obj)) - msg = message or ( - f"'{name}' is deprecated. Use '{alt_name}' instead." - if alt_name - else f"'{name}' is deprecated." + # Validate message type like Python 3.13 does + 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): + # Set __deprecated__ attribute (required by PEP 702) + setattr(obj, "__deprecated__", message) + + # Must support functions AND classes if callable(obj): @functools.wraps(obj) def wrapper(*args, **kwargs): - warnings.warn(msg, DeprecationWarning, stacklevel=2) + warnings.warn(message, category, stacklevel=stacklevel + 1) return obj(*args, **kwargs) return wrapper - else: - raise TypeError( - "deprecated decorator can only be applied to functions or " - "classes" - ) + + raise TypeError( + "deprecated decorator can only be applied to functions or classes" + ) return decorator From 1d936d77fc0ccb3acea09ac9047de94f0df75132 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Mon, 24 Nov 2025 11:00:53 -0500 Subject: [PATCH 2/5] comment --- src/diffpy/utils/_deprecator.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/diffpy/utils/_deprecator.py b/src/diffpy/utils/_deprecator.py index 55593c9..21dffa7 100644 --- a/src/diffpy/utils/_deprecator.py +++ b/src/diffpy/utils/_deprecator.py @@ -15,13 +15,10 @@ def deprecated(message, *, category=DeprecationWarning, stacklevel=1): Matches the Python 3.13 warnings.deprecated API exactly. """ - # If Python 3.13 implementation exists, delegate to it if _builtin_deprecated is not None: return _builtin_deprecated( message, category=category, stacklevel=stacklevel ) - - # Validate message type like Python 3.13 does if not isinstance(message, str): raise TypeError( f"Expected an object of type str for 'message', not " @@ -29,10 +26,7 @@ def deprecated(message, *, category=DeprecationWarning, stacklevel=1): ) def decorator(obj): - # Set __deprecated__ attribute (required by PEP 702) setattr(obj, "__deprecated__", message) - - # Must support functions AND classes if callable(obj): @functools.wraps(obj) From af8c0b1a165cb56077719315d7151643fd44f9cd Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 9 Dec 2025 14:46:08 -0500 Subject: [PATCH 3/5] news --- news/deprecated_update.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 news/deprecated_update.rst diff --git a/news/deprecated_update.rst b/news/deprecated_update.rst new file mode 100644 index 0000000..27fc85d --- /dev/null +++ b/news/deprecated_update.rst @@ -0,0 +1,23 @@ +**Added:** + +* No news needed. + +**Changed:** + +* + +**Deprecated:** + +* + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* From d3c6e879c72fca57cbeed39ef3f09d3ac2ac225a Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 9 Dec 2025 14:49:31 -0500 Subject: [PATCH 4/5] docstring --- src/diffpy/utils/_deprecator.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/diffpy/utils/_deprecator.py b/src/diffpy/utils/_deprecator.py index 21dffa7..a3c598d 100644 --- a/src/diffpy/utils/_deprecator.py +++ b/src/diffpy/utils/_deprecator.py @@ -11,10 +11,8 @@ def deprecated(message, *, category=DeprecationWarning, stacklevel=1): - """Compatibility wrapper for Python <3.13. - - Matches the Python 3.13 warnings.deprecated API exactly. - """ + """Deprecation decorator for functions and classes that is compatible with + Python versions prior to 3.13.""" if _builtin_deprecated is not None: return _builtin_deprecated( message, category=category, stacklevel=stacklevel From 3b7b13b50420cd25f3e30559fe204ea6d603125e Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Tue, 9 Dec 2025 14:52:29 -0500 Subject: [PATCH 5/5] examples in docstring --- src/diffpy/utils/_deprecator.py | 44 ++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/src/diffpy/utils/_deprecator.py b/src/diffpy/utils/_deprecator.py index a3c598d..91f3c0f 100644 --- a/src/diffpy/utils/_deprecator.py +++ b/src/diffpy/utils/_deprecator.py @@ -12,7 +12,49 @@ def deprecated(message, *, category=DeprecationWarning, stacklevel=1): """Deprecation decorator for functions and classes that is compatible with - Python versions prior to 3.13.""" + Python versions prior to 3.13. + + Examples + -------- + Basic usage with a deprecated function: + + .. code-block:: python + + from diffpy._deprecations import deprecated + import warnings + + @deprecated("old_function is deprecated; use new_function instead") + def old_function(x, y): + return x + y + + def new_function(x, y): + return x + y + + old_function(1, 2) # Emits DeprecationWarning + new_function(1, 2) # No warning + + + Deprecating a class: + + .. code-block:: python + + from diffpy._deprecations import deprecated + import warnings + + warnings.simplefilter("always", DeprecationWarning) + + @deprecated("OldAtom is deprecated; use NewAtom instead") + class OldAtom: + def __init__(self, symbol): + self.symbol = symbol + + class NewAtom: + def __init__(self, symbol): + self.symbol = symbol + + a = OldAtom("C") # Emits DeprecationWarning + b = NewAtom("C") # No warning + """ if _builtin_deprecated is not None: return _builtin_deprecated( message, category=category, stacklevel=stacklevel