Allow get_class_name to accept bound method and class method

It is convenient in some cases like:
  if inspect.ismethod(callback):
    class_name = callback.__self__.__class__.__name__
    return [module_name, class_name, func_name]
  else:
    return [module_name, func_name]

The above code example from keystone [1]
[1] https://github.com/openstack/keystone/blob/master/keystone/notifications.py#L256

Change-Id: I4f90c70e8838a1fccb51856b461780ba5fce06d4
This commit is contained in:
ChangBo Guo(gcb) 2015-11-04 14:43:26 +08:00
parent 92712bdc3d
commit 3d42b05bce
2 changed files with 36 additions and 3 deletions

View File

@ -56,10 +56,19 @@ def get_member_names(obj, exclude_hidden=True):
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 object is a type, returns name of the type. If object is a bound
method or a class method, returns its ``self`` object's class name.
If object is an instance of class, returns instance's class name.
Else, name of the type of the object is returned. If fully_qualified
is True, returns fully qualified name of the type. For builtin types,
just name is returned. TypeError is raised if can't get class name from
object.
"""
if inspect.isfunction(obj):
raise TypeError("Can't get class name.")
if inspect.ismethod(obj):
obj = get_method_self(obj)
if not isinstance(obj, six.class_types):
obj = type(obj)
try:

View File

@ -321,6 +321,30 @@ class GetClassNameTest(test_base.BaseTestCase):
name = reflection.get_class_name(42)
self.assertEqual('int', name)
def test_class_method(self):
name = reflection.get_class_name(Class.class_method)
self.assertEqual('%s.Class' % __name__, name)
# test with fully_qualified=False
name = reflection.get_class_name(Class.class_method,
fully_qualified=False)
self.assertEqual('Class', name)
def test_static_method(self):
self.assertRaises(TypeError, reflection.get_class_name,
Class.static_method)
def test_unbound_method(self):
self.assertRaises(TypeError, reflection.get_class_name,
mere_function)
def test_bound_method(self):
c = Class()
name = reflection.get_class_name(c.method)
self.assertEqual('%s.Class' % __name__, name)
# test with fully_qualified=False
name = reflection.get_class_name(c.method, fully_qualified=False)
self.assertEqual('Class', name)
class GetAllClassNamesTest(test_base.BaseTestCase):