Revert part of 13f56cd8dec1 (issue #1785) to avoid breaking getmembers() with unbound methods.

Python 3 isn't affected (unbound methods don't exist).
Thanks to Vincent Pelletier for noticing.
This commit is contained in:
Antoine Pitrou 2012-01-18 17:39:01 +01:00
parent a8f75da8f2
commit e09bc1e8f5
2 changed files with 22 additions and 59 deletions

View file

@ -247,23 +247,12 @@ def isabstract(object):
def getmembers(object, predicate=None): def getmembers(object, predicate=None):
"""Return all members of an object as (name, value) pairs sorted by name. """Return all members of an object as (name, value) pairs sorted by name.
Optionally, only return members that satisfy a given predicate.""" Optionally, only return members that satisfy a given predicate."""
if isclass(object):
mro = (object,) + getmro(object)
else:
mro = ()
results = [] results = []
for key in dir(object): for key in dir(object):
# First try to get the value via __dict__. Some descriptors don't try:
# like calling their __get__ (see bug #1785). value = getattr(object, key)
for base in mro: except AttributeError:
if key in base.__dict__: continue
value = base.__dict__[key]
break
else:
try:
value = getattr(object, key)
except AttributeError:
continue
if not predicate or predicate(value): if not predicate or predicate(value):
results.append((key, value)) results.append((key, value))
results.sort() results.sort()

View file

@ -600,56 +600,30 @@ class TestClassesAndFunctions(unittest.TestCase):
if isinstance(builtin, type): if isinstance(builtin, type):
inspect.classify_class_attrs(builtin) inspect.classify_class_attrs(builtin)
def test_getmembers_descriptors(self): def test_getmembers_method(self):
# Old-style classes # Old-style classes
class A: class B:
dd = _BrokenDataDescriptor() def f(self):
md = _BrokenMethodDescriptor() pass
self.assertEqual(inspect.getmembers(A, inspect.ismethoddescriptor), self.assertIn(('f', B.f), inspect.getmembers(B))
[('md', A.__dict__['md'])]) # contrary to spec, ismethod() is also True for unbound methods
self.assertEqual(inspect.getmembers(A, inspect.isdatadescriptor), # (see #1785)
[('dd', A.__dict__['dd'])]) self.assertIn(('f', B.f), inspect.getmembers(B, inspect.ismethod))
b = B()
class B(A): self.assertIn(('f', b.f), inspect.getmembers(b))
pass self.assertIn(('f', b.f), inspect.getmembers(b, inspect.ismethod))
self.assertEqual(inspect.getmembers(B, inspect.ismethoddescriptor),
[('md', A.__dict__['md'])])
self.assertEqual(inspect.getmembers(B, inspect.isdatadescriptor),
[('dd', A.__dict__['dd'])])
# New-style classes # New-style classes
class A(object): class B(object):
dd = _BrokenDataDescriptor() def f(self):
md = _BrokenMethodDescriptor()
def pred_wrapper(pred):
# A quick'n'dirty way to discard standard attributes of new-style
# classes.
class Empty(object):
pass pass
def wrapped(x):
if hasattr(x, '__name__') and hasattr(Empty, x.__name__):
return False
return pred(x)
return wrapped
ismethoddescriptor = pred_wrapper(inspect.ismethoddescriptor) self.assertIn(('f', B.f), inspect.getmembers(B))
isdatadescriptor = pred_wrapper(inspect.isdatadescriptor) self.assertIn(('f', B.f), inspect.getmembers(B, inspect.ismethod))
b = B()
self.assertEqual(inspect.getmembers(A, ismethoddescriptor), self.assertIn(('f', b.f), inspect.getmembers(b))
[('md', A.__dict__['md'])]) self.assertIn(('f', b.f), inspect.getmembers(b, inspect.ismethod))
self.assertEqual(inspect.getmembers(A, isdatadescriptor),
[('dd', A.__dict__['dd'])])
class B(A):
pass
self.assertEqual(inspect.getmembers(B, ismethoddescriptor),
[('md', A.__dict__['md'])])
self.assertEqual(inspect.getmembers(B, isdatadescriptor),
[('dd', A.__dict__['dd'])])
class TestGetcallargsFunctions(unittest.TestCase): class TestGetcallargsFunctions(unittest.TestCase):