Replace obj.attr_name with new_attr. This method is smart and works at the module, class, and instance level while preserving proper inheritance. It will not stub out C types however unless that has been explicitly allowed by the type. This method supports the case where attr_name
(self, obj, attr_name, new_attr)
| 154 | self.UnsetAll() |
| 155 | |
| 156 | def SmartSet(self, obj, attr_name, new_attr): |
| 157 | """Replace obj.attr_name with new_attr. |
| 158 | |
| 159 | This method is smart and works at the module, class, and instance level |
| 160 | while preserving proper inheritance. It will not stub out C types however |
| 161 | unless that has been explicitly allowed by the type. |
| 162 | |
| 163 | This method supports the case where attr_name is a staticmethod or a |
| 164 | classmethod of obj. |
| 165 | |
| 166 | Notes: |
| 167 | - If obj is an instance, then it is its class that will actually be |
| 168 | stubbed. Note that the method Set() does not do that: if obj is |
| 169 | an instance, it (and not its class) will be stubbed. |
| 170 | - The stubbing is using the builtin getattr and setattr. So, the __get__ |
| 171 | and __set__ will be called when stubbing (TODO: A better idea would |
| 172 | probably be to manipulate obj.__dict__ instead of getattr() and |
| 173 | setattr()). |
| 174 | |
| 175 | Args: |
| 176 | obj: The object whose attributes we want to modify. |
| 177 | attr_name: The name of the attribute to modify. |
| 178 | new_attr: The new value for the attribute. |
| 179 | |
| 180 | Raises: |
| 181 | AttributeError: If the attribute cannot be found. |
| 182 | """ |
| 183 | _, obj = tf_decorator.unwrap(obj) |
| 184 | if (tf_inspect.ismodule(obj) or |
| 185 | (not tf_inspect.isclass(obj) and attr_name in obj.__dict__)): |
| 186 | orig_obj = obj |
| 187 | orig_attr = getattr(obj, attr_name) |
| 188 | else: |
| 189 | if not tf_inspect.isclass(obj): |
| 190 | mro = list(tf_inspect.getmro(obj.__class__)) |
| 191 | else: |
| 192 | mro = list(tf_inspect.getmro(obj)) |
| 193 | |
| 194 | mro.reverse() |
| 195 | |
| 196 | orig_attr = None |
| 197 | found_attr = False |
| 198 | |
| 199 | for cls in mro: |
| 200 | try: |
| 201 | orig_obj = cls |
| 202 | orig_attr = getattr(obj, attr_name) |
| 203 | found_attr = True |
| 204 | except AttributeError: |
| 205 | continue |
| 206 | |
| 207 | if not found_attr: |
| 208 | raise AttributeError('Attribute not found.') |
| 209 | |
| 210 | # Calling getattr() on a staticmethod transforms it to a 'normal' function. |
| 211 | # We need to ensure that we put it back as a staticmethod. |
| 212 | old_attribute = obj.__dict__.get(attr_name) |
| 213 | if old_attribute is not None and isinstance(old_attribute, staticmethod): |