Skip to content

Commit

Permalink
improved pretty print and report template
Browse files Browse the repository at this point in the history
  • Loading branch information
vik378 committed Oct 6, 2023
1 parent 143f69b commit 217513d
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 20 deletions.
82 changes: 72 additions & 10 deletions pretty_print.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,60 @@ def html_constructor(loader, node):
yaml.add_constructor("!html", html_constructor, Loader=yaml.FullLoader)


def generate_diff(previous, current):
def diff_text(previous, current):
dmp = diff_match_patch()
diff = dmp.diff_main("\n".join(previous), "\n".join(current))
dmp.diff_cleanupSemantic(diff)
return dmp.diff_prettyHtml(diff)

def diff_objects(previous, current):
"""return html where previous display_name is shon in red and strike-through,
followed by arrow sign and current display_name in green"""
return f"<del>{previous['display_name']}</del> → <ins>{current['display_name']}</ins>"


def diff_lists(previous, current):
out = []
previous = {item["uuid"]: item for item in previous}
for item in current:
if item["uuid"] not in previous:
out.append(f"<li><ins>{item}</ins></li>")
elif item["uuid"] in previous:
if item["display_name"] != previous[item["uuid"]]["display_name"]:
out.append(f"<li>{diff_objects(previous[item['uuid']], item)}</li>")
else:
out.append(f"<li>{item['display_name']}</li>")
current = {item["uuid"]: item for item in current}
for item in previous:
if item not in current:
out.append(f"<li><del>{previous[item]['display_name']}</del></li>")
return "<ul>" + "".join(out) + "</ul>"



def traverse_and_diff(data):
"""For every key "name" or "description" if it has
child keys "previous" and "current" we perform HtmlDiff
and store result in a new child key "diff".
"""
updates = {}
for key, value in data.items():
if key in ["name", "description"] \
and isinstance(value, dict) \
and "previous" in value \
and "current" in value:
diff = generate_diff(
value["previous"].splitlines(),
value["current"].splitlines()
)
updates[key] = {"diff": diff}
if isinstance(value, dict) and "previous" in value and "current" in value:
prev_type = type(value["previous"])
curr_type = type(value["current"])
if prev_type == curr_type == str:
diff = diff_text(
value["previous"].splitlines(),
value["current"].splitlines()
)
updates[key] = {"diff": diff}
elif prev_type == curr_type == dict:
diff = diff_objects(value["previous"], value["current"])
updates[key] = {"diff": diff}
elif prev_type == curr_type == list:
diff = diff_lists(value["previous"], value["current"])
updates[key] = {"diff": diff}

elif isinstance(value, list):
for item in value:
traverse_and_diff(item)
Expand All @@ -42,6 +74,35 @@ def traverse_and_diff(data):
data[key].update(value)
return data

def compute_diff_stats(data):
"""We need to compute the quantity of created, modified and deleted items and
sum those up for each category and subcategory, like so:
1. when the child branch has lists of deletions, creations or modifications we return stats with lengths of those lists as values
2. we aggregate (sum) those stats for each category and subcategory
3. we add stats key + value to each category and subcategory
"""
stats = {}
if isinstance(data, dict):
if "created" in data:
stats["created"] = len(data["created"])
if "modified" in data:
stats["modified"] = len(data["modified"])
if "deleted" in data:
stats["deleted"] = len(data["deleted"])
if not stats:
for key, value in data.items():
if isinstance(value, dict):
child_stats = compute_diff_stats(value)
if "created" in child_stats:
stats["created"] = stats.get("created", 0) + child_stats["created"]
if "modified" in child_stats:
stats["modified"] = stats.get("modified", 0) + child_stats["modified"]
if "deleted" in child_stats:
stats["deleted"] = stats.get("deleted", 0) + child_stats["deleted"]
data["stats"] = stats
return stats


@click.command()
@click.argument("filename")
Expand All @@ -50,6 +111,7 @@ def main(filename):
data = yaml.load(f, Loader=yaml.FullLoader)
env = Environment(loader=FileSystemLoader("."))
template = env.get_template("report.html.j2")
compute_diff_stats(data)
html = template.render(data=traverse_and_diff(data))
with open("report.html", "w") as f:
f.write(html)
Expand Down
24 changes: 14 additions & 10 deletions report.html.j2
Original file line number Diff line number Diff line change
Expand Up @@ -36,23 +36,27 @@
<h1>Model Change Assessment Report</h1>
<p><b>Current model:</b> {{ data["metadata"]["new-revision"] }}</p>
<p><b>Previous model:</b> {{ data["metadata"]["old-revision"] }}</p>
<h1>Object Changes</h1>
<h1>Object Changes {{ data["objects"].stats }}</h1>
<p><b>Disclaimer:</b> current version of model comparison engine uses a selected list of objects of interest and will not report object changes for object types that were considered as "out of scope". For the objects of interest however we can assure completness and correctness of comparison.</p>
<div class="section">
{% set LAYER = {"oa": "Operational Analysis", "sa": "System Analysis", "la": "Logical Architecture", "pa": "Physical Architecture"}%}
{% for layer in ["oa", "sa", "la", "pa"] %}
<h2>{{LAYER[layer]}}</h2>
{% set layer_data = data["objects"][layer] %}
{% if layer_data %}
<h2>{{LAYER[layer]}} {{ layer_data.stats }}</h2>
{% endif %}

<div class="section">
{% for obj_type in data["objects"][layer] %}
{% for obj_type in data["objects"][layer] if obj_type != "stats" %}
{% set obj_type_items = data["objects"][layer][obj_type] %}
<h3>{{obj_type}}</h3>
<h3>{{obj_type}} {{obj_type_items.stats}}</h3>
<div class="created-modified-delited">
{% if "created" in obj_type_items %}
<h4 style="color: #009900">Created</h4>
<div class="section">
<ul>
{% for obj in obj_type_items["created"] %}
<li>{{obj["name"]}}</li>
<li>{{obj["display_name"]}}</li>
{% endfor %}
</ul>
</div>
Expand All @@ -64,12 +68,12 @@
{% for obj in obj_type_items["modified"] %}
<p><b>{{ obj["display_name"] }}</b></p>
<ul>
{% for change in obj["changes"] %}
{% for change in obj["attributes"] %}
<li><b>{{ change }}</b>:
{% if "diff" in obj["changes"][change] %}
{{ obj["changes"][change]["diff"] }}
{% if "diff" in obj["attributes"][change] %}
{{ obj["attributes"][change]["diff"] }}
{% else %}
{{ obj["changes"][change]["previous"] }} -> {{ obj["changes"][change]["current"] }}
{{ obj["attributes"][change]["previous"] }} -> {{ obj["attributes"][change]["current"] }}
{% endif %}
</li>
{% endfor %}
Expand All @@ -83,7 +87,7 @@
<div class="section">
<ul>
{% for obj in obj_type_items["deleted"] %}
<li>{{obj["name"]}}</li>
<li>{{obj["display_name"]}}</li>
{% endfor %}
</ul>
</div>
Expand Down

0 comments on commit 217513d

Please sign in to comment.