@@ -425,10 +425,37 @@ def tearDown(self):
425425 def test_class (self ):
426426 self .assertSourceEqual (self .fodderModule .X , 1 , 2 )
427427
428+
429+ class _BrokenDataDescriptor (object ):
430+ """
431+ A broken data descriptor. See bug #1785.
432+ """
433+ def __get__ (* args ):
434+ raise AssertionError ("should not __get__ data descriptors" )
435+
436+ def __set__ (* args ):
437+ raise RuntimeError
438+
439+ def __getattr__ (* args ):
440+ raise AssertionError ("should not __getattr__ data descriptors" )
441+
442+
443+ class _BrokenMethodDescriptor (object ):
444+ """
445+ A broken method descriptor. See bug #1785.
446+ """
447+ def __get__ (* args ):
448+ raise AssertionError ("should not __get__ method descriptors" )
449+
450+ def __getattr__ (* args ):
451+ raise AssertionError ("should not __getattr__ method descriptors" )
452+
453+
428454# Helper for testing classify_class_attrs.
429455def attrs_wo_objs (cls ):
430456 return [t [:3 ] for t in inspect .classify_class_attrs (cls )]
431457
458+
432459class TestClassesAndFunctions (unittest .TestCase ):
433460 def test_newstyle_mro (self ):
434461 # The same w/ new-class MRO.
@@ -525,6 +552,9 @@ def m1(self): pass
525552
526553 datablob = '1'
527554
555+ dd = _BrokenDataDescriptor ()
556+ md = _BrokenMethodDescriptor ()
557+
528558 attrs = attrs_wo_objs (A )
529559 self .assertIn (('s' , 'static method' , A ), attrs , 'missing static method' )
530560 self .assertIn (('c' , 'class method' , A ), attrs , 'missing class method' )
@@ -533,6 +563,8 @@ def m1(self): pass
533563 'missing plain method: %r' % attrs )
534564 self .assertIn (('m1' , 'method' , A ), attrs , 'missing plain method' )
535565 self .assertIn (('datablob' , 'data' , A ), attrs , 'missing data' )
566+ self .assertIn (('md' , 'method' , A ), attrs , 'missing method descriptor' )
567+ self .assertIn (('dd' , 'data' , A ), attrs , 'missing data descriptor' )
536568
537569 class B (A ):
538570
@@ -545,6 +577,8 @@ def m(self): pass
545577 self .assertIn (('m' , 'method' , B ), attrs , 'missing plain method' )
546578 self .assertIn (('m1' , 'method' , A ), attrs , 'missing plain method' )
547579 self .assertIn (('datablob' , 'data' , A ), attrs , 'missing data' )
580+ self .assertIn (('md' , 'method' , A ), attrs , 'missing method descriptor' )
581+ self .assertIn (('dd' , 'data' , A ), attrs , 'missing data descriptor' )
548582
549583
550584 class C (A ):
@@ -559,6 +593,8 @@ def c(self): pass
559593 self .assertIn (('m' , 'method' , C ), attrs , 'missing plain method' )
560594 self .assertIn (('m1' , 'method' , A ), attrs , 'missing plain method' )
561595 self .assertIn (('datablob' , 'data' , A ), attrs , 'missing data' )
596+ self .assertIn (('md' , 'method' , A ), attrs , 'missing method descriptor' )
597+ self .assertIn (('dd' , 'data' , A ), attrs , 'missing data descriptor' )
562598
563599 class D (B , C ):
564600
@@ -571,6 +607,49 @@ def m1(self): pass
571607 self .assertIn (('m' , 'method' , B ), attrs , 'missing plain method' )
572608 self .assertIn (('m1' , 'method' , D ), attrs , 'missing plain method' )
573609 self .assertIn (('datablob' , 'data' , A ), attrs , 'missing data' )
610+ self .assertIn (('md' , 'method' , A ), attrs , 'missing method descriptor' )
611+ self .assertIn (('dd' , 'data' , A ), attrs , 'missing data descriptor' )
612+
613+ def test_classify_builtin_types (self ):
614+ # Simple sanity check that all built-in types can have their
615+ # attributes classified.
616+ for name in dir (__builtins__ ):
617+ builtin = getattr (__builtins__ , name )
618+ if isinstance (builtin , type ):
619+ inspect .classify_class_attrs (builtin )
620+
621+ def test_getmembers_descriptors (self ):
622+ class A (object ):
623+ dd = _BrokenDataDescriptor ()
624+ md = _BrokenMethodDescriptor ()
625+
626+ def pred_wrapper (pred ):
627+ # A quick'n'dirty way to discard standard attributes of new-style
628+ # classes.
629+ class Empty (object ):
630+ pass
631+ def wrapped (x ):
632+ if '__name__' in dir (x ) and hasattr (Empty , x .__name__ ):
633+ return False
634+ return pred (x )
635+ return wrapped
636+
637+ ismethoddescriptor = pred_wrapper (inspect .ismethoddescriptor )
638+ isdatadescriptor = pred_wrapper (inspect .isdatadescriptor )
639+
640+ self .assertEqual (inspect .getmembers (A , ismethoddescriptor ),
641+ [('md' , A .__dict__ ['md' ])])
642+ self .assertEqual (inspect .getmembers (A , isdatadescriptor ),
643+ [('dd' , A .__dict__ ['dd' ])])
644+
645+ class B (A ):
646+ pass
647+
648+ self .assertEqual (inspect .getmembers (B , ismethoddescriptor ),
649+ [('md' , A .__dict__ ['md' ])])
650+ self .assertEqual (inspect .getmembers (B , isdatadescriptor ),
651+ [('dd' , A .__dict__ ['dd' ])])
652+
574653
575654class TestGetcallargsFunctions (unittest .TestCase ):
576655
0 commit comments