Issue #1785: Fix inspect and pydoc with misbehaving descriptors.

Also fixes issue #13581: `help(type)` wouldn't display anything.
This commit is contained in:
Antoine Pitrou 2011-12-21 09:59:49 +01:00
commit 12f65d1fef
4 changed files with 151 additions and 38 deletions

View file

@ -425,10 +425,37 @@ class TestNoEOL(GetSourceBase):
def test_class(self):
self.assertSourceEqual(self.fodderModule.X, 1, 2)
class _BrokenDataDescriptor(object):
"""
A broken data descriptor. See bug #1785.
"""
def __get__(*args):
raise AssertionError("should not __get__ data descriptors")
def __set__(*args):
raise RuntimeError
def __getattr__(*args):
raise AssertionError("should not __getattr__ data descriptors")
class _BrokenMethodDescriptor(object):
"""
A broken method descriptor. See bug #1785.
"""
def __get__(*args):
raise AssertionError("should not __get__ method descriptors")
def __getattr__(*args):
raise AssertionError("should not __getattr__ method descriptors")
# Helper for testing classify_class_attrs.
def attrs_wo_objs(cls):
return [t[:3] for t in inspect.classify_class_attrs(cls)]
class TestClassesAndFunctions(unittest.TestCase):
def test_newstyle_mro(self):
# The same w/ new-class MRO.
@ -525,6 +552,9 @@ class TestClassesAndFunctions(unittest.TestCase):
datablob = '1'
dd = _BrokenDataDescriptor()
md = _BrokenMethodDescriptor()
attrs = attrs_wo_objs(A)
self.assertIn(('s', 'static method', A), attrs, 'missing static method')
self.assertIn(('c', 'class method', A), attrs, 'missing class method')
@ -533,6 +563,8 @@ class TestClassesAndFunctions(unittest.TestCase):
'missing plain method: %r' % attrs)
self.assertIn(('m1', 'method', A), attrs, 'missing plain method')
self.assertIn(('datablob', 'data', A), attrs, 'missing data')
self.assertIn(('md', 'method', A), attrs, 'missing method descriptor')
self.assertIn(('dd', 'data', A), attrs, 'missing data descriptor')
class B(A):
@ -545,6 +577,8 @@ class TestClassesAndFunctions(unittest.TestCase):
self.assertIn(('m', 'method', B), attrs, 'missing plain method')
self.assertIn(('m1', 'method', A), attrs, 'missing plain method')
self.assertIn(('datablob', 'data', A), attrs, 'missing data')
self.assertIn(('md', 'method', A), attrs, 'missing method descriptor')
self.assertIn(('dd', 'data', A), attrs, 'missing data descriptor')
class C(A):
@ -559,6 +593,8 @@ class TestClassesAndFunctions(unittest.TestCase):
self.assertIn(('m', 'method', C), attrs, 'missing plain method')
self.assertIn(('m1', 'method', A), attrs, 'missing plain method')
self.assertIn(('datablob', 'data', A), attrs, 'missing data')
self.assertIn(('md', 'method', A), attrs, 'missing method descriptor')
self.assertIn(('dd', 'data', A), attrs, 'missing data descriptor')
class D(B, C):
@ -571,6 +607,49 @@ class TestClassesAndFunctions(unittest.TestCase):
self.assertIn(('m', 'method', B), attrs, 'missing plain method')
self.assertIn(('m1', 'method', D), attrs, 'missing plain method')
self.assertIn(('datablob', 'data', A), attrs, 'missing data')
self.assertIn(('md', 'method', A), attrs, 'missing method descriptor')
self.assertIn(('dd', 'data', A), attrs, 'missing data descriptor')
def test_classify_builtin_types(self):
# Simple sanity check that all built-in types can have their
# attributes classified.
for name in dir(__builtins__):
builtin = getattr(__builtins__, name)
if isinstance(builtin, type):
inspect.classify_class_attrs(builtin)
def test_getmembers_descriptors(self):
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):
pass
def wrapped(x):
if '__name__' in dir(x) 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'])])
class TestGetcallargsFunctions(unittest.TestCase):