MagicAttr
MagicAttr (current version 0.1.6) provides an enhanced `getattr` and `setattr` functionality for Python, capable of navigating and modifying attributes within deeply nested objects, lists, and dictionaries. It stands out by retaining the original cause of failure instead of exclusively raising an `AttributeError`, offering more granular error information. The library sees infrequent but active maintenance, with the latest release in January 2022.
Common errors
-
ModuleNotFoundError: No module named 'magicattr'
cause The `magicattr` library is not installed in the current Python environment.fixpip install magicattr -
TypeError: Path must be a string or a list of path segments
cause The `path` argument passed to `get_at` or `set_at` is neither a string nor a list, which are the only accepted types for defining the navigation path.fixEnsure the path argument is a dot-separated string (e.g., 'a.b.0.c') or a list of segments (e.g., ['a', 'b', 0, 'c']). -
KeyError: 'some_key'
cause During path traversal, `magicattr` encountered a dictionary where a specified key ('some_key' in this example) does not exist, and it propagates the original `KeyError`.fixVerify the path string or list against the actual structure of the nested dictionary to ensure all keys exist, or handle the potential `KeyError` with a `try-except` block. -
ImportError: cannot import name 'magicattr' from 'magicattr'
cause The user is attempting to import the `magicattr` package itself as a named object or function, but the primary functions (`get_at` and `set_at`) are exposed directly from the package, not the package name itself.fixImport the specific functions you intend to use, such as `from magicattr import get_at, set_at`.
Warnings
- gotcha MagicAttr's path parsing does not support advanced Python syntax such as slicing (e.g., `list[1:3]`), arbitrary expressions (e.g., `list[0+1]`), function calls (e.g., `list.pop(0)`), or `eval` related constructs within the attribute string. Attempting to use these will result in `NotImplementedError` or `ValueError`.
- gotcha Unlike standard `getattr`/`setattr` which consistently raise `AttributeError` for missing or invalid attributes, `magicattr` aims to return the underlying exception (e.g., `KeyError` for dicts, `IndexError` for lists) or `None` for missing attributes/indices. This can lead to different error handling patterns than typically expected from Python's built-in attribute access.
- gotcha When using `magicattr.set()` to create new, deeply nested structures (e.g., `magicattr.set(obj, 'new_attr.nested_key', 'value')`), the library automatically infers and creates intermediate `dict` or `list` types as needed. While convenient, this might not always align with expectations if a different custom object type was desired for those intermediate steps.
Install
-
pip install magicattr
Imports
- magicattr
from magicattr import magicattr
Quickstart
from magicattr import magicattr
class Person:
def __init__(self, name, age, settings=None, friends=None):
self.name = name
self.age = age
self.settings = settings if settings is not None else {}
self.friends = friends if friends is not None else []
bob = Person("Bob", 30, {'preferences': {'theme': 'dark'}})
jill = Person("Jill", 25, friends=[Person("Jack", 28), Person("Jane", 27)])
# Get a nested attribute
theme = magicattr.get(bob, 'settings.preferences.theme')
print(f"Bob's theme: {theme}")
# Set a nested attribute
magicattr.set(bob, 'age', 32)
print(f"Bob's new age: {bob.age}")
magicattr.set(jill, 'friends[0].age', 29)
print(f"Jill's first friend's new age: {jill.friends[0].age}")
# Delete a nested attribute
magicattr.delete(jill, 'friends[0]')
print(f"Jill's friends after deletion: {[f.name for f in jill.friends] if jill.friends else 'None'}")
# Demonstrate setting a new deeply nested attribute, creating intermediate dicts
magicattr.set(bob, 'address.city', 'New York')
print(f"Bob's city: {bob.address.city}")