jmespath.py icon indicating copy to clipboard operation
jmespath.py copied to clipboard

Custom "None" value when search fails

Open fjsj opened this issue 6 years ago • 10 comments

Hi, thanks for this awesome lib! One question: it seems to be impossible to set a custom return in case the search fails.

E.g.

not_found = object()
jmespath.search('foo.aaa', {'foo': {'bar': 'baz'}})  # I need `not_found`, not `None`

Is this by design or are you open to supporting that? I see this was discussed at https://github.com/jmespath/jmespath.py/issues/113 But the proposed solution of contains isn't great, as it requires 2 searches.

fjsj avatar Sep 20 '19 16:09 fjsj

You may try

jmespath.search('foo.aaa', {'foo': {'bar': 'baz'}})  or 'not_found'

yashpokar avatar Sep 28 '19 07:09 yashpokar

@yashpokar Not enough for this problem. This will make 'not_found' be returned when 'foo.aaa' is None, like here: {'foo': {'aaa': None}}. That's why it's important to differentiate a valid None from a not found value.

fjsj avatar Sep 30 '19 14:09 fjsj

@fjsj you're right :+1:

yashpokar avatar Oct 01 '19 05:10 yashpokar

Hi, thanks for this awesome lib! One question: it seems to be impossible to set a custom return in case the search fails.

E.g.

not_found = object()
jmespath.search('foo.aaa', {'foo': {'bar': 'baz'}})  # I need `not_found`, not `None`

Is this by design or are you open to supporting that? I see this was discussed at #113 But the proposed solution of contains isn't great, as it requires 2 searches.

Good proposal!!

It has to be differentiated between the legal value 'null' for an existing key and a non-existing key. JMESPath search should return another object than None if a key is not found.

E.g. allow to define an object NotFound as option. If not defined use None for not found. So you are backward compatible.

ges0909 avatar Nov 06 '20 12:11 ges0909

any updates on this?

cdogaru-hrp-ctr avatar Apr 05 '23 17:04 cdogaru-hrp-ctr

Any updates? This seems like quite an important thing to solve imo.

OndraSlama avatar Apr 26 '23 06:04 OndraSlama

+1

agargenta avatar May 07 '23 15:05 agargenta

+1

theobjectivedad avatar May 23 '23 12:05 theobjectivedad

If anyone is looking for a hack, this is what I am using until this issues is resolved. The key_exists function below will check for true existence of key:

def key_exists(key: str, obj: Any, separator='.') -> bool:

    keys = key.split(separator)
    for k in keys:
        if isinstance(obj, dict):
            if k in obj:
                obj = obj[k]
            else:
                return False
        else:
            return False
    return True

To use, check if the search result is None and if the key doesn't exist before implementing handling logic:

result = jmespath.search(search_string, source)

if result is None and not key_exists(search_string, source, separator="."):       
  if match_required:
    # Handle search_string doesn't exist but match is required...

  # Handle search_string doesn't exist and match isn't required, go ahead and assign a default value

# Implied else, search_string was found in source and it may be None

Please use caution, this will easily break when a more sophisticated jmespath expression is used.

theobjectivedad avatar May 23 '23 12:05 theobjectivedad

Since jmespath doesn't care about fixing this, we've ended up using jsonpath-ng which supports everything that jmespath supports + handling None values. Best workaround.

cdogaru-hrp-ctr avatar May 23 '23 16:05 cdogaru-hrp-ctr