_comparator_result.py 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. # Copyright 2023 Avaiga Private Limited
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
  4. # the License. You may obtain a copy of the License at
  5. #
  6. # http://www.apache.org/licenses/LICENSE-2.0
  7. #
  8. # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
  9. # an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
  10. # specific language governing permissions and limitations under the License.
  11. import re
  12. from typing import Dict, List, Set
  13. from .._serializer._json_serializer import _JsonSerializer
  14. class _ComparatorResult(dict):
  15. ADDED_ITEMS_KEY = "added_items"
  16. REMOVED_ITEMS_KEY = "removed_items"
  17. MODIFIED_ITEMS_KEY = "modified_items"
  18. CONFLICTED_SECTION_KEY = "conflicted_sections"
  19. UNCONFLICTED_SECTION_KEY = "unconflicted_sections"
  20. def __init__(self, unconflicted_sections: Set[str]):
  21. super().__init__()
  22. self._unconflicted_sections = unconflicted_sections
  23. def _sort_by_section(self):
  24. if self.get(self.CONFLICTED_SECTION_KEY):
  25. for key in self[self.CONFLICTED_SECTION_KEY].keys():
  26. self[self.CONFLICTED_SECTION_KEY][key].sort(key=lambda x: x[0][0])
  27. if self.get(self.UNCONFLICTED_SECTION_KEY):
  28. for key in self[self.UNCONFLICTED_SECTION_KEY].keys():
  29. self[self.UNCONFLICTED_SECTION_KEY][key].sort(key=lambda x: x[0][0])
  30. def _check_added_items(self, config_deepdiff, new_json_config):
  31. if dictionary_item_added := config_deepdiff.get("dictionary_item_added"):
  32. for item_added in dictionary_item_added:
  33. section_name, config_id, attribute = self.__get_changed_entity_attribute(item_added)
  34. diff_sections = self.__get_section(section_name)
  35. if attribute:
  36. value_added = new_json_config[section_name][config_id][attribute]
  37. elif config_id:
  38. value_added = new_json_config[section_name][config_id]
  39. else:
  40. value_added = new_json_config[section_name]
  41. section_name = self.__rename_global_node_name(section_name)
  42. self.__create_or_append_list(
  43. diff_sections,
  44. self.ADDED_ITEMS_KEY,
  45. ((section_name, config_id, attribute), (value_added)),
  46. )
  47. def _check_removed_items(self, config_deepdiff, old_json_config):
  48. if dictionary_item_removed := config_deepdiff.get("dictionary_item_removed"):
  49. for item_removed in dictionary_item_removed:
  50. section_name, config_id, attribute = self.__get_changed_entity_attribute(item_removed)
  51. diff_sections = self.__get_section(section_name)
  52. if attribute:
  53. value_removed = old_json_config[section_name][config_id][attribute]
  54. elif config_id:
  55. value_removed = old_json_config[section_name][config_id]
  56. else:
  57. value_removed = old_json_config[section_name]
  58. section_name = self.__rename_global_node_name(section_name)
  59. self.__create_or_append_list(
  60. diff_sections,
  61. self.REMOVED_ITEMS_KEY,
  62. ((section_name, config_id, attribute), (value_removed)),
  63. )
  64. def _check_modified_items(self, config_deepdiff, old_json_config, new_json_config):
  65. if values_changed := config_deepdiff.get("values_changed"):
  66. for item_changed, value_changed in values_changed.items():
  67. section_name, config_id, attribute = self.__get_changed_entity_attribute(item_changed)
  68. diff_sections = self.__get_section(section_name)
  69. section_name = self.__rename_global_node_name(section_name)
  70. self.__create_or_append_list(
  71. diff_sections,
  72. self.MODIFIED_ITEMS_KEY,
  73. ((section_name, config_id, attribute), (value_changed["old_value"], value_changed["new_value"])),
  74. )
  75. # Iterable item added will be considered a modified item
  76. if iterable_item_added := config_deepdiff.get("iterable_item_added"):
  77. self.__check_modified_iterable(iterable_item_added, old_json_config, new_json_config)
  78. # Iterable item removed will be considered a modified item
  79. if iterable_item_removed := config_deepdiff.get("iterable_item_removed"):
  80. self.__check_modified_iterable(iterable_item_removed, old_json_config, new_json_config)
  81. def __check_modified_iterable(self, iterable_items, old_json_config, new_json_config):
  82. for item in iterable_items:
  83. section_name, config_id, attribute = self.__get_changed_entity_attribute(item)
  84. diff_sections = self.__get_section(section_name)
  85. if attribute:
  86. new_value = new_json_config[section_name][config_id][attribute]
  87. old_value = old_json_config[section_name][config_id][attribute]
  88. else:
  89. new_value = new_json_config[section_name][config_id]
  90. old_value = old_json_config[section_name][config_id]
  91. section_name = self.__rename_global_node_name(section_name)
  92. modified_value = ((section_name, config_id, attribute), (old_value, new_value))
  93. if (
  94. not diff_sections.get(self.MODIFIED_ITEMS_KEY)
  95. or modified_value not in diff_sections[self.MODIFIED_ITEMS_KEY]
  96. ):
  97. self.__create_or_append_list(
  98. diff_sections,
  99. self.MODIFIED_ITEMS_KEY,
  100. modified_value,
  101. )
  102. def __get_section(self, section_name: str) -> Dict[str, List]:
  103. if section_name in self._unconflicted_sections:
  104. if not self.get(self.UNCONFLICTED_SECTION_KEY):
  105. self[self.UNCONFLICTED_SECTION_KEY] = {}
  106. return self[self.UNCONFLICTED_SECTION_KEY]
  107. if not self.get(self.CONFLICTED_SECTION_KEY):
  108. self[self.CONFLICTED_SECTION_KEY] = {}
  109. return self[self.CONFLICTED_SECTION_KEY]
  110. def __create_or_append_list(self, diff_dict, key, value):
  111. if diff_dict.get(key):
  112. diff_dict[key].append(value)
  113. else:
  114. diff_dict[key] = [value]
  115. def __get_changed_entity_attribute(self, attribute_bracket_notation):
  116. """Split the section name, the config id (if exists), and the attribute name (if exists)
  117. from JSON bracket notation.
  118. """
  119. try:
  120. section_name, config_id, attribute = re.findall(r"\[\'(.*?)\'\]", attribute_bracket_notation)
  121. except ValueError:
  122. try:
  123. section_name, config_id = re.findall(r"\[\'(.*?)\'\]", attribute_bracket_notation)
  124. attribute = None
  125. except ValueError:
  126. section_name = re.findall(r"\[\'(.*?)\'\]", attribute_bracket_notation)[0]
  127. config_id = None
  128. attribute = None
  129. return section_name, config_id, attribute
  130. def __rename_global_node_name(self, node_name):
  131. if node_name == _JsonSerializer._GLOBAL_NODE_NAME:
  132. return "Global Configuration"
  133. return node_name