-- -- --- --- --- --- --- --- ------- ------- ------- |
"""
-- -- --- --- --- --- --- --- ------- ------- ------- |
Report command.
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- |
The report command gives a table of metrics for a specified list of files.
-- -- --- --- --- --- --- --- ------- ------- ------- |
Will compare the values between revisions and highlight changes in green/red.
-- -- --- --- --- --- --- --- ------- ------- ------- |
"""
-- -- --- --- --- --- --- --- ------- ------- ------- |
import tabulate
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- |
from pathlib import Path
-- -- --- --- --- --- --- --- ------- ------- ------- |
from shutil import copytree
-- -- --- --- --- --- --- --- ------- ------- ------- |
from string import Template
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- |
from wily import logger, format_date, format_revision, MAX_MESSAGE_WIDTH
-- -- --- --- --- --- --- --- ------- ------- ------- |
from wily.helper.custom_enums import ReportFormat
-- -- --- --- --- --- --- --- ------- ------- ------- |
from wily.operators import resolve_metric_as_tuple, MetricType
-- -- --- --- --- --- --- --- ------- ------- ------- |
from wily.state import State
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
def report(
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
config,
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
path,
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
metrics,
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
n,
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
output,
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
include_message=False,
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
format=ReportFormat.CONSOLE,
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
console_format=None,
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
):
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
"""
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
Show information about the cache and runtime.
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
:param config: The configuration
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
:type config: :class:`wily.config.WilyConfig`
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
:param path: The path to the file
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
:type path: ``str``
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
:param metrics: Name of the metric to report on
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
:type metrics: ``str``
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
:param n: Number of items to list
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
:type n: ``int``
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
:param output: Output path
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
:type output: ``Path``
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
:param include_message: Include revision messages
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
:type include_message: ``bool``
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
:param format: Output format
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
:type format: ``ReportFormat``
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
:param console_format: Grid format style for tabulate
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
:type console_format: ``str``
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
"""
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
logger.debug("Running report command")
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
logger.info(f"-----------History for {metrics}------------")
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
data = []
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
metric_metas = []
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
for metric in metrics:
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
operator, metric = resolve_metric_as_tuple(metric)
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
key = metric.name
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
operator = operator.name
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
# Set the delta colors depending on the metric type
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
if metric.measure == MetricType.AimHigh:
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
good_color = 32
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
bad_color = 31
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
elif metric.measure == MetricType.AimLow:
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
good_color = 31
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
bad_color = 32
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
elif metric.measure == MetricType.Informational:
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
good_color = 33
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
bad_color = 33
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
metric_meta = {
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
"key": key,
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
"operator": operator,
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
"good_color": good_color,
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
"bad_color": bad_color,
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
"title": metric.description,
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
"type": metric.type,
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
}
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
metric_metas.append(metric_meta)
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
state = State(config)
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
for archiver in state.archivers:
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
history = state.index[archiver].revisions[:n][::-1]
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
last = {}
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
for rev in history:
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
vals = []
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
for meta in metric_metas:
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
try:
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
logger.debug(
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
f"Fetching metric {meta['key']} for {meta['operator']} in {path}"
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
)
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
val = rev.get(config, archiver, meta["operator"], path, meta["key"])
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
last_val = last.get(meta["key"], None)
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
# Measure the difference between this value and the last
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
if meta["type"] in (int, float):
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
if last_val:
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
delta = val - last_val
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
else:
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
delta = 0
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
last[meta["key"]] = val
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
else:
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
# TODO : Measure ranking increases/decreases for str types?
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
delta = 0
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
if delta == 0:
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
delta_col = delta
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
elif delta < 0:
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
delta_col = f"\u001b[{meta['good_color']}m{delta:n}\u001b[0m"
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
else:
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
delta_col = f"\u001b[{meta['bad_color']}m+{delta:n}\u001b[0m"
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
if meta["type"] in (int, float):
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
k = f"{val:n} ({delta_col})"
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
else:
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
k = f"{val}"
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
except KeyError as e:
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
k = f"Not found {e}"
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
vals.append(k)
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
if include_message:
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
data.append(
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
(
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
format_revision(rev.revision.key),
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
rev.revision.message[:MAX_MESSAGE_WIDTH],
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
rev.revision.author_name,
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
format_date(rev.revision.date),
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
*vals,
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
)
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
)
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
else:
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
data.append(
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
(
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
format_revision(rev.revision.key),
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
rev.revision.author_name,
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
format_date(rev.revision.date),
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
*vals,
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
)
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
)
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
descriptions = [meta["title"] for meta in metric_metas]
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
if include_message:
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
headers = ("Revision", "Message", "Author", "Date", *descriptions)
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
else:
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
headers = ("Revision", "Author", "Date", *descriptions)
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
if format == ReportFormat.HTML:
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
if output.is_file and output.suffix == ".html":
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
report_path = output.parents[0]
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
report_output = output
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
else:
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
report_path = output
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
report_output = output.joinpath("index.html")
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
report_path.mkdir(exist_ok=True, parents=True)
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
templates_dir = (Path(__file__).parents[1] / "templates").resolve()
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
report_template = Template((templates_dir / "report_template.html").read_text())
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
table_headers = "".join([f"<th>{header}</th>" for header in headers])
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
table_content = ""
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
for line in data[::-1]:
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
table_content += "<tr>"
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
for element in line:
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
element = element.replace("[32m", "<span class='green-color'>")
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
element = element.replace("[31m", "<span class='red-color'>")
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
element = element.replace("[33m", "<span class='orange-color'>")
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
element = element.replace("[0m", "</span>")
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
table_content += f"<td>{element}</td>"
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
table_content += "</tr>"
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
report_template = report_template.safe_substitute(
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
headers=table_headers, content=table_content
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
)
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
with report_output.open("w") as output:
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
output.write(report_template)
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
try:
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
copytree(str(templates_dir / "css"), str(report_path / "css"))
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
except FileExistsError:
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
pass
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
logger.info(f"wily report was saved to {report_path}")
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
else:
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
print(
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
tabulate.tabulate(
-- 24 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
headers=headers, tabular_data=data[::-1], tablefmt=console_format
-- -- 008 029 021 039 037 060 0312.57 1681.40 0005.38 |
)
-- -- --- --- --- --- --- --- ------- ------- ------- |
)