Skip to main content

A getattr and setattr that works on nested objects, lists, dicts, and any combination thereof without resorting to eval

Project description

Magicattr

Build Status codecov

A getattr and setattr that works on nested objects, lists, dictionaries, and any combination thereof without resorting to eval.

Example

Say we have a person class as follows:

class Person:
    settings = {
        'autosave': True,
        'style': {
            'height': 30,
            'width': 200
        },
        'themes': ['light', 'dark']
    }
    def __init__(self, name, age, friends):
        self.name = name
        self.age = age
        self.friends = friends


bob = Person(name="Bob", age=31, friends=[])
jill = Person(name="Jill", age=29, friends=[bob])
jack = Person(name="Jack", age=28, friends=[bob, jill])

With magicattr we can do this

# Nothing new
assert magicattr.get(bob, 'age') == 31

# Lists
assert magicattr.get(jill, 'friends[0].name') == 'Bob'
assert magicattr.get(jack, 'friends[-1].age') == 29

# Dict lookups
assert magicattr.get(jack, 'settings["style"]["width"]') == 200

# Combination of lookups
assert magicattr.get(jack, 'settings["themes"][-2]') == 'light'
assert magicattr.get(jack, 'friends[-1].settings["themes"][1]') == 'dark'

# Setattr
magicattr.set(bob, 'settings["style"]["width"]', 400)
assert magicattr.get(bob, 'settings["style"]["width"]') == 400

# Nested objects
magicattr.set(bob, 'friends', [jack, jill])
assert magicattr.get(jack, 'friends[0].friends[0]') == jack

magicattr.set(jill, 'friends[0].age', 32)
assert bob.age == 32

You can also delete like this too.

# Deletion
magicattr.delete(jill, 'friends[0]')
assert len(jill.friends) == 0

magicattr.delete(jill, 'age')
assert not hasattr(jill, 'age')

magicattr.delete(bob, 'friends[0].age')
assert not hasattr(jack, 'age')

What if someone tries to mess with you?

# Unsupported
with pytest.raises(NotImplementedError) as e:
    assert magicattr.get(bob, 'friends[0+1]') == jill

# Nice try, function calls are not allowed
with pytest.raises(ValueError):
    assert magicattr.get(bob, 'friends.pop(0)') == bob.friends.pop

Did I miss anything? Let me know!

What it can't do?

Slicing, expressions, function calls, append/pop from lists, eval stuff, etc...

How does it work?

Parses the attr string into an ast node and manually evaluates it.

Installing

pip install magicattr

License

MIT

Hope it helps, cheers!

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

magicattr-0.1.0-py2.py3-none-any.whl (3.2 kB view details)

Uploaded Python 2 Python 3

File details

Details for the file magicattr-0.1.0-py2.py3-none-any.whl.

File metadata

File hashes

Hashes for magicattr-0.1.0-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 df2d8433a44d3d41126e67c030ce73e9a82bfbc9491555effbbab90b9d0d3cff
MD5 62262ddf6c77341a72a5a927c0acd85b
BLAKE2b-256 8fda4e6d9042fe953a83d94d98f10c6378733e335a68fc1be04e482eca3c7a02

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page