From: Aleš Mrázek Date: Thu, 19 Jun 2025 18:45:26 +0000 (+0200) Subject: python: utils/modeling/parsing.py: 'data_combine' function for combining dictionaries... X-Git-Tag: v6.0.15~9^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f50b7777f1e60a104d81ccdeb90699a04abd6ad7;p=thirdparty%2Fknot-resolver.git python: utils/modeling/parsing.py: 'data_combine' function for combining dictionaries data --- diff --git a/python/knot_resolver/utils/modeling/parsing.py b/python/knot_resolver/utils/modeling/parsing.py index 593f6ca17..dc6cec6cc 100644 --- a/python/knot_resolver/utils/modeling/parsing.py +++ b/python/knot_resolver/utils/modeling/parsing.py @@ -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 index 000000000..8218c298a --- /dev/null +++ b/tests/manager/utils/modeling/test_parsing.py @@ -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)