diff --git a/Lib/inspect.py b/Lib/inspect.py index cb07b9d9ab1..66d51865734 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -247,23 +247,12 @@ def isabstract(object): def getmembers(object, predicate=None): """Return all members of an object as (name, value) pairs sorted by name. Optionally, only return members that satisfy a given predicate.""" - if isclass(object): - mro = (object,) + getmro(object) - else: - mro = () results = [] for key in dir(object): - # First try to get the value via __dict__. Some descriptors don't - # like calling their __get__ (see bug #1785). - for base in mro: - if key in base.__dict__: - value = base.__dict__[key] - break - else: - try: - value = getattr(object, key) - except AttributeError: - continue + try: + value = getattr(object, key) + except AttributeError: + continue if not predicate or predicate(value): results.append((key, value)) results.sort() diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index 97de7a07286..30b1556cbfb 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -600,56 +600,30 @@ class TestClassesAndFunctions(unittest.TestCase): if isinstance(builtin, type): inspect.classify_class_attrs(builtin) - def test_getmembers_descriptors(self): + def test_getmembers_method(self): # Old-style classes - class A: - dd = _BrokenDataDescriptor() - md = _BrokenMethodDescriptor() + class B: + def f(self): + pass - self.assertEqual(inspect.getmembers(A, inspect.ismethoddescriptor), - [('md', A.__dict__['md'])]) - self.assertEqual(inspect.getmembers(A, inspect.isdatadescriptor), - [('dd', A.__dict__['dd'])]) - - class B(A): - pass - - self.assertEqual(inspect.getmembers(B, inspect.ismethoddescriptor), - [('md', A.__dict__['md'])]) - self.assertEqual(inspect.getmembers(B, inspect.isdatadescriptor), - [('dd', A.__dict__['dd'])]) + self.assertIn(('f', B.f), inspect.getmembers(B)) + # contrary to spec, ismethod() is also True for unbound methods + # (see #1785) + self.assertIn(('f', B.f), inspect.getmembers(B, inspect.ismethod)) + b = B() + self.assertIn(('f', b.f), inspect.getmembers(b)) + self.assertIn(('f', b.f), inspect.getmembers(b, inspect.ismethod)) # New-style classes - class A(object): - dd = _BrokenDataDescriptor() - md = _BrokenMethodDescriptor() - - def pred_wrapper(pred): - # A quick'n'dirty way to discard standard attributes of new-style - # classes. - class Empty(object): + class B(object): + def f(self): 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) - isdatadescriptor = pred_wrapper(inspect.isdatadescriptor) - - self.assertEqual(inspect.getmembers(A, ismethoddescriptor), - [('md', A.__dict__['md'])]) - 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'])]) + self.assertIn(('f', B.f), inspect.getmembers(B)) + self.assertIn(('f', B.f), inspect.getmembers(B, inspect.ismethod)) + b = B() + self.assertIn(('f', b.f), inspect.getmembers(b)) + self.assertIn(('f', b.f), inspect.getmembers(b, inspect.ismethod)) class TestGetcallargsFunctions(unittest.TestCase):