From 89550c9f26bcc79643b9a129324c52c939d09f6f Mon Sep 17 00:00:00 2001 From: Filip Uhlik Date: Thu, 1 Jun 2023 21:48:52 +0200 Subject: [PATCH] [#186] options: add default not found value option --- jmespath/visitor.py | 11 ++++++----- tests/test_search.py | 12 ++++++++++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/jmespath/visitor.py b/jmespath/visitor.py index 15fb1774..6ef15e8e 100644 --- a/jmespath/visitor.py +++ b/jmespath/visitor.py @@ -1,8 +1,8 @@ import operator +from numbers import Number from jmespath import functions from jmespath.compat import string_type -from numbers import Number def _equals(x, y): @@ -58,7 +58,7 @@ def _is_actual_number(x): class Options(object): """Options to control how a JMESPath function is evaluated.""" - def __init__(self, dict_cls=None, custom_functions=None): + def __init__(self, dict_cls=None, custom_functions=None, not_found_value=None): #: The class to use when creating a dict. The interpreter # may create dictionaries during the evaluation of a JMESPath # expression. For example, a multi-select hash will @@ -69,6 +69,7 @@ def __init__(self, dict_cls=None, custom_functions=None): # have predictable key ordering. self.dict_cls = dict_cls self.custom_functions = custom_functions + self.not_found_value = not_found_value class _Expression(object): @@ -133,9 +134,9 @@ def visit_subexpression(self, node, value): def visit_field(self, node, value): try: - return value.get(node['value']) + return value.get(node['value'], self._options.not_found_value) except AttributeError: - return None + return self._options.not_found_value def visit_comparator(self, node, value): # Common case: comparator is == or != @@ -298,7 +299,7 @@ def _is_false(self, value): # because the truth/false values are different between # python and jmespath. return (value == '' or value == [] or value == {} or value is None or - value is False) + value is False or value == self._options.not_found_value) def _is_true(self, value): return not self._is_false(value) diff --git a/tests/test_search.py b/tests/test_search.py index 4832079b..4c3d4821 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -62,3 +62,15 @@ def test_can_handle_decimals_as_numeric_type(self): result = decimal.Decimal('3') self.assertEqual(jmespath.search('[?a >= `1`].a', [{'a': result}]), [result]) + + +class TestNotFoundValueOption(unittest.TestCase): + opt = jmespath.Options(not_found_value='foo') + + def test_can_supply_custom_not_found_value(self): + value = jmespath.search('b', {'a': 1}, self.opt) + self.assertEqual(value, 'foo') + + def test_custom_value_is_treated_as_false(self): + value = jmespath.search('b || a', {'a': 1}, self.opt) + self.assertEqual(value, 1)