deprecated-params 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- deprecated_params-0.1.0/LICENSE +21 -0
- deprecated_params-0.1.0/PKG-INFO +46 -0
- deprecated_params-0.1.0/README.md +34 -0
- deprecated_params-0.1.0/deprecated_params/__init__.py +273 -0
- deprecated_params-0.1.0/deprecated_params.egg-info/PKG-INFO +46 -0
- deprecated_params-0.1.0/deprecated_params.egg-info/SOURCES.txt +11 -0
- deprecated_params-0.1.0/deprecated_params.egg-info/dependency_links.txt +1 -0
- deprecated_params-0.1.0/deprecated_params.egg-info/requires.txt +3 -0
- deprecated_params-0.1.0/deprecated_params.egg-info/top_level.txt +1 -0
- deprecated_params-0.1.0/pyproject.toml +17 -0
- deprecated_params-0.1.0/setup.cfg +4 -0
- deprecated_params-0.1.0/setup.py +4 -0
- deprecated_params-0.1.0/tests/test_wrapper.py +52 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Vizonex
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: deprecated-params
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A Wrapper for functions, class objects and methods for deprecating keyword parameters
|
|
5
|
+
Author: Vizonex
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Requires-Python: >=3.9
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: typing-extensions; python_version < "3.10"
|
|
11
|
+
Dynamic: license-file
|
|
12
|
+
|
|
13
|
+
# Deprecated Params
|
|
14
|
+
|
|
15
|
+
Inspired after python's warning.deprecated wrapper, deprecated_params is made to serve the single purpose of deprecating parameter names to warn users
|
|
16
|
+
about incoming changes as well as retaining typehinting.
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
## How to Deprecate Parameters
|
|
21
|
+
Parameters should be keyword arguments, not positional, Reason
|
|
22
|
+
for this implementation is that in theory you should've already
|
|
23
|
+
planned an alternative approch to an argument you wish
|
|
24
|
+
to deprecate.
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
from deprecated_params import deprecated_params
|
|
28
|
+
|
|
29
|
+
@deprecated_params(['x'])
|
|
30
|
+
def func(y, *, x:int = 0):
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
# DeprecationWarning: Parameter "x" is deprecated
|
|
34
|
+
func(None, x=20)
|
|
35
|
+
|
|
36
|
+
# NOTE: **kw is accepted but also you could put down more than one
|
|
37
|
+
# parameter if needed...
|
|
38
|
+
@deprecated_params(['foo'], {"foo":"foo was removed in ... don't use it"}, display_kw=False)
|
|
39
|
+
class MyClass:
|
|
40
|
+
def __init__(self, spam:object, **kw):
|
|
41
|
+
self.spam = spam
|
|
42
|
+
self.foo = kw.get("foo", None)
|
|
43
|
+
|
|
44
|
+
# DeprecationWarning: foo was removed in ... don't use it
|
|
45
|
+
mc = MyClass("spam", foo="X")
|
|
46
|
+
```
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Deprecated Params
|
|
2
|
+
|
|
3
|
+
Inspired after python's warning.deprecated wrapper, deprecated_params is made to serve the single purpose of deprecating parameter names to warn users
|
|
4
|
+
about incoming changes as well as retaining typehinting.
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
## How to Deprecate Parameters
|
|
9
|
+
Parameters should be keyword arguments, not positional, Reason
|
|
10
|
+
for this implementation is that in theory you should've already
|
|
11
|
+
planned an alternative approch to an argument you wish
|
|
12
|
+
to deprecate.
|
|
13
|
+
|
|
14
|
+
```python
|
|
15
|
+
from deprecated_params import deprecated_params
|
|
16
|
+
|
|
17
|
+
@deprecated_params(['x'])
|
|
18
|
+
def func(y, *, x:int = 0):
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
# DeprecationWarning: Parameter "x" is deprecated
|
|
22
|
+
func(None, x=20)
|
|
23
|
+
|
|
24
|
+
# NOTE: **kw is accepted but also you could put down more than one
|
|
25
|
+
# parameter if needed...
|
|
26
|
+
@deprecated_params(['foo'], {"foo":"foo was removed in ... don't use it"}, display_kw=False)
|
|
27
|
+
class MyClass:
|
|
28
|
+
def __init__(self, spam:object, **kw):
|
|
29
|
+
self.spam = spam
|
|
30
|
+
self.foo = kw.get("foo", None)
|
|
31
|
+
|
|
32
|
+
# DeprecationWarning: foo was removed in ... don't use it
|
|
33
|
+
mc = MyClass("spam", foo="X")
|
|
34
|
+
```
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Deprecated Params
|
|
3
|
+
-----------------
|
|
4
|
+
|
|
5
|
+
A Library dedicated for warning users about deprecated paramter
|
|
6
|
+
names and changes
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import inspect
|
|
15
|
+
import sys
|
|
16
|
+
import warnings
|
|
17
|
+
import functools
|
|
18
|
+
import inspect
|
|
19
|
+
from types import MethodType
|
|
20
|
+
from typing import Callable, Sequence, TypeVar, Mapping, overload
|
|
21
|
+
|
|
22
|
+
if sys.version_info < (3, 10):
|
|
23
|
+
from typing_extensions import ParamSpec
|
|
24
|
+
else:
|
|
25
|
+
from typing import ParamSpec
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
__version__ = "0.1.0"
|
|
29
|
+
__license__ = "Appache 2.0"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
_T = TypeVar("_T", covariant=True)
|
|
33
|
+
_P = ParamSpec("_P")
|
|
34
|
+
|
|
35
|
+
KEYWORD_ONLY = inspect.Parameter.KEYWORD_ONLY
|
|
36
|
+
VAR_KEYWORD = inspect.Parameter.VAR_KEYWORD
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
__all__ = (
|
|
40
|
+
"MissingKeywordsError",
|
|
41
|
+
"InvalidParametersError",
|
|
42
|
+
"deprecated_params",
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class _KeywordsBaseException(Exception):
|
|
47
|
+
def __init__(self, keywords: set[str], *args):
|
|
48
|
+
self._keywords = keywords
|
|
49
|
+
super().__init__(*args)
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def keywords(self):
|
|
53
|
+
return self._keywords
|
|
54
|
+
|
|
55
|
+
@keywords.setter
|
|
56
|
+
def keywords(self, kw):
|
|
57
|
+
raise ValueError("keywords property is immutable")
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class MissingKeywordsError(_KeywordsBaseException):
|
|
61
|
+
"""Missing keyword for argument"""
|
|
62
|
+
|
|
63
|
+
def __init__(self, keywords: set[str], *args):
|
|
64
|
+
super().__init__(
|
|
65
|
+
keywords, f"Missing Keyword arguments for: {list(keywords)!r}", *args
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class InvalidParametersError(_KeywordsBaseException):
|
|
70
|
+
"""Parameters were positonal arguments without defaults or keyword arguments"""
|
|
71
|
+
|
|
72
|
+
def __init__(self, keywords: set[str], *args):
|
|
73
|
+
super().__init__(
|
|
74
|
+
keywords,
|
|
75
|
+
f"Arguments :{list(keywords)!r} should not be positional",
|
|
76
|
+
*args,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class deprecated_params:
|
|
81
|
+
"""
|
|
82
|
+
A Wrapper inspired by python's wrapper deprecated from 3.13
|
|
83
|
+
and is used to deprecate parameters
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
def __init__(
|
|
87
|
+
self,
|
|
88
|
+
params: Sequence[str],
|
|
89
|
+
message: str | Mapping[str, str] = "is deprecated",
|
|
90
|
+
/,
|
|
91
|
+
*,
|
|
92
|
+
# default_message should be utilized when a keyword isn't
|
|
93
|
+
# given in message if messaged is defined as a dictionary.
|
|
94
|
+
default_message: str | None = None,
|
|
95
|
+
category: type[Warning] | None = DeprecationWarning,
|
|
96
|
+
stacklevel: int = 3,
|
|
97
|
+
display_kw: bool = True,
|
|
98
|
+
):
|
|
99
|
+
if not isinstance(message, (str, dict, Mapping)):
|
|
100
|
+
raise TypeError(
|
|
101
|
+
f"Expected an object of type str or dict or Mappable type for 'message', not {type(message).__name__!r}"
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
self.params = set(params)
|
|
105
|
+
self.message = message or "is deprecated"
|
|
106
|
+
self.message_is_dict = isinstance(message, (Mapping, dict))
|
|
107
|
+
self.display_kw = display_kw
|
|
108
|
+
self.category = category
|
|
109
|
+
self.stacklevel = stacklevel
|
|
110
|
+
self.default_message = default_message or "do not use"
|
|
111
|
+
|
|
112
|
+
def __check_with_missing(
|
|
113
|
+
self,
|
|
114
|
+
fn,
|
|
115
|
+
missing: set[str] | None = None,
|
|
116
|
+
invalid_params: set[str] | None = None,
|
|
117
|
+
skip_missing: bool | None = None,
|
|
118
|
+
allow_miss: bool = False,
|
|
119
|
+
):
|
|
120
|
+
sig = inspect.signature(fn)
|
|
121
|
+
|
|
122
|
+
missing = missing if missing is not None else set(self.params)
|
|
123
|
+
invalid_params = set() if invalid_params is None else invalid_params
|
|
124
|
+
|
|
125
|
+
skip_missing = (
|
|
126
|
+
any([p.kind == VAR_KEYWORD for p in sig.parameters.values()])
|
|
127
|
+
if skip_missing is None
|
|
128
|
+
else skip_missing
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
for m in self.params:
|
|
132
|
+
if not allow_miss:
|
|
133
|
+
p = sig.parameters[m]
|
|
134
|
+
else:
|
|
135
|
+
p = sig.parameters.get(m) # type: ignore
|
|
136
|
+
if p is None:
|
|
137
|
+
continue
|
|
138
|
+
print(p.kind, p.name)
|
|
139
|
+
# Check if were keyword only or aren't carrying a default param
|
|
140
|
+
if p.kind != KEYWORD_ONLY:
|
|
141
|
+
# Anything this isn't a keyword should be considered as deprecated
|
|
142
|
+
# as were still technically using it.
|
|
143
|
+
invalid_params.add(p.name)
|
|
144
|
+
|
|
145
|
+
if not skip_missing:
|
|
146
|
+
missing.remove(p.name)
|
|
147
|
+
|
|
148
|
+
return missing, invalid_params, skip_missing
|
|
149
|
+
|
|
150
|
+
def __check_for_missing_kwds(
|
|
151
|
+
self,
|
|
152
|
+
fn,
|
|
153
|
+
missing: set[str] | None = None,
|
|
154
|
+
invalid_params: set[str] | None = None,
|
|
155
|
+
skip_missing: bool | None = None,
|
|
156
|
+
allow_miss: bool = False,
|
|
157
|
+
):
|
|
158
|
+
# copy sequence to check for missing parameter names
|
|
159
|
+
missing, invalid_params, skip_missing = self.__check_with_missing(
|
|
160
|
+
fn, missing, invalid_params, skip_missing, allow_miss
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
if invalid_params:
|
|
164
|
+
raise InvalidParametersError(invalid_params)
|
|
165
|
+
|
|
166
|
+
if missing and not skip_missing:
|
|
167
|
+
raise MissingKeywordsError(missing)
|
|
168
|
+
|
|
169
|
+
def __warn(self, kw_name: str):
|
|
170
|
+
msg = ""
|
|
171
|
+
if self.display_kw:
|
|
172
|
+
msg += 'Parameter "%s" ' % kw_name
|
|
173
|
+
|
|
174
|
+
if self.message_is_dict:
|
|
175
|
+
msg += self.message.get(kw_name, self.default_message) # type: ignore
|
|
176
|
+
else:
|
|
177
|
+
msg += self.message # type: ignore
|
|
178
|
+
|
|
179
|
+
warnings.warn(msg, self.category, stacklevel=self.stacklevel + 1)
|
|
180
|
+
|
|
181
|
+
@overload
|
|
182
|
+
def __call__(self, arg: type[_T]) -> type[_T]: ...
|
|
183
|
+
|
|
184
|
+
@overload
|
|
185
|
+
def __call__(self, arg: Callable[_P, _T]) -> Callable[_P, _T]: ...
|
|
186
|
+
|
|
187
|
+
# Mirrors python's deprecated wrapper with a few changes
|
|
188
|
+
def __call__(self, arg):
|
|
189
|
+
not_dispatched = self.params.copy()
|
|
190
|
+
|
|
191
|
+
@functools.wraps(not_dispatched)
|
|
192
|
+
def check_kw_arguments(kw: dict):
|
|
193
|
+
if not_dispatched:
|
|
194
|
+
for k in kw.keys():
|
|
195
|
+
print(k, not_dispatched)
|
|
196
|
+
if k in not_dispatched:
|
|
197
|
+
self.__warn(k)
|
|
198
|
+
# remove after so we don't repeat
|
|
199
|
+
not_dispatched.remove(k)
|
|
200
|
+
|
|
201
|
+
if isinstance(arg, type):
|
|
202
|
+
# NOTE: Combining init and new together is done to
|
|
203
|
+
# solve deprecation of both new_args and init_args
|
|
204
|
+
|
|
205
|
+
missing, invalid_params, skip_missing = self.__check_with_missing(
|
|
206
|
+
arg.__init__, allow_miss=True
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
original_new = arg.__new__
|
|
210
|
+
self.__check_for_missing_kwds(
|
|
211
|
+
original_new, missing, invalid_params, skip_missing, allow_miss=True
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
@functools.wraps(original_new)
|
|
215
|
+
def __new__(cls, /, *args, **kwargs):
|
|
216
|
+
check_kw_arguments(kwargs)
|
|
217
|
+
if original_new is not object.__new__:
|
|
218
|
+
return original_new(cls, *args, **kwargs)
|
|
219
|
+
# Python Comment: Mirrors a similar check in object.__new__.
|
|
220
|
+
elif cls.__init__ is object.__init__ and (args or kwargs):
|
|
221
|
+
raise TypeError(f"{cls.__name__}() takes no arguments")
|
|
222
|
+
else:
|
|
223
|
+
return original_new(cls)
|
|
224
|
+
|
|
225
|
+
arg.__new__ = staticmethod(__new__)
|
|
226
|
+
|
|
227
|
+
original_init_subclass = arg.__init_subclass__
|
|
228
|
+
# Python Comment: We need slightly different behavior if __init_subclass__
|
|
229
|
+
# is a bound method (likely if it was implemented in Python)
|
|
230
|
+
if isinstance(original_init_subclass, MethodType):
|
|
231
|
+
self.__check_for_missing_kwds(original_init_subclass)
|
|
232
|
+
|
|
233
|
+
original_init_subclass = original_init_subclass.__func__
|
|
234
|
+
|
|
235
|
+
@functools.wraps(original_init_subclass)
|
|
236
|
+
def __init_subclass__(*args, **kwargs):
|
|
237
|
+
check_kw_arguments(kwargs)
|
|
238
|
+
return original_init_subclass(*args, **kwargs)
|
|
239
|
+
|
|
240
|
+
arg.__init_subclass__ = classmethod(__init_subclass__)
|
|
241
|
+
# Python Comment: Or otherwise, which likely means it's a builtin such as
|
|
242
|
+
# object's implementation of __init_subclass__.
|
|
243
|
+
else:
|
|
244
|
+
|
|
245
|
+
@functools.wraps(original_init_subclass)
|
|
246
|
+
def __init_subclass__(*args, **kwargs):
|
|
247
|
+
check_kw_arguments(kwargs)
|
|
248
|
+
return original_init_subclass(*args, **kwargs)
|
|
249
|
+
|
|
250
|
+
arg.__init_subclass__ = __init_subclass__
|
|
251
|
+
|
|
252
|
+
return arg
|
|
253
|
+
|
|
254
|
+
elif callable(arg):
|
|
255
|
+
# Check for missing functon arguments
|
|
256
|
+
self.__check_for_missing_kwds(arg)
|
|
257
|
+
|
|
258
|
+
@functools.wraps(arg)
|
|
259
|
+
def wrapper(*args, **kwargs):
|
|
260
|
+
check_kw_arguments(kwargs)
|
|
261
|
+
return arg(*args, **kwargs)
|
|
262
|
+
|
|
263
|
+
if sys.version_info >= (3, 12):
|
|
264
|
+
if inspect.iscoroutinefunction(arg):
|
|
265
|
+
wrapper = inspect.markcoroutinefunction(wrapper)
|
|
266
|
+
|
|
267
|
+
return wrapper
|
|
268
|
+
|
|
269
|
+
else:
|
|
270
|
+
raise TypeError(
|
|
271
|
+
"@deprecated_params decorator with non-None category must be applied to "
|
|
272
|
+
f"a class or callable, not {arg!r}"
|
|
273
|
+
)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: deprecated-params
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A Wrapper for functions, class objects and methods for deprecating keyword parameters
|
|
5
|
+
Author: Vizonex
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Requires-Python: >=3.9
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: typing-extensions; python_version < "3.10"
|
|
11
|
+
Dynamic: license-file
|
|
12
|
+
|
|
13
|
+
# Deprecated Params
|
|
14
|
+
|
|
15
|
+
Inspired after python's warning.deprecated wrapper, deprecated_params is made to serve the single purpose of deprecating parameter names to warn users
|
|
16
|
+
about incoming changes as well as retaining typehinting.
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
## How to Deprecate Parameters
|
|
21
|
+
Parameters should be keyword arguments, not positional, Reason
|
|
22
|
+
for this implementation is that in theory you should've already
|
|
23
|
+
planned an alternative approch to an argument you wish
|
|
24
|
+
to deprecate.
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
from deprecated_params import deprecated_params
|
|
28
|
+
|
|
29
|
+
@deprecated_params(['x'])
|
|
30
|
+
def func(y, *, x:int = 0):
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
# DeprecationWarning: Parameter "x" is deprecated
|
|
34
|
+
func(None, x=20)
|
|
35
|
+
|
|
36
|
+
# NOTE: **kw is accepted but also you could put down more than one
|
|
37
|
+
# parameter if needed...
|
|
38
|
+
@deprecated_params(['foo'], {"foo":"foo was removed in ... don't use it"}, display_kw=False)
|
|
39
|
+
class MyClass:
|
|
40
|
+
def __init__(self, spam:object, **kw):
|
|
41
|
+
self.spam = spam
|
|
42
|
+
self.foo = kw.get("foo", None)
|
|
43
|
+
|
|
44
|
+
# DeprecationWarning: foo was removed in ... don't use it
|
|
45
|
+
mc = MyClass("spam", foo="X")
|
|
46
|
+
```
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
setup.py
|
|
5
|
+
deprecated_params/__init__.py
|
|
6
|
+
deprecated_params.egg-info/PKG-INFO
|
|
7
|
+
deprecated_params.egg-info/SOURCES.txt
|
|
8
|
+
deprecated_params.egg-info/dependency_links.txt
|
|
9
|
+
deprecated_params.egg-info/requires.txt
|
|
10
|
+
deprecated_params.egg-info/top_level.txt
|
|
11
|
+
tests/test_wrapper.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
deprecated_params
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools"]
|
|
3
|
+
|
|
4
|
+
[project]
|
|
5
|
+
name = "deprecated-params"
|
|
6
|
+
version = "0.1.0"
|
|
7
|
+
description = "A Wrapper for functions, class objects and methods for deprecating keyword parameters"
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
authors = [
|
|
10
|
+
{ name = "Vizonex" },
|
|
11
|
+
]
|
|
12
|
+
license = "MIT"
|
|
13
|
+
requires-python = ">=3.9"
|
|
14
|
+
dependencies = [
|
|
15
|
+
'typing-extensions; python_version<"3.10"'
|
|
16
|
+
]
|
|
17
|
+
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from deprecated_params import deprecated_params
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
# should carry w x y
|
|
6
|
+
def test_deprecated_param():
|
|
7
|
+
@deprecated_params(["x"], "is deprecated")
|
|
8
|
+
def my_func(w: int, *, x: int = None, y: int = None):
|
|
9
|
+
pass
|
|
10
|
+
|
|
11
|
+
with pytest.warns(DeprecationWarning, match='Parameter "x" is deprecated'):
|
|
12
|
+
my_func(0, x=0)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def test_class_wrapper_and_kw_display_disabled():
|
|
16
|
+
@deprecated_params(["foo"], "foo is deprecated", display_kw=False)
|
|
17
|
+
class MyClass:
|
|
18
|
+
def __init__(self, spam: object, *, foo: object = None):
|
|
19
|
+
self.spam = spam
|
|
20
|
+
self.foo = foo
|
|
21
|
+
|
|
22
|
+
mc = MyClass("spam")
|
|
23
|
+
assert mc.spam == "spam"
|
|
24
|
+
assert mc.foo == None
|
|
25
|
+
|
|
26
|
+
with pytest.warns(DeprecationWarning, match="foo is deprecated"):
|
|
27
|
+
MyClass("spam", foo="foo")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class TornadoWarning(DeprecationWarning):
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_dataclasses_with_wrapper_message_dicts_custom_warning():
|
|
35
|
+
from dataclasses import dataclass, field
|
|
36
|
+
|
|
37
|
+
@deprecated_params(
|
|
38
|
+
["foo"],
|
|
39
|
+
{"foo": "got foo", "spam": "got spam"},
|
|
40
|
+
display_kw=False,
|
|
41
|
+
category=TornadoWarning,
|
|
42
|
+
)
|
|
43
|
+
@dataclass
|
|
44
|
+
class Class:
|
|
45
|
+
foo: str | None = field(kw_only=True, default=None)
|
|
46
|
+
spam: str | None = field(kw_only=True, default=None)
|
|
47
|
+
|
|
48
|
+
with pytest.warns(TornadoWarning, match="got foo"):
|
|
49
|
+
Class(foo="foo")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
# TODO: Metaclasses...
|