Glom (https://glom.readthedocs.io/en/latest/) is, amongst other things, for
path-based access for nested structures
But how do you make it work for nested structures beyond dicts?
Consider the following class (purposely not an actual collection.abc.Mapping
, for simplicity:
class MyMap:
def __init__(self, d):
self.d = d
def __getitem__(self, k):
"""just delegating"""
v = self.d[k]
if isinstance(v, (dict, MyMap)):
return MyMap(v)
else:
return v
This works:
m = MyMap({'a': {'b': {'c': 'd'}}})
assert m['a']['b']['c'] == 'd'
But this doesn't:
from glom import glom
assert glom(m, 'a.b.c') == 'd'
I get the error:
PathAccessError: could not access 'a', part 0 of Path('a', 'b', 'c'), got error: AttributeError("'MyMap' object has no attribute 'a'")
More specifically, how does one specify:
- what's a node (i.e. an object that can be glommed further)
- a key iterator (how to split a path into keys)
- an item getter (how data is retrieved from a key)
In case it helps, here's the kind of function I'm looking for glom to satisfy:
dot_str_key_iterator = lambda p: p.split('.')
bracket_getter = lambda obj, k: obj[k]
def simple_glom(target, spec,
node_types=(dict,),
key_iterator=dot_str_key_iterator,
item_getter=bracket_getter
):
for k in key_iterator(spec):
target = item_getter(target, k)
if not isinstance(target, node_types):
break
return target
This function doesn't have all the bells and whistles, but allows me to do:
m = MyMap({'a': {'b': {'c': 'd'}}})
simple_glom(m, 'a.b.c', node_types=(MyMap,))
Or for an extreme example using all parametrizatons:
from types import FunctionType
from functools import partial
attr_glom = partial(simple_glom,
node_types=(FunctionType, type),
key_iterator=lambda p: p.split('/'),
item_getter=getattr)
assert attr_glom(MyMap, '__getitem__/__doc__') == 'just delegating'