Skip to content

Commit 1a6f6b4

Browse files
committed
add deep_set util function
1 parent 1cac0ab commit 1a6f6b4

File tree

2 files changed

+41
-2
lines changed

2 files changed

+41
-2
lines changed

openeo/util.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ def __init__(self, key, keys):
308308

309309
def deep_get(data: dict, *keys, default=_deep_get_default_undefined):
310310
"""
311-
Get "deep" value from nested dictionaries/lists/tuples
311+
Get value deeply from nested dictionaries/lists/tuples
312312
313313
:param data: nested data structure of dicts, lists, tuples
314314
:param keys: sequence of keys/indexes to traverse
@@ -329,6 +329,27 @@ def deep_get(data: dict, *keys, default=_deep_get_default_undefined):
329329
return data
330330

331331

332+
def deep_set(data: dict, *keys, value):
333+
"""
334+
Set a value deeply in nested dictionary
335+
336+
:param data: nested data structure of dicts, lists, tuples
337+
:param keys: sequence of keys/indexes to traverse
338+
:param value: value to set
339+
"""
340+
if len(keys) == 1:
341+
data[keys[0]] = value
342+
elif len(keys) > 1:
343+
if isinstance(data, dict):
344+
deep_set(data.setdefault(keys[0], {}), *keys[1:], value=value)
345+
elif isinstance(data, (list, tuple)):
346+
deep_set(data[keys[0]], *keys[1:], value=value)
347+
else:
348+
ValueError(data)
349+
else:
350+
raise ValueError("No keys given")
351+
352+
332353
def load_json(path: Union[Path, str]) -> dict:
333354
with Path(path).open("r", encoding="utf-8") as f:
334355
return json.load(f)

tests/test_util.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import pytest
1010

1111
from openeo.util import first_not_none, get_temporal_extent, TimingLogger, ensure_list, ensure_dir, dict_no_none, \
12-
deep_get, DeepKeyError, get_user_config_dir, get_user_data_dir, Rfc3339, rfc3339
12+
deep_get, DeepKeyError, get_user_config_dir, get_user_data_dir, Rfc3339, rfc3339, deep_set
1313

1414

1515
def test_rfc3339_date():
@@ -356,6 +356,24 @@ def test_deep_get_mixed():
356356
deep_get(d, "bar", 2, 22, 222)
357357

358358

359+
@pytest.mark.parametrize(["init", "keys", "expected"], [
360+
({}, ("foo",), {"foo": 42}),
361+
({}, ("foo", "bar", "baz"), {"foo": {"bar": {"baz": 42}}}),
362+
({"foo": {"x": "y"}}, ("foo", "bar"), {"foo": {"x": "y", "bar": 42}}),
363+
({"foo": {"x": "y"}}, ("foo", "bar", "baz"), {"foo": {"x": "y", "bar": {"baz": 42}}}),
364+
({"foo": [1, 2, 3]}, ("foo", 1), {"foo": [1, 42, 3]}),
365+
({"foo": {1: "a", 2: "b"}}, ("foo", 1), {"foo": {1: 42, 2: "b"}}),
366+
({"foo": [{"x": 1}, {"x": 2}, {"x": 3}]}, ("foo", 1, "x"), {"foo": [{"x": 1}, {"x": 42}, {"x": 3}]}),
367+
({"foo": ({"x": 1}, {"x": 2}, {"x": 3})}, ("foo", 1, "x"), {"foo": ({"x": 1}, {"x": 42}, {"x": 3})}),
368+
({"foo": [{"x": {}}, {"x": {}}]}, ("foo", 1, "x", "bar"), {"foo": [{"x": {}}, {"x": {"bar": 42}}]}),
369+
({"foo": [{"x": {}}, {"x": {}}]}, ("foo", 1, "x", "y", "z"), {"foo": [{"x": {}}, {"x": {"y": {"z": 42}}}]}),
370+
])
371+
def test_deep_set_dict(init, keys, expected):
372+
d = init
373+
deep_set(d, *keys, value=42)
374+
assert d == expected
375+
376+
359377
def test_get_user_config_dir():
360378
assert get_user_config_dir() == pathlib.Path(__file__).parent / "data/user_dirs/config/openeo-python-client"
361379

0 commit comments

Comments
 (0)