(self, value, attr)
| 252 | ) |
| 253 | |
| 254 | def can_get_attr(self, value, attr): |
| 255 | allowed_getattr_external = _coerce_path_to_tuples(self.allowed_getattr_external) |
| 256 | |
| 257 | has_original_attribute = _has_original_dunder( |
| 258 | value, |
| 259 | allowed_types=self.allowed_getattr, |
| 260 | allowed_methods=self._getattribute_methods, |
| 261 | allowed_external=allowed_getattr_external, |
| 262 | method_name="__getattribute__", |
| 263 | ) |
| 264 | has_original_attr = _has_original_dunder( |
| 265 | value, |
| 266 | allowed_types=self.allowed_getattr, |
| 267 | allowed_methods=self._getattr_methods, |
| 268 | allowed_external=allowed_getattr_external, |
| 269 | method_name="__getattr__", |
| 270 | ) |
| 271 | |
| 272 | accept = False |
| 273 | |
| 274 | # Many objects do not have `__getattr__`, this is fine. |
| 275 | if has_original_attr is None and has_original_attribute: |
| 276 | accept = True |
| 277 | else: |
| 278 | # Accept objects without modifications to `__getattr__` and `__getattribute__` |
| 279 | accept = has_original_attr and has_original_attribute |
| 280 | |
| 281 | if accept: |
| 282 | # We still need to check for overridden properties. |
| 283 | |
| 284 | value_class = type(value) |
| 285 | if not hasattr(value_class, attr): |
| 286 | return True |
| 287 | |
| 288 | class_attr_val = getattr(value_class, attr) |
| 289 | is_property = isinstance(class_attr_val, property) |
| 290 | |
| 291 | if not is_property: |
| 292 | return True |
| 293 | |
| 294 | # Properties in allowed types are ok (although we do not include any |
| 295 | # properties in our default allow list currently). |
| 296 | if type(value) in self.allowed_getattr: |
| 297 | return True # pragma: no cover |
| 298 | |
| 299 | # Properties in subclasses of allowed types may be ok if not changed |
| 300 | for module_name, *access_path in allowed_getattr_external: |
| 301 | try: |
| 302 | external_class = _get_external(module_name, access_path) |
| 303 | external_class_attr_val = getattr(external_class, attr) |
| 304 | except (KeyError, AttributeError): |
| 305 | return False # pragma: no cover |
| 306 | return class_attr_val == external_class_attr_val |
| 307 | |
| 308 | return False |
| 309 | |
| 310 | def can_get_item(self, value, item): |
| 311 | """Allow accessing `__getiitem__` of allow-listed instances unless it was not modified.""" |
no test coverage detected