Merge "Use __qualname__ where appropriate"

This commit is contained in:
Jenkins
2014-09-03 10:34:31 +00:00
committed by Gerrit Code Review
2 changed files with 105 additions and 17 deletions

View File

@@ -19,6 +19,9 @@ import functools
import inspect
import sys
import six
import testtools
from taskflow import states
from taskflow import test
from taskflow.tests import utils as test_utils
@@ -111,17 +114,22 @@ class GetCallableNameTest(test.TestCase):
def test_method(self):
name = reflection.get_callable_name(Class.method)
self.assertEqual(name, '.'.join((__name__, 'method')))
self.assertEqual(name, '.'.join((__name__, 'Class', 'method')))
def test_instance_method(self):
name = reflection.get_callable_name(Class().method)
self.assertEqual(name, '.'.join((__name__, 'Class', 'method')))
def test_static_method(self):
# NOTE(imelnikov): static method are just functions, class name
# is not recorded anywhere in them.
name = reflection.get_callable_name(Class.static_method)
self.assertEqual(name, '.'.join((__name__, 'static_method')))
if six.PY3:
self.assertEqual(name,
'.'.join((__name__, 'Class', 'static_method')))
else:
# NOTE(imelnikov): static method are just functions, class name
# is not recorded anywhere in them.
self.assertEqual(name,
'.'.join((__name__, 'static_method')))
def test_class_method(self):
name = reflection.get_callable_name(Class.class_method)
@@ -141,6 +149,46 @@ class GetCallableNameTest(test.TestCase):
'__call__')))
# These extended/special case tests only work on python 3, due to python 2
# being broken/incorrect with regard to these special cases...
@testtools.skipIf(not six.PY3, 'python 3.x is not currently available')
class GetCallableNameTestExtended(test.TestCase):
# Tests items in http://legacy.python.org/dev/peps/pep-3155/
class InnerCallableClass(object):
def __call__(self):
pass
def test_inner_callable_class(self):
obj = self.InnerCallableClass()
name = reflection.get_callable_name(obj.__call__)
expected_name = '.'.join((__name__, 'GetCallableNameTestExtended',
'InnerCallableClass', '__call__'))
self.assertEqual(expected_name, name)
def test_inner_callable_function(self):
def a():
def b():
pass
return b
name = reflection.get_callable_name(a())
expected_name = '.'.join((__name__, 'GetCallableNameTestExtended',
'test_inner_callable_function', '<locals>',
'a', '<locals>', 'b'))
self.assertEqual(expected_name, name)
def test_inner_class(self):
obj = self.InnerCallableClass()
name = reflection.get_callable_name(obj)
expected_name = '.'.join((__name__,
'GetCallableNameTestExtended',
'InnerCallableClass'))
self.assertEqual(expected_name, name)
class NotifierTest(test.TestCase):
def test_notify_called(self):

View File

@@ -21,6 +21,16 @@ import six
from taskflow.openstack.common import importutils
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__', 'exceptions')
def _get_members(obj, exclude_hidden):
"""Yields the members of an object, filtering by hidden/not hidden."""
@@ -86,12 +96,27 @@ def get_class_name(obj, fully_qualified=True):
"""
if not isinstance(obj, six.class_types):
obj = type(obj)
if obj.__module__ in ('builtins', '__builtin__', 'exceptions'):
return obj.__name__
if fully_qualified:
return '.'.join((obj.__module__, obj.__name__))
try:
built_in = obj.__module__ in _BUILTIN_MODULES
except AttributeError:
pass
else:
return obj.__name__
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_all_class_names(obj, up_to=object):
@@ -115,21 +140,36 @@ def get_callable_name(function):
"""
method_self = get_method_self(function)
if method_self is not None:
# this is bound method
# This is a bound method.
if isinstance(method_self, six.class_types):
# this is bound class method
# This is a bound class method.
im_class = method_self
else:
im_class = type(method_self)
parts = (im_class.__module__, im_class.__name__,
function.__name__)
elif inspect.isfunction(function) or inspect.ismethod(function):
parts = (function.__module__, function.__name__)
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:
if im_class is _TYPE_TYPE:
im_class = function
parts = (im_class.__module__, im_class.__name__)
try:
parts = (im_class.__module__, im_class.__qualname__)
except AttributeError:
parts = (im_class.__module__, im_class.__name__)
return '.'.join(parts)