Skip to content

Commit 29e9ab3

Browse files
authored
471- fixes deprecated args (#3447)
* fixes deprecated args Signed-off-by: Wenqi Li <[email protected]> * update based on comments Signed-off-by: Wenqi Li <[email protected]>
1 parent 98c1c43 commit 29e9ab3

File tree

2 files changed

+53
-7
lines changed

2 files changed

+53
-7
lines changed

monai/utils/deprecate_utils.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
# limitations under the License.
1111

1212
import inspect
13+
import sys
1314
import warnings
1415
from functools import wraps
1516
from types import FunctionType
@@ -62,7 +63,7 @@ def deprecated(
6263

6364
# if version_val.startswith("0+"):
6465
# # version unknown, set version_val to a large value (assuming the latest version)
65-
# version_val = "100"
66+
# version_val = f"{sys.maxsize}"
6667
if since is not None and removed is not None and not version_leq(since, removed):
6768
raise ValueError(f"since must be less or equal to removed, got since={since}, removed={removed}.")
6869
is_not_yet_deprecated = since is not None and version_val != since and version_leq(version_val, since)
@@ -144,14 +145,16 @@ def deprecated_arg(
144145
msg_suffix: message appended to warning/exception detailing reasons for deprecation and what to use instead.
145146
version_val: (used for testing) version to compare since and removed against, default is MONAI version.
146147
new_name: name of position or keyword argument to replace the deprecated argument.
148+
if it is specified and the signature of the decorated function has a `kwargs`, the value to the
149+
deprecated argument `name` will be removed.
147150
148151
Returns:
149152
Decorated callable which warns or raises exception when deprecated argument used.
150153
"""
151154

152155
if version_val.startswith("0+") or not f"{version_val}".strip()[0].isdigit():
153156
# version unknown, set version_val to a large value (assuming the latest version)
154-
version_val = "100"
157+
version_val = f"{sys.maxsize}"
155158
if since is not None and removed is not None and not version_leq(since, removed):
156159
raise ValueError(f"since must be less or equal to removed, got since={since}, removed={removed}.")
157160
is_not_yet_deprecated = since is not None and version_val != since and version_leq(version_val, since)
@@ -197,9 +200,13 @@ def _wrapper(*args, **kwargs):
197200
# multiple values for new_name using both args and kwargs
198201
kwargs.pop(new_name, None)
199202
binding = sig.bind(*args, **kwargs).arguments
200-
201203
positional_found = name in binding
202-
kw_found = "kwargs" in binding and name in binding["kwargs"]
204+
kw_found = False
205+
for k, param in sig.parameters.items():
206+
if param.kind == inspect.Parameter.VAR_KEYWORD and k in binding and name in binding[k]:
207+
kw_found = True
208+
# if the deprecated arg is found in the **kwargs, it should be removed
209+
kwargs.pop(name, None)
203210

204211
if positional_found or kw_found:
205212
if is_removed:

tests/test_deprecated.py

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def test_warning(self):
2929
def foo2():
3030
pass
3131

32-
print(foo2())
32+
foo2() # should not raise any warnings
3333

3434
def test_warning_milestone(self):
3535
"""Test deprecated decorator with `since` and `removed` set for a milestone version"""
@@ -172,7 +172,7 @@ def test_arg_warn2(self):
172172
"""Test deprecated_arg decorator with just `since` set."""
173173

174174
@deprecated_arg("b", since=self.prev_version, version_val=self.test_version)
175-
def afoo2(a, **kwargs):
175+
def afoo2(a, **kw):
176176
pass
177177

178178
afoo2(1) # ok when no b provided
@@ -235,6 +235,19 @@ def afoo4(a, b=None):
235235

236236
self.assertRaises(DeprecatedError, lambda: afoo4(1, b=2))
237237

238+
def test_arg_except3_unknown(self):
239+
"""
240+
Test deprecated_arg decorator raises exception with `removed` set in the past.
241+
with unknown version and kwargs
242+
"""
243+
244+
@deprecated_arg("b", removed=self.prev_version, version_val="0+untagged.1.g3131155")
245+
def afoo4(a, b=None, **kwargs):
246+
pass
247+
248+
self.assertRaises(DeprecatedError, lambda: afoo4(1, b=2))
249+
self.assertRaises(DeprecatedError, lambda: afoo4(1, b=2, c=3))
250+
238251
def test_replacement_arg(self):
239252
"""
240253
Test deprecated arg being replaced.
@@ -245,10 +258,36 @@ def afoo4(a, b=None):
245258
return a
246259

247260
self.assertEqual(afoo4(b=2), 2)
248-
# self.assertRaises(DeprecatedError, lambda: afoo4(1, b=2))
249261
self.assertEqual(afoo4(1, b=2), 1) # new name is in use
250262
self.assertEqual(afoo4(a=1, b=2), 1) # prefers the new arg
251263

264+
def test_replacement_arg1(self):
265+
"""
266+
Test deprecated arg being replaced with kwargs.
267+
"""
268+
269+
@deprecated_arg("b", new_name="a", since=self.prev_version, version_val=self.test_version)
270+
def afoo4(a, *args, **kwargs):
271+
return a
272+
273+
self.assertEqual(afoo4(b=2), 2)
274+
self.assertEqual(afoo4(1, b=2, c=3), 1) # new name is in use
275+
self.assertEqual(afoo4(a=1, b=2, c=3), 1) # prefers the new arg
276+
277+
def test_replacement_arg2(self):
278+
"""
279+
Test deprecated arg (with a default value) being replaced.
280+
"""
281+
282+
@deprecated_arg("b", new_name="a", since=self.prev_version, version_val=self.test_version)
283+
def afoo4(a, b=None, **kwargs):
284+
return a, kwargs
285+
286+
self.assertEqual(afoo4(b=2, c=3), (2, {"c": 3}))
287+
self.assertEqual(afoo4(1, b=2, c=3), (1, {"c": 3})) # new name is in use
288+
self.assertEqual(afoo4(a=1, b=2, c=3), (1, {"c": 3})) # prefers the new arg
289+
self.assertEqual(afoo4(1, 2, c=3), (1, {"c": 3})) # prefers the new positional arg
290+
252291

253292
if __name__ == "__main__":
254293
unittest.main()

0 commit comments

Comments
 (0)