@@ -61,22 +61,20 @@ def smart_set(self, obj, attr_name, new_attr):
6161 This method supports the case where attr_name is a staticmethod or a
6262 classmethod of obj.
6363
64- Notes:
65- - If obj is an instance, then it is its class that will actually be
66- stubbed. Note that the method Set() does not do that: if obj is
67- an instance, it (and not its class) will be stubbed.
68- - The stubbing is using the builtin getattr and setattr. So, the
69- __get__ and __set__ will be called when stubbing (TODO: A better
70- idea would probably be to manipulate obj.__dict__ instead of
71- getattr() and setattr()).
64+ If obj is an instance, then it is its class that will actually be
65+ stubbed. Note that the method Set() does not do that: if obj is an
66+ instance, it (and not its class) will be stubbed.
7267
7368 Raises AttributeError if the attribute cannot be found.
7469 """
7570 if inspect .ismodule (obj ) or (
7671 not inspect .isclass (obj ) and attr_name in obj .__dict__
7772 ):
7873 orig_obj = obj
79- orig_attr = getattr (obj , attr_name )
74+ if attr_name in obj .__dict__ :
75+ orig_attr = obj .__dict__ [attr_name ]
76+ else :
77+ orig_attr = None
8078
8179 else :
8280 if not inspect .isclass (obj ):
@@ -91,21 +89,15 @@ def smart_set(self, obj, attr_name, new_attr):
9189 for cls in mro :
9290 try :
9391 orig_obj = cls
94- orig_attr = getattr ( obj , attr_name )
95- except AttributeError :
92+ orig_attr = obj . __dict__ [ attr_name ]
93+ except KeyError :
9694 continue
9795
9896 if orig_attr is None :
9997 raise AttributeError ("Attribute not found." )
10098
101- # Calling getattr() on a staticmethod transforms it to a 'normal'
102- # function. We need to ensure that we put it back as a staticmethod.
103- old_attribute = obj .__dict__ .get (attr_name )
104- if old_attribute is not None and isinstance (old_attribute , staticmethod ):
105- orig_attr = staticmethod (orig_attr ) # pytype: disable=not-callable
106-
10799 self .stubs .append ((orig_obj , attr_name , orig_attr ))
108- setattr ( orig_obj , attr_name , new_attr )
100+ orig_obj . __dict__ [ attr_name ] = new_attr
109101
110102 def smart_unset_all (self ):
111103 """Reverses all the SmartSet() calls.
@@ -116,8 +108,8 @@ def smart_unset_all(self):
116108 """
117109 self .stubs .reverse ()
118110
119- for args in self .stubs :
120- setattr ( * args )
111+ for obj , attr_name , old_attr in self .stubs :
112+ obj . __dict__ [ attr_name ] = old_attr
121113
122114 self .stubs = []
123115
@@ -143,7 +135,7 @@ def set(self, parent, child_name, new_child):
143135 old_child = classmethod (old_child .__func__ )
144136
145137 self .cache .append ((parent , old_child , child_name ))
146- setattr ( parent , child_name , new_child )
138+ parent . __dict__ [ child_name ] = new_child
147139
148140 def unset_all (self ):
149141 """Reverses all the Set() calls.
@@ -158,5 +150,5 @@ def unset_all(self):
158150 self .cache .reverse ()
159151
160152 for parent , old_child , child_name in self .cache :
161- setattr ( parent , child_name , old_child )
153+ parent . __dict__ [ child_name ] = old_child
162154 self .cache = []
0 commit comments