@@ -651,3 +651,73 @@ def test_check_shape(target, test_shape):
651
651
with pytest .raises (ValueError ,
652
652
match = error_pattern ):
653
653
cbook ._check_shape (target , aardvark = data )
654
+
655
+
656
+ def test_setattr_cm ():
657
+ class A :
658
+
659
+ cls_level = object ()
660
+ override = object ()
661
+ def __init__ (self ):
662
+ self .aardvark = 'aardvark'
663
+ self .override = 'override'
664
+ self ._p = 'p'
665
+
666
+ def meth (self ):
667
+ ...
668
+
669
+ @property
670
+ def prop (self ):
671
+ return self ._p
672
+
673
+ @prop .setter
674
+ def prop (self , val ):
675
+ self ._p = val
676
+
677
+ class B (A ):
678
+ ...
679
+
680
+ other = A ()
681
+
682
+ def verify_pre_post_state (obj ):
683
+ # When you access a Python method the function is bound
684
+ # to the object at access time so you get a new instance
685
+ # of MethodType every time.
686
+ #
687
+ # https://docs.python.org/3/howto/descriptor.html#functions-and-methods
688
+ assert obj .meth is not obj .meth
689
+ # normal attribute should give you back the same instance every time
690
+ assert obj .aardvark is obj .aardvark
691
+ assert a .aardvark == 'aardvark'
692
+ # and our property happens to give the same instance every time
693
+ assert obj .prop is obj .prop
694
+ assert obj .cls_level is A .cls_level
695
+ assert obj .override == 'override'
696
+ assert not hasattr (obj , 'extra' )
697
+ assert obj .prop == 'p'
698
+ assert obj .monkey == other .meth
699
+
700
+ a = B ()
701
+
702
+ a .monkey = other .meth
703
+ verify_pre_post_state (a )
704
+ with cbook ._setattr_cm (
705
+ a , prop = 'squirrel' ,
706
+ aardvark = 'moose' , meth = lambda : None ,
707
+ override = 'boo' , extra = 'extra' ,
708
+ monkey = lambda : None ):
709
+ # because we have set a lambda, it is normal attribute access
710
+ # and the same every time
711
+ assert a .meth is a .meth
712
+ assert a .aardvark is a .aardvark
713
+ assert a .aardvark == 'moose'
714
+ assert a .override == 'boo'
715
+ assert a .extra == 'extra'
716
+ assert a .prop == 'squirrel'
717
+ assert a .monkey != other .meth
718
+
719
+ verify_pre_post_state (a )
720
+
721
+ with pytest .raises (ValueError ):
722
+ with cbook ._setattr_cm (a , cls_level = 'bob' ):
723
+ pass
0 commit comments