summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_inspect.py
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2011-12-21 08:59:49 (GMT)
committerAntoine Pitrou <solipsis@pitrou.net>2011-12-21 08:59:49 (GMT)
commit12f65d1fefde68ae142b96075917012a61cb8abf (patch)
treec95cb03a5ada920abd3ca1ae6720ba1cfb201dda /Lib/test/test_inspect.py
parent501da61671f88032cfde9b81060ddd82d22bf8ec (diff)
parent86a8a9ae983b66ea218ccbb57d3e3a5cdf918e97 (diff)
downloadcpython-12f65d1fefde68ae142b96075917012a61cb8abf.zip
cpython-12f65d1fefde68ae142b96075917012a61cb8abf.tar.gz
cpython-12f65d1fefde68ae142b96075917012a61cb8abf.tar.bz2
Issue #1785: Fix inspect and pydoc with misbehaving descriptors.
Also fixes issue #13581: `help(type)` wouldn't display anything.
Diffstat (limited to 'Lib/test/test_inspect.py')
-rw-r--r--Lib/test/test_inspect.py79
1 files changed, 79 insertions, 0 deletions
diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py
index 7163103..17c9f40 100644
--- a/Lib/test/test_inspect.py
+++ b/Lib/test/test_inspect.py
@@ -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):