From d26a1b969f632b5511bd72c82a36fbc92ecfdee5 Mon Sep 17 00:00:00 2001 From: Laurent Peuch Date: Thu, 16 Apr 2020 04:14:52 +0200 Subject: add depreciation.argument_renamed --- logilab/common/deprecation.py | 33 +++++++++++++++++++++++++++++++++ test/unittest_deprecation.py | 14 ++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/logilab/common/deprecation.py b/logilab/common/deprecation.py index d45424d..577aee7 100644 --- a/logilab/common/deprecation.py +++ b/logilab/common/deprecation.py @@ -235,6 +235,39 @@ def attribute_renamed(old_name, new_name): return _class_wrap +def argument_renamed(old_name, new_name): + """ + callable decorator to allow getting backward compatibility for renamed keyword arguments. + + >>> @argument_renamed(old_name="old", new_name="new") + ... def some_function(new): + ... return new + >>> some_function(old=42) + sample.py:15: DeprecationWarning: argument old of callable some_function has been renamed and is deprecated, use keyword argument new instead + some_function(old=42) + 42 + """ + def _wrap(func): + @wraps(func) + def check_kwargs(*args, **kwargs): + if old_name in kwargs and new_name in kwargs: + raise ValueError(f"argument {old_name} of callable {func.__name__} has been " + f"renamed to {new_name} but you are both using {old_name} and " + f"{new_name} has keyword arguments, only uses {new_name}") + + if old_name in kwargs: + warn(f"argument {old_name} of callable {func.__name__} has been renamed and is " + f"deprecated, use keyword argument {new_name} instead", stacklevel=2) + kwargs[new_name] = kwargs[old_name] + del kwargs[old_name] + + return func(*args, **kwargs) + + return check_kwargs + + return _wrap + + def renamed(old_name, new_function): """use to tell that a callable has been renamed. diff --git a/test/unittest_deprecation.py b/test/unittest_deprecation.py index 7778325..7881252 100644 --- a/test/unittest_deprecation.py +++ b/test/unittest_deprecation.py @@ -93,6 +93,20 @@ class RawInputTC(TestCase): self.assertFalse(hasattr(some_class, "new")) self.assertFalse(hasattr(some_class, "old")) + def test_argument_renamed(self): + @deprecation.argument_renamed(old_name="old", new_name="new") + def some_function(new): + return new + + self.assertEqual(some_function(new=42), 42) + self.assertEqual(some_function(old=42), 42) + self.assertEqual(self.messages, + ['argument old of callable some_function has been renamed and is ' + 'deprecated, use keyword argument new instead']) + + with self.assertRaises(ValueError): + some_function(new=42, old=42) + def test_renamed(self): def any_func(): pass -- cgit v1.2.1