Skip to content

Commit 1033143

Browse files
authored
Merge pull request #363 from cadenmyers13/deprecator
feat: add `@deprecated` decorator
2 parents 30407bf + 4ec1cf2 commit 1033143

File tree

2 files changed

+111
-0
lines changed

2 files changed

+111
-0
lines changed

news/deprecator.rst

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
**Added:**
2+
3+
* Add ``@deprecated`` decorator.
4+
5+
**Changed:**
6+
7+
* <news item>
8+
9+
**Deprecated:**
10+
11+
* <news item>
12+
13+
**Removed:**
14+
15+
* <news item>
16+
17+
**Fixed:**
18+
19+
* <news item>
20+
21+
**Security:**
22+
23+
* <news item>

src/diffpy/utils/_deprecator.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import functools
2+
import warnings
3+
4+
# Deprecated decorator is available for Python 3.13+, once
5+
# Support for earlier versions is dropped, this custom
6+
# implementation can be removed.
7+
try:
8+
from warnings import deprecated as _builtin_deprecated
9+
except ImportError:
10+
_builtin_deprecated = None
11+
12+
13+
def deprecated(*, alt_name=None, message=None):
14+
"""Marks a function or class as deprecated.
15+
16+
Emits a DeprecationWarning whenever the decorated function is called
17+
or the decorated class is instantiated.
18+
19+
Parameters
20+
----------
21+
alt_name : str, optional
22+
Name of the recommended alternative.
23+
message : str, optional
24+
Custom deprecation message. If None, a default message is generated.
25+
26+
Returns
27+
-------
28+
decorator : function
29+
Decorator that wraps the deprecated object.
30+
31+
Examples
32+
--------
33+
.. code-block:: python
34+
35+
from diffpy._deprecations import deprecated
36+
37+
# ------------------------------
38+
# Deprecated function
39+
# ------------------------------
40+
@deprecated(alt_name="new_function")
41+
def old_function(x, y):
42+
return x + y
43+
44+
def new_function(x, y):
45+
return x + y
46+
47+
# Usage
48+
old_function(1, 2) # Emits DeprecationWarning
49+
new_function(1, 2) # No warning
50+
51+
# ------------------------------
52+
# Deprecated class
53+
# ------------------------------
54+
@deprecated(alt_name="NewAtom")
55+
class OldAtom:
56+
def __init__(self, symbol):
57+
self.symbol = symbol
58+
59+
# Usage
60+
a = OldAtom("C") # Emits DeprecationWarning
61+
atom = NewAtom("C") # No warning
62+
"""
63+
if _builtin_deprecated:
64+
return _builtin_deprecated
65+
66+
def decorator(obj):
67+
name = getattr(obj, "__name__", repr(obj))
68+
msg = message or (
69+
f"'{name}' is deprecated. Use '{alt_name}' instead."
70+
if alt_name
71+
else f"'{name}' is deprecated."
72+
)
73+
74+
if callable(obj):
75+
76+
@functools.wraps(obj)
77+
def wrapper(*args, **kwargs):
78+
warnings.warn(msg, DeprecationWarning, stacklevel=2)
79+
return obj(*args, **kwargs)
80+
81+
return wrapper
82+
else:
83+
raise TypeError(
84+
"deprecated decorator can only be applied to functions or "
85+
"classes"
86+
)
87+
88+
return decorator

0 commit comments

Comments
 (0)