Skip to content

Commit 0728a44

Browse files
committed
update deprecator to exactly match 3.13 deprecated decorator
1 parent 1033143 commit 0728a44

File tree

1 file changed

+23
-62
lines changed

1 file changed

+23
-62
lines changed

src/diffpy/utils/_deprecator.py

Lines changed: 23 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -10,79 +10,40 @@
1010
_builtin_deprecated = None
1111

1212

13-
def deprecated(*, alt_name=None, message=None):
14-
"""Marks a function or class as deprecated.
13+
def deprecated(message, *, category=DeprecationWarning, stacklevel=1):
14+
"""Compatibility wrapper for Python <3.13.
1515
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
16+
Matches the Python 3.13 warnings.deprecated API exactly.
6217
"""
63-
if _builtin_deprecated:
64-
return _builtin_deprecated
18+
# If Python 3.13 implementation exists, delegate to it
19+
if _builtin_deprecated is not None:
20+
return _builtin_deprecated(
21+
message, category=category, stacklevel=stacklevel
22+
)
6523

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."
24+
# Validate message type like Python 3.13 does
25+
if not isinstance(message, str):
26+
raise TypeError(
27+
f"Expected an object of type str for 'message', not "
28+
f"{type(message).__name__!r}"
7229
)
7330

31+
def decorator(obj):
32+
# Set __deprecated__ attribute (required by PEP 702)
33+
setattr(obj, "__deprecated__", message)
34+
35+
# Must support functions AND classes
7436
if callable(obj):
7537

7638
@functools.wraps(obj)
7739
def wrapper(*args, **kwargs):
78-
warnings.warn(msg, DeprecationWarning, stacklevel=2)
40+
warnings.warn(message, category, stacklevel=stacklevel + 1)
7941
return obj(*args, **kwargs)
8042

8143
return wrapper
82-
else:
83-
raise TypeError(
84-
"deprecated decorator can only be applied to functions or "
85-
"classes"
86-
)
44+
45+
raise TypeError(
46+
"deprecated decorator can only be applied to functions or classes"
47+
)
8748

8849
return decorator

0 commit comments

Comments
 (0)