mirror of
https://github.com/python/cpython.git
synced 2025-08-04 00:48:58 +00:00
Issue #1785: Fix inspect and pydoc with misbehaving descriptors.
Also fixes issue #13581: `help(type)` wouldn't display anything.
This commit is contained in:
commit
12f65d1fef
4 changed files with 151 additions and 38 deletions
|
@ -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):
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue