Skip to content

Commit

Permalink
Inverse Reporting - Shows whats not changed
Browse files Browse the repository at this point in the history
  • Loading branch information
jyejare committed Apr 17, 2024
1 parent c10932c commit 0c7018d
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 34 deletions.
5 changes: 3 additions & 2 deletions candore/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,17 @@ def compare_entities(
self,
pre_file=None,
post_file=None,
inverse=None,
output=None,
report_type=None,
record_evs=None,
):
comp = Comparator(settings=self.settings)
if record_evs:
comp.record_evs = True
results = comp.compare_json(pre_file=pre_file, post_file=post_file)
results = comp.compare_json(pre_file=pre_file, post_file=post_file, inverse=inverse)
reporter = Reporting(results=results)
reporter.generate_report(output_file=output, output_type=report_type)
reporter.generate_report(output_file=output, output_type=report_type, inverse=inverse)

def find_path(self, path, json_file, delimiter):
finder = Finder()
Expand Down
4 changes: 3 additions & 1 deletion candore/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ def extract(ctx, mode, output, full):
@candore.command(help="Compare pre and post upgrade data")
@click.option("--pre", type=str, help="The pre upgrade json file")
@click.option("--post", type=str, help="The post upgrade json file")
@click.option("-i", "--inverse", is_flag=True, help="Inverse comparison, shows whats not changed")
@click.option("-o", "--output", type=str, help="The output file name")
@click.option(
"-t",
Expand All @@ -64,11 +65,12 @@ def extract(ctx, mode, output, full):
)
@click.option("--record-evs", is_flag=True, help="Record Expected Variations in reporting")
@click.pass_context
def compare(ctx, pre, post, output, report_type, record_evs):
def compare(ctx, pre, post, inverse, output, report_type, record_evs):
candore_obj = ctx.parent.candore
candore_obj.compare_entities(
pre_file=pre,
post_file=post,
inverse=inverse,
output=output,
report_type=report_type,
record_evs=record_evs,
Expand Down
72 changes: 47 additions & 25 deletions candore/modules/comparator.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import json

from candore.modules.variatons import Variations
from candore.utils import last_index_of_element
from candore.utils import last_index_of_element, is_list_contains_dict


class Comparator:
def __init__(self, settings):
self.big_key = []
self.big_compare = {}
self.big_constant = {}
self.record_evs = False
self.variations = Variations(settings)
self.expected_variations = self.variations.expected_variations
self.skipped_variations = self.variations.skipped_variations

def remove_non_variant_key(self, key):
def remove_verifed_key(self, key):
reversed_bk = self.big_key[::-1]
if key in reversed_bk:
reversed_bk.remove(key)
Expand Down Expand Up @@ -44,6 +45,13 @@ def record_variation(self, pre, post, var_details=None):
variation = {"pre": pre, "post": post, "variation": var_details or ""}
self.big_compare.update({full_path: variation})

def record_constants(self, pre, post):
big_key = [str(itm) for itm in self.big_key]
full_path = "/".join(big_key)
# var_full_path = "/".join([itm for itm in self.big_key if not isinstance(itm, int)])
variation = {"pre": pre, "post": post}
self.big_constant.update({full_path: variation})

def _is_data_type_dict(self, pre, post, unique_key=""):
if (pre and 'id' in pre) and (post and 'id' in post):
# Dont compare the entities if the ids are not the same
Expand All @@ -62,32 +70,41 @@ def _is_data_type_dict(self, pre, post, unique_key=""):
)
self.remove_path(unique_key)

def _is_data_type_list(self, pre, post, unique_key=""):
def _is_data_type_list_contains_dict(self, pre, post):
for pre_entity in pre:
if not pre_entity:
continue
if type(pre_entity) is dict:
for post_entity in post:
if not post_entity:
continue
if "id" in pre_entity:
if pre_entity["id"] == post_entity["id"]:
self.compare_all_pres_with_posts(
pre_entity, post_entity, unique_key=pre_entity["id"]
)
else:
key = list(pre_entity.keys())[0]
if pre_entity[key] == post_entity[key]:
self.compare_all_pres_with_posts(
pre_entity[key], post_entity[key], unique_key=key
)
for post_entity in post:
if not post_entity:
continue
if "id" in pre_entity:
self.remove_path(pre_entity["id"])
if pre_entity["id"] == post_entity["id"]:
self.compare_all_pres_with_posts(
pre_entity, post_entity, unique_key=pre_entity["id"]
)
else:
self.remove_path(pre_entity[list(pre_entity.keys())[0]])
key = list(pre_entity.keys())[0]
if pre_entity[key] == post_entity[key]:
self.compare_all_pres_with_posts(
pre_entity[key], post_entity[key], unique_key=key
)
if "id" in pre_entity:
self.remove_path(pre_entity["id"])
else:
self.remove_path(pre_entity[list(pre_entity.keys())[0]])

def _is_data_type_list(self, pre, post, unique_key=""):

def custom_key(elem):
return 'None' if elem is None else elem

if not is_list_contains_dict(pre):
if sorted(pre, key=custom_key) != sorted(post, key=custom_key):
self.record_variation(pre, post)
else:
if pre_entity not in post:
self.record_variation(pre, post)
self.record_constants(pre, post)
else:
self._is_data_type_list_contains_dict(pre, post)
self.remove_path(unique_key)

def compare_all_pres_with_posts(self, pre_data, post_data, unique_key="", var_details=None):
Expand All @@ -100,9 +117,11 @@ def compare_all_pres_with_posts(self, pre_data, post_data, unique_key="", var_de
else:
if pre_data != post_data:
self.record_variation(pre_data, post_data, var_details)
self.remove_non_variant_key(unique_key)
else:
self.record_constants(pre_data, post_data)
self.remove_verifed_key(unique_key)

def compare_json(self, pre_file, post_file):
def compare_json(self, pre_file, post_file, inverse):
pre_data = post_data = None

with open(pre_file, "r") as fpre:
Expand All @@ -112,4 +131,7 @@ def compare_json(self, pre_file, post_file):
post_data = json.load(fpost)

self.compare_all_pres_with_posts(pre_data, post_data)
return self.big_compare
if not inverse:
return self.big_compare
else:
return self.big_constant
16 changes: 10 additions & 6 deletions candore/modules/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ def __init__(self, results):
"""
self.results = results

def generate_report(self, output_file, output_type):
def generate_report(self, output_file, output_type, inverse):
"""Generate a report of the compared results
Args:
output_file (str): The file to write the report to
output_type (str): The type of report to generate json / CSV
inverse (bool): Shows what not changed in comparison results
Returns:
None
Raises:
Expand All @@ -31,9 +32,9 @@ def generate_report(self, output_file, output_type):
if output_type == "json":
self._generate_json_report(output_file)
elif output_type == "html":
self._generate_html_report()
print('The HTML reporting is not implemented yet! Try next time!')
elif output_type == "csv":
self._generate_csv_report(output_file)
self._generate_csv_report(output_file, inverse=inverse)
else:
raise ValueError("Output type {} not supported".format(output_type))

Expand Down Expand Up @@ -65,7 +66,7 @@ def _generate_html_report(self):
# render_webpage()
print("HTML report is ready to view at: http://localhost:5000")

def _generate_csv_report(self, output_file):
def _generate_csv_report(self, output_file, inverse):
"""Generate a CSV report of the compared results
Args:
Expand All @@ -78,8 +79,11 @@ def _generate_csv_report(self, output_file):
output_file = Path(output_file)
# Convert json to csv and write to output file
csv_writer = csv.writer(output_file.open("w"))
csv_writer.writerow(["Variation Path", "Pre-Upgrade", "Post-Upgrade", "Variation"])
# Table Column Names
columns = ["Path", "Pre-Upgrade", "Post-Upgrade", "Variation?" if not inverse else 'Constant?']
csv_writer.writerow(columns)
# Writing Rows
for var_path, vals in self.results.items():
csv_writer.writerow([var_path, vals["pre"], vals["post"], vals["variation"]])
csv_writer.writerow([var_path, vals["pre"], vals["post"], vals.get('variation', None)])
print("Wrote CSV report to {}".format(output_file))
print("CSV report contains {} results".format(len(self.results)))
5 changes: 5 additions & 0 deletions candore/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,8 @@ def last_index_of_element(arr, element):
if arr[i] == element:
return i
return -1


def is_list_contains_dict(_list):
contains_dict = any(isinstance(element, dict) for element in _list)
return contains_dict

0 comments on commit 0c7018d

Please sign in to comment.