@@ -126,7 +126,6 @@ def __getattr__(self, attr):
126126 def test_get_slot_members (self ):
127127 class C (object ):
128128 __slots__ = ("a" , "b" )
129-
130129 x = C ()
131130 x .a = 42
132131 members = dict (inspect .getmembers (x ))
@@ -469,24 +468,24 @@ class _BrokenDataDescriptor(object):
469468 A broken data descriptor. See bug #1785.
470469 """
471470 def __get__ (* args ):
472- raise AssertionError ( "should not __get__ data descriptors " )
471+ raise AttributeError ( "broken data descriptor " )
473472
474473 def __set__ (* args ):
475474 raise RuntimeError
476475
477476 def __getattr__ (* args ):
478- raise AssertionError ( "should not __getattr__ data descriptors " )
477+ raise AttributeError ( "broken data descriptor " )
479478
480479
481480class _BrokenMethodDescriptor (object ):
482481 """
483482 A broken method descriptor. See bug #1785.
484483 """
485484 def __get__ (* args ):
486- raise AssertionError ( "should not __get__ method descriptors " )
485+ raise AttributeError ( "broken method descriptor " )
487486
488487 def __getattr__ (* args ):
489- raise AssertionError ( "should not __getattr__ method descriptors " )
488+ raise AttributeError ( "broken method descriptor " )
490489
491490
492491# Helper for testing classify_class_attrs.
@@ -656,13 +655,77 @@ def test_classify_builtin_types(self):
656655 if isinstance (builtin , type ):
657656 inspect .classify_class_attrs (builtin )
658657
659- def test_classify_VirtualAttribute (self ):
660- class VA :
658+ def test_classify_DynamicClassAttribute (self ):
659+ class Meta (type ):
660+ def __getattr__ (self , name ):
661+ if name == 'ham' :
662+ return 'spam'
663+ return super ().__getattr__ (name )
664+ class VA (metaclass = Meta ):
661665 @types .DynamicClassAttribute
662666 def ham (self ):
663667 return 'eggs'
664- should_find = inspect .Attribute ('ham' , 'data' , VA , VA .__dict__ ['ham' ])
665- self .assertIn (should_find , inspect .classify_class_attrs (VA ))
668+ should_find_dca = inspect .Attribute ('ham' , 'data' , VA , VA .__dict__ ['ham' ])
669+ self .assertIn (should_find_dca , inspect .classify_class_attrs (VA ))
670+ should_find_ga = inspect .Attribute ('ham' , 'data' , VA , 'spam' )
671+ self .assertIn (should_find_ga , inspect .classify_class_attrs (VA ))
672+
673+ def test_classify_VirtualAttribute (self ):
674+ class Meta (type ):
675+ def __dir__ (cls ):
676+ return ['__class__' , '__module__' , '__name__' , 'BOOM' ]
677+ def __getattr__ (self , name ):
678+ if name == 'BOOM' :
679+ return 42
680+ return super ().__getattr (name )
681+ class Class (metaclass = Meta ):
682+ pass
683+ should_find = inspect .Attribute ('BOOM' , 'data' , Class , 42 )
684+ self .assertIn (should_find , inspect .classify_class_attrs (Class ))
685+
686+ def test_classify_VirtualAttribute_multi_classes (self ):
687+ class Meta1 (type ):
688+ def __dir__ (cls ):
689+ return ['__class__' , '__module__' , '__name__' , 'one' ]
690+ def __getattr__ (self , name ):
691+ if name == 'one' :
692+ return 1
693+ return super ().__getattr__ (name )
694+ class Meta2 (type ):
695+ def __dir__ (cls ):
696+ return ['__class__' , '__module__' , '__name__' , 'two' ]
697+ def __getattr__ (self , name ):
698+ if name == 'two' :
699+ return 2
700+ return super ().__getattr__ (name )
701+ class Meta3 (Meta1 , Meta2 ):
702+ def __dir__ (cls ):
703+ return list (sorted (set (['__class__' , '__module__' , '__name__' , 'three' ] +
704+ Meta1 .__dir__ (cls ) + Meta2 .__dir__ (cls ))))
705+ def __getattr__ (self , name ):
706+ if name == 'three' :
707+ return 3
708+ return super ().__getattr__ (name )
709+ class Class1 (metaclass = Meta1 ):
710+ pass
711+ class Class2 (Class1 , metaclass = Meta3 ):
712+ pass
713+
714+ should_find1 = inspect .Attribute ('one' , 'data' , Class1 , 1 )
715+ should_find2 = inspect .Attribute ('two' , 'data' , Class2 , 2 )
716+ should_find3 = inspect .Attribute ('three' , 'data' , Class2 , 3 )
717+ cca = inspect .classify_class_attrs (Class2 )
718+ for sf in (should_find1 , should_find2 , should_find3 ):
719+ self .assertIn (sf , cca )
720+
721+ def test_classify_class_attrs_with_buggy_dir (self ):
722+ class M (type ):
723+ def __dir__ (cls ):
724+ return ['__class__' , '__name__' , 'missing' ]
725+ class C (metaclass = M ):
726+ pass
727+ attrs = [a [0 ] for a in inspect .classify_class_attrs (C )]
728+ self .assertNotIn ('missing' , attrs )
666729
667730 def test_getmembers_descriptors (self ):
668731 class A (object ):
@@ -708,11 +771,26 @@ def f(self):
708771 self .assertIn (('f' , b .f ), inspect .getmembers (b , inspect .ismethod ))
709772
710773 def test_getmembers_VirtualAttribute (self ):
711- class A :
774+ class M (type ):
775+ def __getattr__ (cls , name ):
776+ if name == 'eggs' :
777+ return 'scrambled'
778+ return super ().__getattr__ (name )
779+ class A (metaclass = M ):
712780 @types .DynamicClassAttribute
713781 def eggs (self ):
714782 return 'spam'
715- self .assertIn (('eggs' , A .__dict__ ['eggs' ]), inspect .getmembers (A ))
783+ self .assertIn (('eggs' , 'scrambled' ), inspect .getmembers (A ))
784+ self .assertIn (('eggs' , 'spam' ), inspect .getmembers (A ()))
785+
786+ def test_getmembers_with_buggy_dir (self ):
787+ class M (type ):
788+ def __dir__ (cls ):
789+ return ['__class__' , '__name__' , 'missing' ]
790+ class C (metaclass = M ):
791+ pass
792+ attrs = [a [0 ] for a in inspect .getmembers (C )]
793+ self .assertNotIn ('missing' , attrs )
716794
717795
718796_global_ref = object ()
0 commit comments