@@ -404,10 +404,37 @@ def test_findsource_code_in_linecache(self):
404
404
self .assertEqual (inspect .findsource (co ), (lines ,0 ))
405
405
self .assertEqual (inspect .getsource (co ), lines [0 ])
406
406
407
+
408
+ class _BrokenDataDescriptor (object ):
409
+ """
410
+ A broken data descriptor. See bug #1785.
411
+ """
412
+ def __get__ (* args ):
413
+ raise AssertionError ("should not __get__ data descriptors" )
414
+
415
+ def __set__ (* args ):
416
+ raise RuntimeError
417
+
418
+ def __getattr__ (* args ):
419
+ raise AssertionError ("should not __getattr__ data descriptors" )
420
+
421
+
422
+ class _BrokenMethodDescriptor (object ):
423
+ """
424
+ A broken method descriptor. See bug #1785.
425
+ """
426
+ def __get__ (* args ):
427
+ raise AssertionError ("should not __get__ method descriptors" )
428
+
429
+ def __getattr__ (* args ):
430
+ raise AssertionError ("should not __getattr__ method descriptors" )
431
+
432
+
407
433
# Helper for testing classify_class_attrs.
408
434
def attrs_wo_objs (cls ):
409
435
return [t [:3 ] for t in inspect .classify_class_attrs (cls )]
410
436
437
+
411
438
class TestClassesAndFunctions (unittest .TestCase ):
412
439
def test_classic_mro (self ):
413
440
# Test classic-class method resolution order.
@@ -494,13 +521,18 @@ def m1(self): pass
494
521
495
522
datablob = '1'
496
523
524
+ dd = _BrokenDataDescriptor ()
525
+ md = _BrokenMethodDescriptor ()
526
+
497
527
attrs = attrs_wo_objs (A )
498
528
self .assertIn (('s' , 'static method' , A ), attrs , 'missing static method' )
499
529
self .assertIn (('c' , 'class method' , A ), attrs , 'missing class method' )
500
530
self .assertIn (('p' , 'property' , A ), attrs , 'missing property' )
501
531
self .assertIn (('m' , 'method' , A ), attrs , 'missing plain method' )
502
532
self .assertIn (('m1' , 'method' , A ), attrs , 'missing plain method' )
503
533
self .assertIn (('datablob' , 'data' , A ), attrs , 'missing data' )
534
+ self .assertIn (('md' , 'method' , A ), attrs , 'missing method descriptor' )
535
+ self .assertIn (('dd' , 'data' , A ), attrs , 'missing data descriptor' )
504
536
505
537
class B (A ):
506
538
def m (self ): pass
@@ -512,6 +544,8 @@ def m(self): pass
512
544
self .assertIn (('m' , 'method' , B ), attrs , 'missing plain method' )
513
545
self .assertIn (('m1' , 'method' , A ), attrs , 'missing plain method' )
514
546
self .assertIn (('datablob' , 'data' , A ), attrs , 'missing data' )
547
+ self .assertIn (('md' , 'method' , A ), attrs , 'missing method descriptor' )
548
+ self .assertIn (('dd' , 'data' , A ), attrs , 'missing data descriptor' )
515
549
516
550
517
551
class C (A ):
@@ -525,6 +559,8 @@ def c(self): pass
525
559
self .assertIn (('m' , 'method' , C ), attrs , 'missing plain method' )
526
560
self .assertIn (('m1' , 'method' , A ), attrs , 'missing plain method' )
527
561
self .assertIn (('datablob' , 'data' , A ), attrs , 'missing data' )
562
+ self .assertIn (('md' , 'method' , A ), attrs , 'missing method descriptor' )
563
+ self .assertIn (('dd' , 'data' , A ), attrs , 'missing data descriptor' )
528
564
529
565
class D (B , C ):
530
566
def m1 (self ): pass
@@ -539,6 +575,8 @@ def m1(self): pass
539
575
self .assertIn (('m' , 'method' , B ), attrs , 'missing plain method' )
540
576
self .assertIn (('m1' , 'method' , D ), attrs , 'missing plain method' )
541
577
self .assertIn (('datablob' , 'data' , A ), attrs , 'missing data' )
578
+ self .assertIn (('md' , 'method' , A ), attrs , 'missing method descriptor' )
579
+ self .assertIn (('dd' , 'data' , A ), attrs , 'missing data descriptor' )
542
580
543
581
544
582
def test_classify_oldstyle (self ):
@@ -554,6 +592,64 @@ def test_classify_newstyle(self):
554
592
"""
555
593
self ._classify_test (True )
556
594
595
+ def test_classify_builtin_types (self ):
596
+ # Simple sanity check that all built-in types can have their
597
+ # attributes classified.
598
+ for name in dir (__builtin__ ):
599
+ builtin = getattr (__builtin__ , name )
600
+ if isinstance (builtin , type ):
601
+ inspect .classify_class_attrs (builtin )
602
+
603
+ def test_getmembers_descriptors (self ):
604
+ # Old-style classes
605
+ class A :
606
+ dd = _BrokenDataDescriptor ()
607
+ md = _BrokenMethodDescriptor ()
608
+
609
+ self .assertEqual (inspect .getmembers (A , inspect .ismethoddescriptor ),
610
+ [('md' , A .__dict__ ['md' ])])
611
+ self .assertEqual (inspect .getmembers (A , inspect .isdatadescriptor ),
612
+ [('dd' , A .__dict__ ['dd' ])])
613
+
614
+ class B (A ):
615
+ pass
616
+
617
+ self .assertEqual (inspect .getmembers (B , inspect .ismethoddescriptor ),
618
+ [('md' , A .__dict__ ['md' ])])
619
+ self .assertEqual (inspect .getmembers (B , inspect .isdatadescriptor ),
620
+ [('dd' , A .__dict__ ['dd' ])])
621
+
622
+ # New-style classes
623
+ class A (object ):
624
+ dd = _BrokenDataDescriptor ()
625
+ md = _BrokenMethodDescriptor ()
626
+
627
+ def pred_wrapper (pred ):
628
+ # A quick'n'dirty way to discard standard attributes of new-style
629
+ # classes.
630
+ class Empty (object ):
631
+ pass
632
+ def wrapped (x ):
633
+ if hasattr (x , '__name__' ) and hasattr (Empty , x .__name__ ):
634
+ return False
635
+ return pred (x )
636
+ return wrapped
637
+
638
+ ismethoddescriptor = pred_wrapper (inspect .ismethoddescriptor )
639
+ isdatadescriptor = pred_wrapper (inspect .isdatadescriptor )
640
+
641
+ self .assertEqual (inspect .getmembers (A , ismethoddescriptor ),
642
+ [('md' , A .__dict__ ['md' ])])
643
+ self .assertEqual (inspect .getmembers (A , isdatadescriptor ),
644
+ [('dd' , A .__dict__ ['dd' ])])
645
+
646
+ class B (A ):
647
+ pass
648
+
649
+ self .assertEqual (inspect .getmembers (B , ismethoddescriptor ),
650
+ [('md' , A .__dict__ ['md' ])])
651
+ self .assertEqual (inspect .getmembers (B , isdatadescriptor ),
652
+ [('dd' , A .__dict__ ['dd' ])])
557
653
558
654
559
655
class TestGetcallargsFunctions (unittest .TestCase ):
0 commit comments