glom icon indicating copy to clipboard operation
glom copied to clipboard

coalesce-along-list

Open kurtbrose opened this issue 4 years ago • 6 comments

context = [{}, {}, {'user': {'client': 123}}, {}]

client = glom(context,
     Coalesce(
        ([Coalesce('user.client', default=SKIP)], T[0]),
        default=None))

basically, you want to get the first element in a list which has a valid value here's how the above would look with that available:

client = glom(context, IterCoalesce('user.client', default=None))

maybe this should be Iter().first(coalesce=True)? I'm not sure the best place to fit it into the API

kurtbrose avatar Aug 14 '20 16:08 kurtbrose

this is close, but doesn't quite work right:

Iter().first('user.client', default=None)
>>> t3 = [{'b': 1}, {'a': 2}]
>>> glom(t3, Iter('a').first())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Users\Kurt\workspace\glom\glom\core.py", line 2085, in glom
    raise err
glom.core.PathAccessError: error raised while processing, details below.
 Target-spec trace (most recent last):
 - Target: [{'b': 1}, {'a': 2}]
 + Spec: (Iter('a'), First(T))
 |\ Spec: Iter('a')
 ||\ Target: {'b': 1}
 ||X Spec: 'a'
 |X\ Target: <generator object Iter._iterate at 0x0000024741931848>
 ||| Spec: First(T)
 ||| Spec: Spec(Call(<class 'functools.partial'>, args=(<bound method Spec....
 ||| Spec: Call(<class 'functools.partial'>, args=(<bound method Spec.glom ...
 ||X Spec: S
 |\ Spec: Iter('a')
 ||\ Target: {'b': 1}
 ||X Spec: 'a'
 ||\ Target: <generator object Iter._iterate at 0x0000024741931848>
 ||| Spec: First(T)
 ||| Spec: Spec(Call(<class 'functools.partial'>, args=(<bound method Spec....
 ||| Spec: Call(<class 'functools.partial'>, args=(<bound method Spec.glom ...
 ||| Spec: S

kurtbrose avatar Aug 14 '20 17:08 kurtbrose

maybe this could be addressed by '*' paths -- Coalesce('*.user.client', default=None) instead of [Coalesce('user.client', default=SKIP)]

kurtbrose avatar Aug 14 '20 17:08 kurtbrose

Hey what's the bottom of that .first() stack? Iter(default=None).first() was my first thought. Like, return a value if StopIteration without any results, but I need to think it out more.

mahmoud avatar Aug 14 '20 17:08 mahmoud

right? :-) I think Iter() does some weird things inside its eval

kurtbrose avatar Aug 14 '20 18:08 kurtbrose

image

kurtbrose avatar Aug 14 '20 18:08 kurtbrose

the actual use case was cleaning up some sloppy input that might be a dict, or a list of dicts looking for user.client

context = [{}, {}, {'user': {'client': 123}}, {}]

client = glom(context,
     Coalesce(
        'user.client',
        ([Coalesce('user.client', default=SKIP)], T[0]),
        default=None))

so, * support would actually be great

glom(context, Coalesce('user.client', '*.user.client'))

kurtbrose avatar Aug 15 '20 03:08 kurtbrose