Skip to content

Commit ad7b965

Browse files
authored
Merge pull request #15 from jyejare/inverse_compare
Inverse Reporting - Shows whats not changed
2 parents ed4b1d9 + 885109f commit ad7b965

11 files changed

+181
-99
lines changed

6_14.yaml

-17
This file was deleted.

6_14_constants.yaml.template

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
expected_constants:
2+
# These are just examples, please replace these with some real expected constants
3+
hosts:
4+
content_facet_something: content_source_something_id
5+
6+
skipped_constants:
7+
# These are just examples, please replace these with some real skip-able constants
8+
content_view_versions:
9+
environments:
10+
permissions_something: something here

6_14_variations.yaml.template

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
expected_variations:
2+
# These are just examples, please replace these with some real expected variations
3+
hosts:
4+
content_facet_somevar: content_source_ssomevar_id
5+
6+
skipped_variations:
7+
# These are just examples, please replace these with some real skip-able variations
8+
content_view_versions:
9+
environments:
10+
permissions_somevar: somevar_here

candore/__init__.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,17 @@ def compare_entities(
5050
self,
5151
pre_file=None,
5252
post_file=None,
53+
inverse=None,
5354
output=None,
5455
report_type=None,
5556
record_evs=None,
5657
):
5758
comp = Comparator(settings=self.settings)
5859
if record_evs:
5960
comp.record_evs = True
60-
results = comp.compare_json(pre_file=pre_file, post_file=post_file)
61+
results = comp.compare_json(pre_file=pre_file, post_file=post_file, inverse=inverse)
6162
reporter = Reporting(results=results)
62-
reporter.generate_report(output_file=output, output_type=report_type)
63+
reporter.generate_report(output_file=output, output_type=report_type, inverse=inverse)
6364

6465
def find_path(self, path, json_file, delimiter):
6566
finder = Finder()

candore/cli.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ def extract(ctx, mode, output, full):
5454
@candore.command(help="Compare pre and post upgrade data")
5555
@click.option("--pre", type=str, help="The pre upgrade json file")
5656
@click.option("--post", type=str, help="The post upgrade json file")
57+
@click.option("-i", "--inverse", is_flag=True, help="Inverse comparison, shows whats not changed")
5758
@click.option("-o", "--output", type=str, help="The output file name")
5859
@click.option(
5960
"-t",
@@ -64,11 +65,12 @@ def extract(ctx, mode, output, full):
6465
)
6566
@click.option("--record-evs", is_flag=True, help="Record Expected Variations in reporting")
6667
@click.pass_context
67-
def compare(ctx, pre, post, output, report_type, record_evs):
68+
def compare(ctx, pre, post, inverse, output, report_type, record_evs):
6869
candore_obj = ctx.parent.candore
6970
candore_obj.compare_entities(
7071
pre_file=pre,
7172
post_file=post,
73+
inverse=inverse,
7274
output=output,
7375
report_type=report_type,
7476
record_evs=record_evs,

candore/modules/comparator.py

+68-29
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,25 @@
11
import json
22

3-
from candore.modules.variatons import Variations
4-
from candore.utils import last_index_of_element
3+
from candore.modules.variations import Variations, Constants
4+
from candore.utils import last_index_of_element, is_list_contains_dict
55

66

77
class Comparator:
88
def __init__(self, settings):
99
self.big_key = []
10-
self.big_compare = {}
10+
self.big_diff = {}
11+
self.big_constant = {}
1112
self.record_evs = False
1213
self.variations = Variations(settings)
14+
self.constants = Constants(settings)
1315
self.expected_variations = self.variations.expected_variations
1416
self.skipped_variations = self.variations.skipped_variations
17+
self.expected_constants = self.constants.expected_constants
18+
self.skipped_constants = self.constants.skipped_constants
1519

16-
def remove_non_variant_key(self, key):
20+
21+
22+
def remove_verifed_key(self, key):
1723
reversed_bk = self.big_key[::-1]
1824
if key in reversed_bk:
1925
reversed_bk.remove(key)
@@ -36,13 +42,32 @@ def record_variation(self, pre, post, var_details=None):
3642
"post": post,
3743
"variation": var_details or "Expected(A)",
3844
}
39-
self.big_compare.update({full_path: variation})
45+
self.big_diff.update({full_path: variation})
4046
elif (
4147
var_full_path not in self.expected_variations
4248
and var_full_path not in self.skipped_variations
4349
):
4450
variation = {"pre": pre, "post": post, "variation": var_details or ""}
45-
self.big_compare.update({full_path: variation})
51+
self.big_diff.update({full_path: variation})
52+
53+
def record_constants(self, pre, post, var_details=None):
54+
big_key = [str(itm) for itm in self.big_key]
55+
full_path = "/".join(big_key)
56+
var_full_path = "/".join([itm for itm in self.big_key if not isinstance(itm, int)])
57+
if var_full_path in self.expected_constants or var_full_path in self.skipped_constants:
58+
if self.record_evs:
59+
variation = {
60+
"pre": pre,
61+
"post": post,
62+
"constant": var_details or "Expected(A)",
63+
}
64+
self.big_constant.update({full_path: variation})
65+
elif (
66+
var_full_path not in self.expected_constants
67+
and var_full_path not in self.skipped_constants
68+
):
69+
variation = {"pre": pre, "post": post, "constant": var_details or ""}
70+
self.big_constant.update({full_path: variation})
4671

4772
def _is_data_type_dict(self, pre, post, unique_key=""):
4873
if (pre and 'id' in pre) and (post and 'id' in post):
@@ -62,32 +87,41 @@ def _is_data_type_dict(self, pre, post, unique_key=""):
6287
)
6388
self.remove_path(unique_key)
6489

65-
def _is_data_type_list(self, pre, post, unique_key=""):
90+
def _is_data_type_list_contains_dict(self, pre, post):
6691
for pre_entity in pre:
6792
if not pre_entity:
6893
continue
69-
if type(pre_entity) is dict:
70-
for post_entity in post:
71-
if not post_entity:
72-
continue
73-
if "id" in pre_entity:
74-
if pre_entity["id"] == post_entity["id"]:
75-
self.compare_all_pres_with_posts(
76-
pre_entity, post_entity, unique_key=pre_entity["id"]
77-
)
78-
else:
79-
key = list(pre_entity.keys())[0]
80-
if pre_entity[key] == post_entity[key]:
81-
self.compare_all_pres_with_posts(
82-
pre_entity[key], post_entity[key], unique_key=key
83-
)
94+
for post_entity in post:
95+
if not post_entity:
96+
continue
8497
if "id" in pre_entity:
85-
self.remove_path(pre_entity["id"])
98+
if pre_entity["id"] == post_entity["id"]:
99+
self.compare_all_pres_with_posts(
100+
pre_entity, post_entity, unique_key=pre_entity["id"]
101+
)
86102
else:
87-
self.remove_path(pre_entity[list(pre_entity.keys())[0]])
103+
key = list(pre_entity.keys())[0]
104+
if pre_entity[key] == post_entity[key]:
105+
self.compare_all_pres_with_posts(
106+
pre_entity[key], post_entity[key], unique_key=key
107+
)
108+
if "id" in pre_entity:
109+
self.remove_path(pre_entity["id"])
88110
else:
89-
if pre_entity not in post:
90-
self.record_variation(pre, post)
111+
self.remove_path(pre_entity[list(pre_entity.keys())[0]])
112+
113+
def _is_data_type_list(self, pre, post, unique_key=""):
114+
115+
def custom_key(elem):
116+
return 'None' if elem is None else str(elem)
117+
118+
if not is_list_contains_dict(pre):
119+
if sorted(pre, key=custom_key) != sorted(post, key=custom_key):
120+
self.record_variation(pre, post)
121+
else:
122+
self.record_constants(pre, post)
123+
else:
124+
self._is_data_type_list_contains_dict(pre, post)
91125
self.remove_path(unique_key)
92126

93127
def compare_all_pres_with_posts(self, pre_data, post_data, unique_key="", var_details=None):
@@ -100,9 +134,11 @@ def compare_all_pres_with_posts(self, pre_data, post_data, unique_key="", var_de
100134
else:
101135
if pre_data != post_data:
102136
self.record_variation(pre_data, post_data, var_details)
103-
self.remove_non_variant_key(unique_key)
137+
else:
138+
self.record_constants(pre_data, post_data, var_details)
139+
self.remove_verifed_key(unique_key)
104140

105-
def compare_json(self, pre_file, post_file):
141+
def compare_json(self, pre_file, post_file, inverse):
106142
pre_data = post_data = None
107143

108144
with open(pre_file, "r") as fpre:
@@ -112,4 +148,7 @@ def compare_json(self, pre_file, post_file):
112148
post_data = json.load(fpost)
113149

114150
self.compare_all_pres_with_posts(pre_data, post_data)
115-
return self.big_compare
151+
if not inverse:
152+
return self.big_diff
153+
else:
154+
return self.big_constant

candore/modules/report.py

+12-6
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,13 @@ def __init__(self, results):
1717
"""
1818
self.results = results
1919

20-
def generate_report(self, output_file, output_type):
20+
def generate_report(self, output_file, output_type, inverse):
2121
"""Generate a report of the compared results
2222
2323
Args:
2424
output_file (str): The file to write the report to
2525
output_type (str): The type of report to generate json / CSV
26+
inverse (bool): Shows what not changed in comparison results
2627
Returns:
2728
None
2829
Raises:
@@ -31,9 +32,9 @@ def generate_report(self, output_file, output_type):
3132
if output_type == "json":
3233
self._generate_json_report(output_file)
3334
elif output_type == "html":
34-
self._generate_html_report()
35+
print('The HTML reporting is not implemented yet! Try next time!')
3536
elif output_type == "csv":
36-
self._generate_csv_report(output_file)
37+
self._generate_csv_report(output_file, inverse=inverse)
3738
else:
3839
raise ValueError("Output type {} not supported".format(output_type))
3940

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

68-
def _generate_csv_report(self, output_file):
69+
def _generate_csv_report(self, output_file, inverse):
6970
"""Generate a CSV report of the compared results
7071
7172
Args:
@@ -78,8 +79,13 @@ def _generate_csv_report(self, output_file):
7879
output_file = Path(output_file)
7980
# Convert json to csv and write to output file
8081
csv_writer = csv.writer(output_file.open("w"))
81-
csv_writer.writerow(["Variation Path", "Pre-Upgrade", "Post-Upgrade", "Variation"])
82+
# Table Column Names
83+
columns = ["Path", "Pre-Upgrade", "Post-Upgrade", "Variation?" if not inverse else 'Constant?']
84+
csv_writer.writerow(columns)
85+
# Writing Rows
8286
for var_path, vals in self.results.items():
83-
csv_writer.writerow([var_path, vals["pre"], vals["post"], vals["variation"]])
87+
csv_writer.writerow([
88+
var_path, vals["pre"], vals["post"],
89+
vals["variation" if not inverse else "constant"]])
8490
print("Wrote CSV report to {}".format(output_file))
8591
print("CSV report contains {} results".format(len(self.results)))

candore/modules/variations.py

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
"""
2+
A module responsible for calculating expected and skipped variations from
3+
`conf/variations` yaml file and convert them into processable list
4+
"""
5+
from functools import cached_property
6+
from candore.utils import yaml_reader, get_yaml_paths
7+
8+
import yaml
9+
10+
11+
class Variations:
12+
def __init__(self, settings):
13+
self.settings = settings
14+
15+
@cached_property
16+
def variations(self):
17+
yaml_data = yaml_reader(file_path=self.settings.candore.var_file)
18+
return yaml_data
19+
20+
@cached_property
21+
def expected_variations(self):
22+
return get_yaml_paths(yaml_data=self.variations.get("expected_variations"))
23+
24+
@cached_property
25+
def skipped_variations(self):
26+
return get_yaml_paths(yaml_data=self.variations.get("skipped_variations"))
27+
28+
29+
class Constants:
30+
def __init__(self, settings):
31+
self.settings = settings
32+
33+
@cached_property
34+
def constants(self):
35+
yaml_data = yaml_reader(file_path=self.settings.candore.constant_file)
36+
return yaml_data
37+
38+
@cached_property
39+
def expected_constants(self):
40+
return get_yaml_paths(yaml_data=self.constants.get("expected_constants"))
41+
42+
@cached_property
43+
def skipped_constants(self):
44+
return get_yaml_paths(yaml_data=self.constants.get("skipped_constants"))

candore/modules/variatons.py

-43
This file was deleted.

0 commit comments

Comments
 (0)