8
8
:license: MIT, see LICENSE for details.
9
9
"""
10
10
11
- import copy
12
11
import functools
13
12
import warnings
13
+ from collections import namedtuple
14
14
15
15
from werkzeug .local import LocalProxy as module_property # noqa
16
16
@@ -55,21 +55,19 @@ def deprecated(new_func=None, eol_version=None):
55
55
:param Union[str, (str, str)] new_func: Name (or name and end-of-life version) of replacement
56
56
:param str eol_version: Version in which this function may no longer work
57
57
:return:
58
+ Raise a deprecation warning for decorated function.
59
+ Tuple is supported for new_func just in case somebody infers it as an option based on the way we
60
+ deprecate params..
61
+ If tuple form is used for new_func AND eol_version is provided, eol_version will trump whatever is
62
+ found in the tuple; caveat emptor
58
63
"""
59
64
60
65
def decorator (f ):
61
66
@functools .wraps (f )
62
67
def wrapper (* args , ** kwargs ):
63
- new = None
64
- eol = eol_version
65
- if (
66
- type (new_func ) is tuple
67
- ): # in case somebody inferred this from the way we deprecate params..
68
- new = str (new_func [0 ])
69
- eol = str (new_func [1 ])
70
- elif new_func :
71
- new = str (new_func )
72
- _deprecation_warning (f .__name__ , new , eol )
68
+ new , eol = _validated_deprecation_spec (new_func )
69
+ eol = eol_version or eol
70
+ _deprecation_warning (f .__name__ , new , eol , stacklevel = 3 )
73
71
return f (* args , ** kwargs )
74
72
75
73
return wrapper
@@ -96,35 +94,54 @@ def wrapper(*args, **kwargs):
96
94
return decorator
97
95
98
96
97
+ def _validated_deprecation_spec (spec ):
98
+ """
99
+ :param Union[new_name, (new_name, eol_version)] spec: new name and/or expected end-of-life version
100
+ :return: (str new_name, str eol_version), normalized to tuple and sanitized to deal with malformed inputs
101
+ Parse a deprecation spec (string or tuple) to a standardized namedtuple form.
102
+ If spec is provided as a bare value (presumably string), we'll treat as new name with no end-of-life version
103
+ If spec is provided (likely on accident) as a 1-element tuple, we'll treat same as a bare value
104
+ If spec is provided as a tuple with more than 2 elements, we'll simply ignore the extraneous
105
+ """
106
+ new_name = None
107
+ eol_version = None
108
+ if type (spec ) is tuple :
109
+ if len (spec ) > 0 :
110
+ new_name = str (spec [0 ]) if spec [0 ] else None
111
+ if len (spec ) > 1 :
112
+ eol_version = str (spec [1 ]) if spec [1 ] else None
113
+ elif spec :
114
+ new_name = str (spec )
115
+ validated = namedtuple ("deprecation_spec" , ["new_name" , "eol_version" ])(
116
+ new_name , eol_version
117
+ )
118
+ return validated
119
+
120
+
99
121
def _remap_kwargs (func_name , kwargs , aliases ):
100
122
"""
101
123
Adapted from https://stackoverflow.com/a/49802489/977046
102
124
"""
103
- remapped_args = copy . deepcopy (kwargs )
125
+ remapped_args = dict (kwargs )
104
126
for alias , new_spec in aliases .items ():
105
127
if alias in remapped_args :
106
- eol_version = None
107
- if type (new_spec ) is tuple :
108
- new = str (new_spec [0 ])
109
- if len (new_spec ) >= 2 :
110
- eol_version = str (new_spec [1 ]) if new_spec [1 ] else None
111
- else :
112
- new = str (new_spec )
128
+ new , eol_version = _validated_deprecation_spec (new_spec )
113
129
if new in remapped_args :
114
130
raise TypeError (
115
131
"{} received both {} and {}" .format (func_name , alias , new )
116
132
)
117
133
else :
118
- _deprecation_warning (alias , new , eol_version )
119
- remapped_args [new ] = remapped_args .pop (alias )
134
+ _deprecation_warning (alias , new , eol_version , stacklevel = 4 )
135
+ if new :
136
+ remapped_args [new ] = remapped_args .pop (alias )
120
137
121
138
return remapped_args
122
139
123
140
124
- def _deprecation_warning (old_name , new_name , eol_version ):
141
+ def _deprecation_warning (old_name , new_name , eol_version , stacklevel = 1 ):
125
142
eol_clause = (
126
143
" and may be removed in version {}" .format (eol_version ) if eol_version else ""
127
144
)
128
145
replacement_clause = "; use {}" .format (new_name ) if new_name else ""
129
146
msg = "{} is deprecated{}{}" .format (old_name , eol_clause , replacement_clause )
130
- warnings .warn (msg , config .warning_type )
147
+ warnings .warn (message = msg , category = config .warning_type , stacklevel = stacklevel )
0 commit comments