[mod] utils.get_value() - avoidance of a recursion

In a comment [1] dalf suggested to avoid a recursion of get_value()

[1] https://github.com/searxng/searxng/pull/99#discussion_r640833716

Suggested-by: Alexandre Flament <alex@al-f.net>
Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
This commit is contained in:
Markus Heiser 2021-05-27 20:15:33 +02:00
parent 6ed4616da9
commit 96b223023a
1 changed files with 12 additions and 16 deletions

View File

@ -505,13 +505,14 @@ NOT_EXISTS = object()
"""Singleton used by :py:obj:`get_value` if a key does not exists.""" """Singleton used by :py:obj:`get_value` if a key does not exists."""
def get_value(dictionary, keyword, *keys, default=NOT_EXISTS): def get_value(dictionary, *keys, default=NOT_EXISTS):
"""Return the value from a *deep* mapping type (e.g. the ``settings`` object """Return the value from a *deep* mapping type (e.g. the ``settings`` object
from yaml). If the path to the *key* does not exists a :py:obj:`NOT_EXISTS` from yaml). If the path to the *key* does not exists a :py:obj:`NOT_EXISTS`
is returned (non ``KeyError`` exception is raised). is returned (non ``KeyError`` exception is raised).
.. code: python .. code: python
>>> from searx import settings
>>> from searx.utils import get_value, NOT_EXISTS >>> from searx.utils import get_value, NOT_EXISTS
>>> get_value(settings, 'checker', 'additional_tests', 'rosebud', 'result_container') >>> get_value(settings, 'checker', 'additional_tests', 'rosebud', 'result_container')
['not_empty', ['one_title_contains', 'citizen kane']] ['not_empty', ['one_title_contains', 'citizen kane']]
@ -519,7 +520,7 @@ def get_value(dictionary, keyword, *keys, default=NOT_EXISTS):
>>> get_value(settings, 'search', 'xxx') is NOT_EXISTS >>> get_value(settings, 'search', 'xxx') is NOT_EXISTS
True True
>>> get_value(settings, 'search', 'formats') >>> get_value(settings, 'search', 'formats')
['csv', 'json', 'rss'] ['html', 'csv', 'json', 'rss']
The list returned from the ``search.format`` key is not a mapping type, you The list returned from the ``search.format`` key is not a mapping type, you
can't traverse along non-mapping types. If you try it, you will get a can't traverse along non-mapping types. If you try it, you will get a
@ -529,7 +530,7 @@ def get_value(dictionary, keyword, *keys, default=NOT_EXISTS):
>>> get_value(settings, 'search', 'format', 'csv') is NOT_EXISTS >>> get_value(settings, 'search', 'format', 'csv') is NOT_EXISTS
True True
>>> get_value(settings, 'search', 'formats')[0] >>> get_value(settings, 'search', 'formats')[1]
'csv' 'csv'
For convenience you can replace :py:ref:`NOT_EXISTS` by a default value of For convenience you can replace :py:ref:`NOT_EXISTS` by a default value of
@ -541,20 +542,15 @@ def get_value(dictionary, keyword, *keys, default=NOT_EXISTS):
print("csv format is denied") print("csv format is denied")
""" """
if not isinstance(dictionary, Mapping):
raise TypeError("expected mapping type, got %s" % type(dictionary))
ret_val = dictionary.get(keyword, default) obj = dictionary
for k in keys:
if ret_val is default: if not isinstance(obj, Mapping):
return ret_val raise TypeError("expected mapping type, got %s" % type(obj))
obj = obj.get(k, default)
if len(keys): if obj is default:
if not isinstance(ret_val, Mapping): return obj
ret_val = default return obj
else:
ret_val = get_value(ret_val, *keys, default=default)
return ret_val
def get_xpath(xpath_spec): def get_xpath(xpath_spec):