From 8f56c90309db2353470a03650ee56cec5215ed44 Mon Sep 17 00:00:00 2001 From: Laurent Peuch Date: Thu, 16 Apr 2020 03:56:24 +0200 Subject: add depreciation.attribute_renamed --- logilab/common/deprecation.py | 45 +++++++++++++++++++++++++++++++++++++++++++ test/unittest_deprecation.py | 22 +++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/logilab/common/deprecation.py b/logilab/common/deprecation.py index 3cfdff0..d45424d 100644 --- a/logilab/common/deprecation.py +++ b/logilab/common/deprecation.py @@ -190,6 +190,51 @@ def moved(modpath, objname): moved.__doc__ = _defaultdeprecator.moved.__doc__ +def attribute_renamed(old_name, new_name): + """ + class decorator to allow getting backward compatibility for renamed attributes. + + >>> @attribute_renamed(old_name="old", new_name="new") + ... class SomeClass: + ... def __init__(self): + ... self.new = 42 + + >>> some_class = SomeClass() + >>> print(some_class.old) + sample.py:15: DeprecationWarning: SomeClass.old has been renamed and is deprecated, use SomeClass.new instead + print(some_class.old) + 42 + >>> some_class.old = 43 + sample.py:16: DeprecationWarning: SomeClass.old has been renamed and is deprecated, use SomeClass.new instead + some_class.old = 43 + >>> some_class.old == some_class.new + True + """ + def _class_wrap(klass): + reason = ( + f"{klass.__name__}.{old_name} has been renamed and is deprecated, use " + f"{klass.__name__}.{new_name} instead" + ) + + def _get_old(self): + warn(reason, DeprecationWarning, stacklevel=2) + return getattr(self, new_name) + + def _set_old(self, value): + warn(reason, DeprecationWarning, stacklevel=2) + setattr(self, new_name, value) + + def _del_old(self): + warn(reason, DeprecationWarning, stacklevel=2) + delattr(self, new_name) + + setattr(klass, old_name, property(_get_old, _set_old, _del_old)) + + return klass + + return _class_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 d82c2bc..7778325 100644 --- a/test/unittest_deprecation.py +++ b/test/unittest_deprecation.py @@ -71,6 +71,28 @@ class RawInputTC(TestCase): self.assertEqual(self.messages, ['The function "any_func" is deprecated', 'message']) + def test_attribute_renamed(self): + @deprecation.attribute_renamed(old_name="old", new_name="new") + class SomeClass: + def __init__(self): + self.new = 42 + + some_class = SomeClass() + self.assertEqual(some_class.old, some_class.new) + self.assertEqual(self.messages, + ['SomeClass.old has been renamed and is deprecated, use SomeClass.new ' + 'instead']) + + some_class.old = 43 + self.assertEqual(some_class.old, 43) + self.assertEqual(some_class.old, some_class.new) + + self.assertTrue(hasattr(some_class, "new")) + self.assertTrue(hasattr(some_class, "old")) + del some_class.old + self.assertFalse(hasattr(some_class, "new")) + self.assertFalse(hasattr(some_class, "old")) + def test_renamed(self): def any_func(): pass -- cgit v1.2.1