def diff(config, files, metrics, changes_only=True, detail=True):
config.targets = files<EOL>files = list(files)<EOL>state = State(config)<EOL>last_revision = state.index[state.default_archiver].revisions[<NUM_LIT:0>]<EOL>operators = {resolve_operator(metric.split("<STR_LIT:.>")[<NUM_LIT:0>]) for metric in metrics}<EOL>metrics = [(metric.split("<STR_LIT:.>")[<NUM_LIT:0>], resolve_metric(metric)) for metric in metrics]<EOL>data = {}<EOL>results = []<EOL>_operators = [operator.cls(config) for operator in operators]<EOL>cwd = os.getcwd()<EOL>os.chdir(config.path)<EOL>for operator in _operators:<EOL><INDENT>logger.debug(f"<STR_LIT>")<EOL>data[operator.name] = operator.run(None, config)<EOL><DEDENT>os.chdir(cwd)<EOL>extra = []<EOL>for operator, metric in metrics:<EOL><INDENT>if detail and resolve_operator(operator).level == OperatorLevel.Object:<EOL><INDENT>for file in files:<EOL><INDENT>try:<EOL><INDENT>extra.extend(<EOL>[<EOL>f"<STR_LIT>"<EOL>for k in data[operator][file].keys()<EOL>if k != metric.name<EOL>and isinstance(data[operator][file][k], dict)<EOL>]<EOL>)<EOL><DEDENT>except KeyError:<EOL><INDENT>logger.debug(f"<STR_LIT>")<EOL>logger.debug("<STR_LIT>")<EOL>logger.debug(data[operator])<EOL><DEDENT><DEDENT><DEDENT><DEDENT>files.extend(extra)<EOL>logger.debug(files)<EOL>for file in files:<EOL><INDENT>metrics_data = []<EOL>has_changes = False<EOL>for operator, metric in metrics:<EOL><INDENT>try:<EOL><INDENT>current = last_revision.get(<EOL>config, state.default_archiver, operator, file, metric.name<EOL>)<EOL><DEDENT>except KeyError as e:<EOL><INDENT>current = "<STR_LIT:->"<EOL><DEDENT>try:<EOL><INDENT>new = get_metric(data, operator, file, metric.name)<EOL><DEDENT>except KeyError as e:<EOL><INDENT>new = "<STR_LIT:->"<EOL><DEDENT>if new != current:<EOL><INDENT>has_changes = True<EOL><DEDENT>if metric.type in (int, float) and new != "<STR_LIT:->" and current != "<STR_LIT:->":<EOL><INDENT>if current > new:<EOL><INDENT>metrics_data.append(<EOL>"<STR_LIT>".format(<EOL>current, new, BAD_COLORS[metric.measure]<EOL>)<EOL>)<EOL><DEDENT>elif current < new:<EOL><INDENT>metrics_data.append(<EOL>"<STR_LIT>".format(<EOL>current, new, GOOD_COLORS[metric.measure]<EOL>)<EOL>)<EOL><DEDENT>else:<EOL><INDENT>metrics_data.append("<STR_LIT>".format(current, new))<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if current == "<STR_LIT:->" and new == "<STR_LIT:->":<EOL><INDENT>metrics_data.append("<STR_LIT:->")<EOL><DEDENT>else:<EOL><INDENT>metrics_data.append("<STR_LIT>".format(current, new))<EOL><DEDENT><DEDENT><DEDENT>if has_changes or not changes_only:<EOL><INDENT>results.append((file, *metrics_data))<EOL><DEDENT>else:<EOL><INDENT>logger.debug(metrics_data)<EOL><DEDENT><DEDENT>descriptions = [metric.description for operator, metric in metrics]<EOL>headers = ("<STR_LIT>", *descriptions)<EOL>if len(results) > <NUM_LIT:0>:<EOL><INDENT>print(<EOL>tabulate.tabulate(<EOL>headers=headers, tabular_data=results, tablefmt=DEFAULT_GRID_STYLE<EOL>)<EOL>)<EOL><DEDENT>
Show the differences in metrics for each of the files.

:param config: The wily configuration
:type  config: :namedtuple:`wily.config.WilyConfig`

:param files: The files to compare.
:type  files: ``list`` of ``str``

:param metrics: The metrics to measure.
:type  metrics: ``list`` of ``str``

:param changes_only: Only include changes files in output.
:type  changes_only: ``bool``

:param detail: Show details (function-level)
:type  detail: ``bool``