Add a moved *instance* method deprecation pattern

When an instance method has moved to a better location (for
whatever reason) it is nice to provide the old instance method
under the previous name for a deprecation cycle. To enable
this kind of pattern use/modify/extend the existing moved decorator
to not just work for properties but also work for instance methods.

Change-Id: Ie002d9255d9e5127011c5308c7f5ce16d0b44821
This commit is contained in:
Joshua Harlow 2015-01-20 16:16:11 -08:00
parent b833207aaa
commit 31733373e1
2 changed files with 50 additions and 2 deletions

View File

@ -23,10 +23,12 @@ from debtcollector import _utils
_KIND_MOVED_PREFIX_TPL = "%s '%s' has moved to '%s'"
_CLASS_MOVED_PREFIX_TPL = "Class '%s' has moved to '%s'"
_MOVED_METHOD_POSTFIX = "()"
def _moved_decorator(kind, new_attribute_name, message=None,
version=None, removal_version=None, stacklevel=3):
version=None, removal_version=None, stacklevel=3,
attr_postfix=None):
"""Decorates a method/property that was moved to another location."""
def decorator(f):
@ -38,6 +40,9 @@ def _moved_decorator(kind, new_attribute_name, message=None,
old_attribute_name = f.__name__
fully_qualified = False
if attr_postfix:
old_attribute_name += attr_postfix
@six.wraps(f)
def wrapper(self, *args, **kwargs):
base_name = reflection.get_class_name(self, fully_qualified=False)
@ -58,10 +63,20 @@ def _moved_decorator(kind, new_attribute_name, message=None,
return decorator
def moved_method(new_method_name, message=None,
version=None, removal_version=None, stacklevel=3):
"""Decorates a *instance* method that was moved to another location."""
if not new_method_name.endswith(_MOVED_METHOD_POSTFIX):
new_method_name += _MOVED_METHOD_POSTFIX
return _moved_decorator('Method', new_method_name, message=message,
version=version, removal_version=removal_version,
stacklevel=stacklevel,
attr_postfix=_MOVED_METHOD_POSTFIX)
def moved_property(new_attribute_name, message=None,
version=None, removal_version=None, stacklevel=3):
"""Decorates a *instance* property that was moved to another location."""
return _moved_decorator('Property', new_attribute_name, message=message,
version=version, removal_version=removal_version,
stacklevel=stacklevel)

View File

@ -35,6 +35,16 @@ class WoofWoof(object):
return self.bark
class KittyKat(object):
@moves.moved_method('supermeow')
def meow(self):
return self.supermeow()
def supermeow(self):
return 'supermeow'
class NewHotness(object):
def hot(self):
return 'cold'
@ -94,6 +104,29 @@ class MovedPropertyTest(test_base.TestCase):
self.assertEqual(0, len(capture))
class MovedMethodTest(test_base.TestCase):
def test_basics(self):
c = KittyKat()
self.assertEqual('supermeow', c.meow())
self.assertEqual('supermeow', c.supermeow())
def test_warnings_emitted(self):
c = KittyKat()
with warnings.catch_warnings(record=True) as capture:
warnings.simplefilter("always")
self.assertEqual('supermeow', c.meow())
self.assertEqual(1, len(capture))
w = capture[0]
self.assertEqual(DeprecationWarning, w.category)
def test_warnings_not_emitted(self):
c = KittyKat()
with warnings.catch_warnings(record=True) as capture:
warnings.simplefilter("always")
self.assertEqual('supermeow', c.supermeow())
self.assertEqual(0, len(capture))
class RenamedKwargTest(test_base.TestCase):
def test_basics(self):
self.assertEqual((1, 1), blip_blop())