Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nested dict access via a pathing system #117

Open
RitikShah opened this issue Sep 10, 2019 · 2 comments
Open

nested dict access via a pathing system #117

RitikShah opened this issue Sep 10, 2019 · 2 comments

Comments

@RitikShah
Copy link

aka: being able to access a nested item via an xpath-esque syntax

>>> from addict import Dict
>>> a = Dict()
>>> a.b.c = 10
>>> a.b.d = 20
>>> a.c.c = 100
>>> a.c.d = 200
>>>
>>> a.search('a/b/c')  # or a.search('a.b.c')
10
>>> a.search('a/b').c = 11
>>> a.b.c
11
>>> a.search('a/b/[cd]')
(11, 20)
>>> a.search('a/b/[cd]', full_path=True)
{a: {b: {c: 11, d: 20}}}
>>> a.search('a/*/c', full_path=True)
{a: {b: {c: 11}, c: {c: 100}}

There's a lot more that could be expanded upon this. This is basically like the dpath library or the jsonpointer library but integrated into the library.

I think this is a good opportunity for a kind of superdict as this as it implements a lot of possibilities. It could be as simple as binding the dpath functions internally making that lib a requirement (eh), or maybe creating an interface akin to that.

However, I realize this is a lot to request (hehe) and probably is more work than warranted (I could try to take a stab at it potentially). Another less extreme idea is just to add simple iterable get and set.
ex:

>>> from addict import Dict
>>> a = Dict()
>>> a.b.c = 10
>>> a.get_from(['a', 'b', 'c'])
10
>>> a.set_from(['a', 'b', 'c'], 20)
>>> a.b.c
20
>>> # this functionality can easily be replicated but it uses eval so it's not favorable
>>> path = '.'.join(['a', 'b', 'c'])
>>> eval(f'a.{path}')  # yuck
20

These are just a couple ideas I had. I think the first idea might be taking it a lil too far but the latter does fit in with the rest of this class I feel. Just wondering what you thought. I potentially may come with a pull request if I find the time.

Thanks!
~ Ritik Shah ~

@mewwts
Copy link
Owner

mewwts commented Mar 15, 2020

Hi @RitikShah, thanks for your contribution!

I'd be open to including the latter functionality. Keen on making a PR?

@whoiswes
Copy link

whoiswes commented Jan 7, 2021

mewwts, thanks for creating addict - we use it extensively for a number of our internal apps and modules.

Just in case anyone comes across this and needs an immediate solution, here is a quick and dirty func I wrote that can walk a dotted-string notation to set/get a Dict() property. Not extensively tested and only handles dictionaries and absolute paths. If time permits I'll try to expand upon this and possibly submit a PR.

def tree(obj, path, data=None, separator="."):
    """ String to addict nested property conversion """
    # Extract branch/leaf properties from path
    tree = path.split(separator)
    leaf = tree.pop()
    # Loop through branches to get to leaf, creating branches as needed
    for branch in tree:
        obj = getattr(obj, branch, obj[branch])
    # At the leaf, assign data if set
    if data:
        obj[leaf] = data
    # Return leaf
    return obj[leaf]

Usage:

test = Dict()
tree(test, "foo.bar.baz", 42)
>>> 42
test
>>> {'foo': {'bar': {'baz': 42}}}
tree(test, "foo.bar.baz")
>>> 42
tree(test, "baz.bar.foo")
>>> {}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants