Repository navigation
Expand file tree
/
Copy path_deprecator.py
More file actions
174 lines (141 loc) · 5.46 KB
/
Copy path_deprecator.py
File metadata and controls
174 lines (141 loc) · 5.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
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
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
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."
)
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
"""
print(
f"This function has been deprecated and will be removed in version "
f"{removal_version}.\n"
f"Please use {new_base}.{new_name} instead."
)
return