From b1efc5c49da1ccf47b44556e5b7e40aa598b39ae Mon Sep 17 00:00:00 2001 From: Jorrit Schaap <schaap@astron.nl> Date: Thu, 8 Jul 2021 12:18:00 +0200 Subject: [PATCH] TMSS-745: fixed dict_with_overrides for nested lists in the dict(s) --- LCS/PyCommon/test/t_util.py | 30 +++++++++++++++++++++++++++++- LCS/PyCommon/util.py | 24 +++++++++++++++++++----- 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/LCS/PyCommon/test/t_util.py b/LCS/PyCommon/test/t_util.py index fdb48f516ca..77971885fb7 100644 --- a/LCS/PyCommon/test/t_util.py +++ b/LCS/PyCommon/test/t_util.py @@ -14,9 +14,10 @@ def setUpModule(): def tearDownModule(): pass + +@unit_test class TestUtils(unittest.TestCase): - @unit_test def test_is_iterable(self): #list self.assertTrue(is_iterable([])) @@ -36,6 +37,33 @@ class TestUtils(unittest.TestCase): self.assertFalse(is_iterable(1)) self.assertFalse(is_iterable(None)) + def test_merge_nested_dicts(self): + dict_a = {'a': 1, + 'b': { + 'c': 3, + 'd': [4, 5, 6]}, + 'e': [{'foo': 1}, + {'bar': 2}]} + + dict_b = {'a': 2} + merged = dict_with_overrides(dict_a, dict_b) + self.assertEqual({'a': 2, 'b': {'c': 3, 'd': [4, 5, 6]}, 'e': [{'foo': 1}, {'bar': 2}]}, merged) + + dict_b = {'a': 1, 'b': 2} + merged = dict_with_overrides(dict_a, dict_b) + self.assertEqual({'a': 1, 'b': 2, 'e': [{'foo': 1}, {'bar': 2}]}, merged) + + dict_b = {'b': {'c': 4}} + merged = dict_with_overrides(dict_a, dict_b) + self.assertEqual({'a': 1, 'b': {'c': 4, 'd': [4, 5, 6]}, 'e': [{'foo': 1}, {'bar': 2}]}, merged) + + dict_b = {'e': [{'foo': 2}, {'bar': 3}]} + merged = dict_with_overrides(dict_a, dict_b) + self.assertEqual({'a': 1, 'b': {'c': 3, 'd': [4, 5, 6]}, 'e': [{'foo': 2}, {'bar': 3}]}, merged) + + with self.assertRaises(AssertionError): + dict_b = {'e': []} #AssertionError should be raised cause list is not of same length as original + dict_with_overrides(dict_a, dict_b) def main(argv): unittest.main() diff --git a/LCS/PyCommon/util.py b/LCS/PyCommon/util.py index 71204a9ced3..541937c640c 100644 --- a/LCS/PyCommon/util.py +++ b/LCS/PyCommon/util.py @@ -28,7 +28,8 @@ import sys import os, os.path import time from copy import deepcopy - +import logging +logger = logging.getLogger(__name__) def check_bit(value, bit): """ @@ -235,13 +236,26 @@ def dict_search_and_replace(d: dict, key, value): dict_search_and_replace(i, key, value) -def dict_with_overrides(org_dict: dict, overrides_dict: dict) -> dict: +def dict_with_overrides(org_dict: dict, overrides: dict) -> dict: '''return a copy of the original (nested) org_dict with all (nested) key/value pairs in the overrides_dict applied''' new_dict = deepcopy(org_dict) - for override_key, override_value in overrides_dict.items(): - # recurse + + for override_key, override_value in overrides.items(): if isinstance(override_value, dict): - new_dict[override_key] = dict_with_overrides(org_dict.get(override_key,{}), override_value) + sub_dict = new_dict.get(override_key, {}) + new_dict[override_key] = dict_with_overrides(sub_dict, override_value) + elif isinstance(override_value, list): + sub_list = new_dict.get(override_key, []) + assert isinstance(sub_list, list) + assert len(sub_list) == len(override_value) + + for i in range(len(override_value)): + org_list_item = sub_list[i] + override_list_item = override_value[i] + if isinstance(org_list_item, dict) and isinstance(override_list_item, dict): + new_dict[override_key][i] = dict_with_overrides(org_list_item, override_list_item) + else: + new_dict[override_key][i] = override_list_item else: new_dict[override_key] = override_value -- GitLab