wily\commands\diff.py
-- -- --- --- --- --- --- --- ------- ------- ------- | """
-- -- --- --- --- --- --- --- ------- ------- ------- | Diff command.
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- | Compares metrics between uncommitted files and indexed files.
-- -- --- --- --- --- --- --- ------- ------- ------- | """
-- -- --- --- --- --- --- --- ------- ------- ------- | import multiprocessing
-- -- --- --- --- --- --- --- ------- ------- ------- | import tabulate
-- -- --- --- --- --- --- --- ------- ------- ------- | from pathlib import Path
-- -- --- --- --- --- --- --- ------- ------- ------- | from wily import logger
-- -- --- --- --- --- --- --- ------- ------- ------- | from wily.config import DEFAULT_GRID_STYLE, DEFAULT_PATH
-- -- --- --- --- --- --- --- ------- ------- ------- | from wily.operators import (
-- -- --- --- --- --- --- --- ------- ------- ------- | resolve_metric,
-- -- --- --- --- --- --- --- ------- ------- ------- | resolve_operator,
-- -- --- --- --- --- --- --- ------- ------- ------- | get_metric,
-- -- --- --- --- --- --- --- ------- ------- ------- | GOOD_COLORS,
-- -- --- --- --- --- --- --- ------- ------- ------- | BAD_COLORS,
-- -- --- --- --- --- --- --- ------- ------- ------- | OperatorLevel,
-- -- --- --- --- --- --- --- ------- ------- ------- | )
-- -- --- --- --- --- --- --- ------- ------- ------- | from wily.commands.build import run_operator
-- -- --- --- --- --- --- --- ------- ------- ------- | from wily.state import State
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | def diff(config, files, metrics, changes_only=True, detail=True):
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | """
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | Show the differences in metrics for each of the files.
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 |
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | :param config: The wily configuration
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | :type config: :namedtuple:`wily.config.WilyConfig`
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 |
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | :param files: The files to compare.
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | :type files: ``list`` of ``str``
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 |
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | :param metrics: The metrics to measure.
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | :type metrics: ``list`` of ``str``
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 |
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | :param changes_only: Only include changes files in output.
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | :type changes_only: ``bool``
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 |
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | :param detail: Show details (function-level)
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | :type detail: ``bool``
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | """
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | config.targets = files
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | files = list(files)
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | state = State(config)
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 |
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | # Resolve target paths when the cli has specified --path
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | if config.path != DEFAULT_PATH:
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | targets = [str(Path(config.path) / Path(file)) for file in files]
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | else:
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | targets = files
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 |
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | last_revision = state.index[state.default_archiver].last_revision
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 |
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | # Convert the list of metrics to a list of metric instances
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | operators = {resolve_operator(metric.split(".")[0]) for metric in metrics}
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | metrics = [(metric.split(".")[0], resolve_metric(metric)) for metric in metrics]
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | results = []
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 |
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | # Build a set of operators
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | with multiprocessing.Pool(processes=len(operators)) as pool:
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | operator_exec_out = pool.starmap(
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | run_operator,
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | [(operator, None, config, targets) for operator in operators],
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | )
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | data = {}
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | for operator_name, result in operator_exec_out:
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | data[operator_name] = result
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 |
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | # Write a summary table
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | extra = []
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | for operator, metric in metrics:
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | if detail and resolve_operator(operator).level == OperatorLevel.Object:
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | for file in files:
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | try:
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | extra.extend(
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | [
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | f"{file}:{k}"
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | for k in data[operator][file]["detailed"].keys()
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | if k != metric.name
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | and isinstance(data[operator][file]["detailed"][k], dict)
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | ]
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | )
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | except KeyError:
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | logger.debug(f"File {file} not in cache")
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | logger.debug("Cache follows -- ")
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | logger.debug(data[operator])
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | files.extend(extra)
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | logger.debug(files)
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | for file in files:
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | metrics_data = []
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | has_changes = False
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | for operator, metric in metrics:
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | try:
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | current = last_revision.get(
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | config, state.default_archiver, operator, file, metric.name
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | )
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | except KeyError:
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | current = "-"
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | try:
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | new = get_metric(data, operator, file, metric.name)
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | except KeyError:
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | new = "-"
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | if new != current:
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | has_changes = True
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | if metric.type in (int, float) and new != "-" and current != "-":
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | if current > new:
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | metrics_data.append(
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | "{0:n} -> \u001b[{2}m{1:n}\u001b[0m".format(
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | current, new, BAD_COLORS[metric.measure]
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | )
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | )
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | elif current < new:
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | metrics_data.append(
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | "{0:n} -> \u001b[{2}m{1:n}\u001b[0m".format(
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | current, new, GOOD_COLORS[metric.measure]
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | )
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | )
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | else:
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | metrics_data.append("{0:n} -> {1:n}".format(current, new))
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | else:
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | if current == "-" and new == "-":
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | metrics_data.append("-")
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | else:
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | metrics_data.append("{0} -> {1}".format(current, new))
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | if has_changes or not changes_only:
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | results.append((file, *metrics_data))
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | else:
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | logger.debug(metrics_data)
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 |
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | descriptions = [metric.description for operator, metric in metrics]
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | headers = ("File", *descriptions)
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | if len(results) > 0:
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | print(
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | # But it still makes more sense to show the newest at the top, so reverse again
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | tabulate.tabulate(
-- 31 009 027 019 038 036 057 0294.69 1866.34 0006.33 | headers=headers, tabular_data=results, tablefmt=DEFAULT_GRID_STYLE
-- -- 009 027 019 038 036 057 0294.69 1866.34 0006.33 | )
-- -- --- --- --- --- --- --- ------- ------- ------- | )