@@ -706,12 +706,162 @@ def _getAssertEqualParams(self, func, call_params_string, locs=None):
706706 locs = dict (locs or {}, inst = self .inst )
707707 return (func , 'inst,' + call_params_string , locs )
708708
709+
710+ class TestGetattrStatic (unittest .TestCase ):
711+
712+ def test_basic (self ):
713+ class Thing (object ):
714+ x = object ()
715+
716+ thing = Thing ()
717+ self .assertEqual (inspect .getattr_static (thing , 'x' ), Thing .x )
718+ self .assertEqual (inspect .getattr_static (thing , 'x' , None ), Thing .x )
719+ with self .assertRaises (AttributeError ):
720+ inspect .getattr_static (thing , 'y' )
721+
722+ self .assertEqual (inspect .getattr_static (thing , 'y' , 3 ), 3 )
723+
724+ def test_inherited (self ):
725+ class Thing (object ):
726+ x = object ()
727+ class OtherThing (Thing ):
728+ pass
729+
730+ something = OtherThing ()
731+ self .assertEqual (inspect .getattr_static (something , 'x' ), Thing .x )
732+
733+ def test_instance_attr (self ):
734+ class Thing (object ):
735+ x = 2
736+ def __init__ (self , x ):
737+ self .x = x
738+ thing = Thing (3 )
739+ self .assertEqual (inspect .getattr_static (thing , 'x' ), 3 )
740+ del thing .x
741+ self .assertEqual (inspect .getattr_static (thing , 'x' ), 2 )
742+
743+ def test_property (self ):
744+ class Thing (object ):
745+ @property
746+ def x (self ):
747+ raise AttributeError ("I'm pretending not to exist" )
748+ thing = Thing ()
749+ self .assertEqual (inspect .getattr_static (thing , 'x' ), Thing .x )
750+
751+ def test_descriptor (self ):
752+ class descriptor (object ):
753+ def __get__ (* _ ):
754+ raise AttributeError ("I'm pretending not to exist" )
755+ desc = descriptor ()
756+ class Thing (object ):
757+ x = desc
758+ thing = Thing ()
759+ self .assertEqual (inspect .getattr_static (thing , 'x' ), desc )
760+
761+ def test_classAttribute (self ):
762+ class Thing (object ):
763+ x = object ()
764+
765+ self .assertEqual (inspect .getattr_static (Thing , 'x' ), Thing .x )
766+
767+ def test_inherited_classattribute (self ):
768+ class Thing (object ):
769+ x = object ()
770+ class OtherThing (Thing ):
771+ pass
772+
773+ self .assertEqual (inspect .getattr_static (OtherThing , 'x' ), Thing .x )
774+
775+ def test_slots (self ):
776+ class Thing (object ):
777+ y = 'bar'
778+ __slots__ = ['x' ]
779+ def __init__ (self ):
780+ self .x = 'foo'
781+ thing = Thing ()
782+ self .assertEqual (inspect .getattr_static (thing , 'x' ), Thing .x )
783+ self .assertEqual (inspect .getattr_static (thing , 'y' ), 'bar' )
784+
785+ del thing .x
786+ self .assertEqual (inspect .getattr_static (thing , 'x' ), Thing .x )
787+
788+ def test_metaclass (self ):
789+ class meta (type ):
790+ attr = 'foo'
791+ class Thing (object , metaclass = meta ):
792+ pass
793+ self .assertEqual (inspect .getattr_static (Thing , 'attr' ), 'foo' )
794+
795+ class sub (meta ):
796+ pass
797+ class OtherThing (object , metaclass = sub ):
798+ x = 3
799+ self .assertEqual (inspect .getattr_static (OtherThing , 'attr' ), 'foo' )
800+
801+ class OtherOtherThing (OtherThing ):
802+ pass
803+ # this test is odd, but it was added as it exposed a bug
804+ self .assertEqual (inspect .getattr_static (OtherOtherThing , 'x' ), 3 )
805+
806+ def test_no_dict_no_slots (self ):
807+ self .assertEqual (inspect .getattr_static (1 , 'foo' , None ), None )
808+ self .assertNotEqual (inspect .getattr_static ('foo' , 'lower' ), None )
809+
810+ def test_no_dict_no_slots_instance_member (self ):
811+ # returns descriptor
812+ with open (__file__ ) as handle :
813+ self .assertEqual (inspect .getattr_static (handle , 'name' ), type (handle ).name )
814+
815+ def test_inherited_slots (self ):
816+ # returns descriptor
817+ class Thing (object ):
818+ __slots__ = ['x' ]
819+ def __init__ (self ):
820+ self .x = 'foo'
821+
822+ class OtherThing (Thing ):
823+ pass
824+ # it would be nice if this worked...
825+ # we get the descriptor instead of the instance attribute
826+ self .assertEqual (inspect .getattr_static (OtherThing (), 'x' ), Thing .x )
827+
828+ def test_descriptor (self ):
829+ class descriptor (object ):
830+ def __get__ (self , instance , owner ):
831+ return 3
832+ class Foo (object ):
833+ d = descriptor ()
834+
835+ foo = Foo ()
836+
837+ # for a non data descriptor we return the instance attribute
838+ foo .__dict__ ['d' ] = 1
839+ self .assertEqual (inspect .getattr_static (foo , 'd' ), 1 )
840+
841+ # if the descriptor is a data-desciptor we should return the
842+ # descriptor
843+ descriptor .__set__ = lambda s , i , v : None
844+ self .assertEqual (inspect .getattr_static (foo , 'd' ), Foo .__dict__ ['d' ])
845+
846+
847+ def test_metaclass_with_descriptor (self ):
848+ class descriptor (object ):
849+ def __get__ (self , instance , owner ):
850+ return 3
851+ class meta (type ):
852+ d = descriptor ()
853+ class Thing (object , metaclass = meta ):
854+ pass
855+ self .assertEqual (inspect .getattr_static (Thing , 'd' ), meta .__dict__ ['d' ])
856+
857+
709858def test_main ():
710859 run_unittest (
711860 TestDecorators , TestRetrievingSourceCode , TestOneliners , TestBuggyCases ,
712861 TestInterpreterStack , TestClassesAndFunctions , TestPredicates ,
713862 TestGetcallargsFunctions , TestGetcallargsMethods ,
714- TestGetcallargsUnboundMethods )
863+ TestGetcallargsUnboundMethods , TestGetattrStatic
864+ )
715865
716866if __name__ == "__main__" :
717867 test_main ()
0 commit comments