From 8f4100aac7d2a6ef7b2945e55eeda1b913791126 Mon Sep 17 00:00:00 2001 From: Jamie Lennox Date: Tue, 26 May 2015 16:05:06 +1000 Subject: [PATCH] Remove oslo.utils dependency There are two reasons to remove oslo.utils: * oslo.utils brings in a number of dependencies that are not required by any debtcollector code paths. This is a concern for having debtcollector be adopted by libraries that want to maintain minimal external requirements. * oslo.utils now has a dependency on debtcollector. While this doesn't seem to cause any problems with pip it is a weird circular dependency that is best to break. Copy the required reflection methods from oslo.utils to debtcollector and the associated tests and remove the oslo.utils dependency. Change-Id: Id4d8f4f7466775d099ab1e82b38605e98e6d840d --- debtcollector/_utils.py | 97 +++++++++++++++++++++++++++++++++++++++ debtcollector/moves.py | 5 +- debtcollector/removals.py | 11 ++--- requirements.txt | 1 - 4 files changed, 104 insertions(+), 10 deletions(-) diff --git a/debtcollector/_utils.py b/debtcollector/_utils.py index 7d3d757..09334a1 100644 --- a/debtcollector/_utils.py +++ b/debtcollector/_utils.py @@ -14,8 +14,23 @@ # License for the specific language governing permissions and limitations # under the License. +import inspect +import types import warnings +import six + +try: + _TYPE_TYPE = types.TypeType +except AttributeError: + _TYPE_TYPE = type + + +# See: https://docs.python.org/2/library/__builtin__.html#module-__builtin__ +# and see https://docs.python.org/2/reference/executionmodel.html (and likely +# others)... +_BUILTIN_MODULES = ('builtins', '__builtin__', '__builtins__', 'exceptions') + def deprecation(message, stacklevel=None, category=None): """Warns about some type of deprecation that has been (or will be) made. @@ -68,3 +83,85 @@ def generate_message(prefix, postfix=None, message=None, if message: message_components.append(": %s" % message) return ''.join(message_components) + + +def get_class_name(obj, fully_qualified=True): + """Get class name for object. + + If object is a type, fully qualified name of the type is returned. + Else, fully qualified name of the type of the object is returned. + For builtin types, just name is returned. + """ + if not isinstance(obj, six.class_types): + obj = type(obj) + try: + built_in = obj.__module__ in _BUILTIN_MODULES + except AttributeError: + pass + else: + if built_in: + try: + return obj.__qualname__ + except AttributeError: + return obj.__name__ + pieces = [] + try: + pieces.append(obj.__qualname__) + except AttributeError: + pieces.append(obj.__name__) + if fully_qualified: + try: + pieces.insert(0, obj.__module__) + except AttributeError: + pass + return '.'.join(pieces) + + +def get_method_self(method): + """Gets the ``self`` object attached to this method (or none).""" + if not inspect.ismethod(method): + return None + try: + return six.get_method_self(method) + except AttributeError: + return None + + +def get_callable_name(function): + """Generate a name from callable. + + Tries to do the best to guess fully qualified callable name. + """ + method_self = get_method_self(function) + if method_self is not None: + # This is a bound method. + if isinstance(method_self, six.class_types): + # This is a bound class method. + im_class = method_self + else: + im_class = type(method_self) + try: + parts = (im_class.__module__, function.__qualname__) + except AttributeError: + parts = (im_class.__module__, im_class.__name__, function.__name__) + elif inspect.ismethod(function) or inspect.isfunction(function): + # This could be a function, a static method, a unbound method... + try: + parts = (function.__module__, function.__qualname__) + except AttributeError: + if hasattr(function, 'im_class'): + # This is a unbound method, which exists only in python 2.x + im_class = function.im_class + parts = (im_class.__module__, + im_class.__name__, function.__name__) + else: + parts = (function.__module__, function.__name__) + else: + im_class = type(function) + if im_class is _TYPE_TYPE: + im_class = function + try: + parts = (im_class.__module__, im_class.__qualname__) + except AttributeError: + parts = (im_class.__module__, im_class.__name__) + return '.'.join(parts) diff --git a/debtcollector/moves.py b/debtcollector/moves.py index df358d3..8899c09 100644 --- a/debtcollector/moves.py +++ b/debtcollector/moves.py @@ -16,7 +16,6 @@ import inspect -from oslo_utils import reflection import six from debtcollector import _utils @@ -38,7 +37,7 @@ def decorator(f): @six.wraps(f) def wrapper(self, *args, **kwargs): - base_name = reflection.get_class_name(self, fully_qualified=False) + base_name = _utils.get_class_name(self, fully_qualified=False) if fully_qualified: old_name = old_attribute_name else: @@ -96,7 +95,7 @@ def moved_class(new_class, old_class_name, old_module_name, " class type only)" % type_name) old_name = ".".join((old_module_name, old_class_name)) - new_name = reflection.get_class_name(new_class) + new_name = _utils.get_class_name(new_class) prefix = _CLASS_MOVED_PREFIX_TPL % (old_name, new_name) out_message = _utils.generate_message( prefix, message=message, version=version, diff --git a/debtcollector/removals.py b/debtcollector/removals.py index 4b4d6c1..6438acf 100644 --- a/debtcollector/removals.py +++ b/debtcollector/removals.py @@ -15,7 +15,6 @@ import functools import inspect -from oslo_utils import reflection import six import wrapt @@ -67,22 +66,22 @@ def wrapper(f, instance, args, kwargs): thing_post = '' module_name = _get_module_name(inspect.getmodule(f)) if module_name == '__main__': - f_name = reflection.get_class_name( + f_name = _utils.get_class_name( f, fully_qualified=False) else: - f_name = reflection.get_class_name( + f_name = _utils.get_class_name( f, fully_qualified=True) # Decorator was a used on a function else: thing_post = '()' module_name = _get_module_name(inspect.getmodule(f)) if module_name != '__main__': - f_name = reflection.get_callable_name(f) + f_name = _utils.get_callable_name(f) # Decorator was used on a classmethod or instancemethod else: thing_post = '()' - base_name = reflection.get_class_name(instance, - fully_qualified=False) + base_name = _utils.get_class_name(instance, + fully_qualified=False) if base_name: thing_name = ".".join([base_name, f_name]) else: diff --git a/requirements.txt b/requirements.txt index cc0be8e..34677f1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,5 +5,4 @@ pbr>=0.11,<2.0 Babel>=1.3 six>=1.9.0 -oslo.utils>=1.4.0 # Apache-2.0 wrapt>=1.7.0 # BSD License