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