]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
python: utils/modeling/parsing.py: 'data_combine' function for combining dictionaries...
authorAleš Mrázek <ales.mrazek@nic.cz>
Thu, 19 Jun 2025 18:45:26 +0000 (20:45 +0200)
committerVladimír Čunát <vladimir.cunat@nic.cz>
Fri, 4 Jul 2025 17:12:45 +0000 (19:12 +0200)
python/knot_resolver/utils/modeling/parsing.py
tests/manager/utils/modeling/test_parsing.py [new file with mode: 0644]

index 593f6ca1751f08768cab1fd2a1192955f8b70361..dc6cec6cc74effa3052bb7acede0dc258e8f6ce9 100644 (file)
@@ -6,7 +6,7 @@ import yaml
 from yaml.constructor import ConstructorError
 from yaml.nodes import MappingNode
 
-from .exceptions import DataParsingError
+from .exceptions import DataParsingError, DataValidationError
 from .renaming import Renamed, renamed
 
 
@@ -95,3 +95,18 @@ def try_to_parse(data: str) -> Any:
             raise DataParsingError(  # pylint: disable=raise-missing-from
                 f"failed to parse data, JSON: {je}, YAML: {ye}"
             ) from ye
+
+
+def data_combine(data: Dict[Any, Any], additional_data: Dict[Any, Any], object_path: str = "") -> Dict[Any, Any]:
+    """Combine dictionaries data"""
+    for key in additional_data:
+        if key in data:
+            # if both are dictionaries we can try to combine them deeper
+            if isinstance(data[key], (Dict, dict)) and isinstance(additional_data[key], (Dict, dict)):
+                data[key] = data_combine(data[key], additional_data[key], f"{object_path}/{key}").copy()
+                continue
+            # otherwise we cannot combine them
+            raise DataValidationError(f"duplicity key '{key}' with value in data", object_path)
+        val = additional_data[key]
+        data[key] = val.copy() if hasattr(val, "copy") else val
+    return data
diff --git a/tests/manager/utils/modeling/test_parsing.py b/tests/manager/utils/modeling/test_parsing.py
new file mode 100644 (file)
index 0000000..8218c29
--- /dev/null
@@ -0,0 +1,31 @@
+import copy
+from typing import Any, Dict
+
+import pytest
+from pytest import raises
+
+from knot_resolver.utils.modeling.exceptions import DataValidationError
+from knot_resolver.utils.modeling.parsing import data_combine
+
+# default data
+data_default = {"key1": {"inner11": False}}
+
+
+@pytest.mark.parametrize(
+    "val,res",
+    [
+        ({"key2": "value"}, {"key1": {"inner11": False}, "key2": "value"}),
+        ({"key2": {"inner21": True}}, {"key1": {"inner11": False}, "key2": {"inner21": True}}),
+        ({"key1": {"inner12": 5}}, {"key1": {"inner11": False, "inner12": 5}}),
+    ],
+)
+def test_data_combine_valid(val: Dict[Any, Any], res: Dict[Any, Any]) -> None:
+    data = copy.deepcopy(data_default)
+    assert data_combine(data, val) == res
+
+
+@pytest.mark.parametrize("val", [{"key1": "value"}, {"key1": {"inner11": False}}])
+def test_data_combine_invalid(val: Dict[Any, Any]) -> None:
+    data = copy.deepcopy(data_default)
+    with raises(DataValidationError):
+        data_combine(data, val)