Check if any attribute of obj has the wrong_name as a nested attribute. Returns the first nested attribute suggestion found, or None. Limited to checking 20 attributes. Only considers non-descriptor outer attributes to avoid executing arbitrary code. Checks nested attributes statica
(obj, wrong_name, attrs)
| 1675 | |
| 1676 | |
| 1677 | def _check_for_nested_attribute(obj, wrong_name, attrs): |
| 1678 | """Check if any attribute of obj has the wrong_name as a nested attribute. |
| 1679 | |
| 1680 | Returns the first nested attribute suggestion found, or None. |
| 1681 | Limited to checking 20 attributes. |
| 1682 | Only considers non-descriptor outer attributes to avoid executing |
| 1683 | arbitrary code. Checks nested attributes statically so descriptors such |
| 1684 | as properties can still be suggested without invoking them. |
| 1685 | Skips lazy imports to avoid triggering module loading. |
| 1686 | """ |
| 1687 | from inspect import getattr_static |
| 1688 | |
| 1689 | # Check for nested attributes (only one level deep) |
| 1690 | attrs_to_check = [x for x in attrs if not x.startswith('_')][:20] # Limit number of attributes to check |
| 1691 | for attr_name in attrs_to_check: |
| 1692 | with suppress(Exception): |
| 1693 | # Check if attr_name is a descriptor - if so, skip it |
| 1694 | attr_from_class = getattr_static(type(obj), attr_name, _sentinel) |
| 1695 | if attr_from_class is not _sentinel and hasattr(attr_from_class, '__get__'): |
| 1696 | continue # Skip descriptors to avoid executing arbitrary code |
| 1697 | |
| 1698 | # Skip lazy imports to avoid triggering module loading |
| 1699 | if _is_lazy_import(obj, attr_name): |
| 1700 | continue |
| 1701 | |
| 1702 | # Safe to get the attribute since it's not a descriptor |
| 1703 | attr_obj = getattr(obj, attr_name) |
| 1704 | |
| 1705 | if _is_lazy_import(attr_obj, wrong_name): |
| 1706 | continue |
| 1707 | |
| 1708 | if getattr_static(attr_obj, wrong_name, _sentinel) is not _sentinel: |
| 1709 | return f"{attr_name}.{wrong_name}" |
| 1710 | |
| 1711 | return None |
| 1712 | |
| 1713 | |
| 1714 | def _get_safe___dir__(obj): |
no test coverage detected
searching dependent graphs…