diff --git a/debtcollector/_utils.py b/debtcollector/_utils.py index a7b3527..7d3d757 100644 --- a/debtcollector/_utils.py +++ b/debtcollector/_utils.py @@ -42,6 +42,14 @@ def deprecation(message, stacklevel=None, category=None): warnings.warn(message, category=category, stacklevel=stacklevel) +def get_qualified_name(obj): + # Prefer the py3.x name (if we can get at it...) + try: + return (True, obj.__qualname__) + except AttributeError: + return (False, obj.__name__) + + def generate_message(prefix, postfix=None, message=None, version=None, removal_version=None): """Helper to generate a common message 'style' for deprecation helpers.""" diff --git a/debtcollector/moves.py b/debtcollector/moves.py index 17f7368..df358d3 100644 --- a/debtcollector/moves.py +++ b/debtcollector/moves.py @@ -14,6 +14,8 @@ # License for the specific language governing permissions and limitations # under the License. +import inspect + from oslo_utils import reflection import six @@ -30,14 +32,7 @@ def _moved_decorator(kind, new_attribute_name, message=None, """Decorates a method/property that was moved to another location.""" def decorator(f): - try: - # Prefer the py3.x name (if we can get at it...) - old_attribute_name = f.__qualname__ - fully_qualified = True - except AttributeError: - old_attribute_name = f.__name__ - fully_qualified = False - + fully_qualified, old_attribute_name = _utils.get_qualified_name(f) if attr_postfix: old_attribute_name += attr_postfix @@ -95,6 +90,11 @@ def moved_class(new_class, old_class_name, old_module_name, improved location for the old class now is. """ + if not inspect.isclass(new_class): + _qual, type_name = _utils.get_qualified_name(type(new_class)) + raise TypeError("Unexpected class type '%s' (expected" + " class type only)" % type_name) + old_name = ".".join((old_module_name, old_class_name)) new_name = reflection.get_class_name(new_class) prefix = _CLASS_MOVED_PREFIX_TPL % (old_name, new_name) diff --git a/debtcollector/removals.py b/debtcollector/removals.py index 3ef314e..4b4d6c1 100644 --- a/debtcollector/removals.py +++ b/debtcollector/removals.py @@ -22,16 +22,8 @@ from debtcollector import _utils -def _get_qualified_name(obj): - # Prefer the py3.x name (if we can get at it...) - try: - return (True, obj.__qualname__) - except AttributeError: - return (False, obj.__name__) - - def _get_module_name(mod): - return _get_qualified_name(mod)[1] + return _utils.get_qualified_name(mod)[1] def remove(f=None, message=None, version=None, removal_version=None, @@ -57,7 +49,7 @@ def remove(f=None, message=None, version=None, removal_version=None, @wrapt.decorator def wrapper(f, instance, args, kwargs): - qualified, f_name = _get_qualified_name(f) + qualified, f_name = _utils.get_qualified_name(f) if qualified: if inspect.isclass(f): prefix_pre = "Using class" @@ -157,7 +149,7 @@ def removed_module(module, replacement=None, message=None, elif isinstance(module, six.string_types): module_name = module else: - _qual, type_name = _get_qualified_name(type(module)) + _qual, type_name = _utils.get_qualified_name(type(module)) raise TypeError("Unexpected module type '%s' (expected string or" " module type only)" % type_name) prefix = "The '%s' module usage is deprecated" % module_name diff --git a/debtcollector/tests/test_deprecation.py b/debtcollector/tests/test_deprecation.py index f46dd59..307f603 100644 --- a/debtcollector/tests/test_deprecation.py +++ b/debtcollector/tests/test_deprecation.py @@ -132,6 +132,9 @@ def green_giant(): class MovedInheritableClassTest(test_base.TestCase): + def test_broken_type_class(self): + self.assertRaises(TypeError, moves.moved_class, 'b', __name__) + def test_basics(self): old = OldHotness() self.assertIsInstance(old, NewHotness)