github-actions[bot] wrote:
<!--LLVM CODE FORMAT COMMENT: {darker}-->
:warning: Python code formatter, darker found issues in your code. :warning:
<details>
<summary>
You can test this locally with the following command:
</summary>
``````````bash
darker --check --diff -r origin/main...HEAD
cross-project-tests/debuginfo-tests/dexter/dex/evaluation/ExpectMatch.py
cross-project-tests/debuginfo-tests/dexter/dex/evaluation/Metrics.py
cross-project-tests/debuginfo-tests/dexter/dex/evaluation/RunMatch.py
cross-project-tests/debuginfo-tests/dexter/dex/evaluation/StateMatch.py
cross-project-tests/debuginfo-tests/dexter/dex/evaluation/__init__.py
cross-project-tests/debuginfo-tests/dexter/dex/debugger/DebuggerControllers/ScriptDebuggerController.py
cross-project-tests/debuginfo-tests/dexter/dex/test_script/__init__.py
cross-project-tests/debuginfo-tests/dexter/dex/tools/test/Tool.py
``````````
:warning:
The reproduction instructions above might return results for more than one PR
in a stack if you are using a stacked PR workflow. You can limit the results by
changing `origin/main` to the base branch/commit you want to compare against.
:warning:
</details>
<details>
<summary>
View the diff from darker here.
</summary>
``````````diff
--- evaluation/ExpectMatch.py 2026-05-20 15:01:31.000000 +0000
+++ evaluation/ExpectMatch.py 2026-05-20 15:11:09.681921 +0000
@@ -10,20 +10,23 @@
from dex.dextIR import ValueIR
from dex.test_script.Nodes import Expect, Value
-
class DebuggerExpectMatch:
"""Class that represents the match between a particular expected value for
an Expect node and the actual debugger
output corresponding to the watched value for that node."""
+
def __init__(self, expect: Expect, expected, actual: ValueIR):
self.expect = expect
self.expected = expected
self.actual = actual
self.actual_result = self.expect.get_variable_result(self.actual)
- self.match_result = self.expected is not None and str(self.expected)
== self.actual_result
+ self.match_result = (
+ self.expected is not None and str(self.expected) ==
self.actual_result
+ )
+
def get_expect_match(expect: Expect, expected_values, actual: ValueIR):
"""Given one or more expected values for an Expect node and an actual
ValueIR, returns a match for the first
matching expected values, or for None if there are no matching expected
values."""
if not isinstance(expected_values, list):
@@ -31,6 +34,5 @@
for expected_value in expected_values:
expect_match = DebuggerExpectMatch(expect, expected_value, actual)
if expect_match.match_result:
return expect_match
return DebuggerExpectMatch(expect, None, actual)
-
--- evaluation/Metrics.py 2026-05-20 15:01:31.000000 +0000
+++ evaluation/Metrics.py 2026-05-20 15:11:09.716314 +0000
@@ -12,11 +12,11 @@
from dex.evaluation.ExpectMatch import DebuggerExpectMatch
from dex.test_script.Nodes import Expect, Value
class Metric:
- def __init__(self, improves_asc = True):
+ def __init__(self, improves_asc=True):
self.improves_asc = improves_asc
def as_scalar(self) -> float:
raise NotImplementedError()
@@ -34,12 +34,13 @@
elif a < b:
return -1
else:
return 0
+
class ScalarMetric(Metric):
- def __init__(self, value: Union[int, float], improves_asc = True):
+ def __init__(self, value: Union[int, float], improves_asc=True):
self.value = value
super().__init__(improves_asc)
def as_scalar(self) -> float:
return float(self.value)
@@ -48,12 +49,13 @@
return ScalarMetric(self.value + other.value, self.improves_asc)
def __repr__(self):
return f"{self.value}"
+
class FractionMetric(Metric):
- def __init__(self, numerator: int, denominator: int, improves_asc = True):
+ def __init__(self, numerator: int, denominator: int, improves_asc=True):
self.num = numerator
self.dom = denominator
super().__init__(improves_asc)
def as_scalar(self) -> float:
@@ -61,23 +63,29 @@
def as_pct(self) -> float:
return self.as_scalar() * 100
def aggregate(self, other):
- return FractionMetric(self.num + other.num, self.dom + other.dom,
self.improves_asc)
+ return FractionMetric(
+ self.num + other.num, self.dom + other.dom, self.improves_asc
+ )
def __repr__(self):
return f"{self.as_pct():.1f}% ({self.num}/{self.dom})"
+
def serialize_metric_to_json(metric):
if isinstance(metric, ScalarMetric):
return metric.value
elif isinstance(metric, FractionMetric):
return metric.as_pct()
raise Exception("Invalid metric type!")
-def get_variable_metrics(expect: Expect, expected_values: Any, matches:
List[DebuggerExpectMatch]) -> Dict[str, Metric]:
+
+def get_variable_metrics(
+ expect: Expect, expected_values: Any, matches: List[DebuggerExpectMatch]
+) -> Dict[str, Metric]:
"""Given an Expect node with its expected values and a list of all matches
for that Expect in a debugger session,
returns the computed metrics for that Expect node."""
assert isinstance(expect, Value), "Non-Value expects currently unsupported"
if not isinstance(expected_values, list):
expected_values = [expected_values]
@@ -101,11 +109,13 @@
# other variables.
"total_watched_steps": ScalarMetric(num_total_steps),
# The number of steps where the expected value sequence was observed.
"correct_steps": ScalarMetric(num_correct_steps),
# The number of steps which did not match the expected value sequence.
- "incorrect_steps": ScalarMetric(num_total_steps - num_correct_steps,
improves_asc=False),
+ "incorrect_steps": ScalarMetric(
+ num_total_steps - num_correct_steps, improves_asc=False
+ ),
# The number of steps where the watched variable/expression was not
available in the debugger.
"missing_var_steps": ScalarMetric(num_missing_var_steps,
improves_asc=False),
# The number of steps where the watched variable/expression had a
value not in the set of expected values.
"unexpected_value_steps": ScalarMetric(
num_unexpected_value_steps, improves_asc=False
@@ -113,8 +123,10 @@
# The % of steps where the expected value sequence was observed.
"correct_step_coverage": FractionMetric(num_correct_steps,
num_total_steps),
# The number of expected values that were observed at least once.
"seen_values": ScalarMetric(num_seen_values),
# The number of expected values that were not observed.
- "missing_values": ScalarMetric(len(expected_values) - num_seen_values,
improves_asc=False),
+ "missing_values": ScalarMetric(
+ len(expected_values) - num_seen_values, improves_asc=False
+ ),
}
return metrics
--- evaluation/RunMatch.py 2026-05-20 15:01:31.000000 +0000
+++ evaluation/RunMatch.py 2026-05-20 15:11:09.762202 +0000
@@ -13,35 +13,52 @@
from collections import defaultdict
from typing import Any, Dict, List, Tuple
from dex.dextIR import DextIR, StepIR
from dex.evaluation.ExpectMatch import DebuggerExpectMatch, get_expect_match
-from dex.evaluation.Metrics import Metric, get_variable_metrics,
serialize_metric_to_json
+from dex.evaluation.Metrics import (
+ Metric,
+ get_variable_metrics,
+ serialize_metric_to_json,
+)
from dex.evaluation.StateMatch import get_active_where_expects
from dex.test_script import DexterScript, Scope
from dex.test_script.Nodes import Expect, Value
+
class DebuggerStepMatch:
"""Class used to record the match between a DexterScript and a StepIR,
including the state match, determining which
script nodes are "active", and the expect matches, which compare the
debugger's output to the DexterScript's
expected output."""
+
def __init__(self, step: StepIR, script: DexterScript):
self.step = step
self.script = script
self.state_match = get_active_where_expects(script, step)
- expects_to_match = {expect for frame_idx, expects in
self.state_match.values() for expect in expects}
+ expects_to_match = {
+ expect
+ for frame_idx, expects in self.state_match.values()
+ for expect in expects
+ }
self.expect_matches: Dict[Expect, DebuggerExpectMatch] = {}
+
def add_expected_values(expect: Expect, expected_value: Any, scope:
Scope):
assert isinstance(expect, Value), "Non-Value expects currently
unsupported"
if expect in expects_to_match:
- self.expect_matches[expect] = get_expect_match(expect,
expected_value, step.watches[expect.get_watched_expr()])
+ self.expect_matches[expect] = get_expect_match(
+ expect, expected_value,
step.watches[expect.get_watched_expr()]
+ )
+
script.visit_script(visit_expect=add_expected_values)
+
class DebuggerRunMatch(object):
"""Class used to record the complete match of a debugger session and a
DexterScript. Compares debugger steps to the
script one-at-a-time, rather than comparing individual variables
longtitudinally, as there will exist some shared
- state across evaluation that is updated step-by-step and can be shared
across variables."""
+ state across evaluation that is updated step-by-step and can be shared
across variables.
+ """
+
def __init__(self, context, dext_ir: DextIR):
self.context = context
self.dext_ir = dext_ir
self.metrics: Dict[str, Metric] = {}
self.step_matches: List[DebuggerStepMatch] = []
@@ -52,35 +69,42 @@
script = self.dext_ir.script
assert script is not None, "Trying to evaluate DextIR without attached
script?"
# Gather the expected values for each Expect.
expected_values = {}
+
def add_expected_values(expect: Expect, expected_value: Any, scope:
Scope):
assert isinstance(expect, Value), "Non-Value expects currently
unsupported"
expected_values[expect] = expected_value
self.per_expect_results[expect] = []
+
script.visit_script(visit_expect=add_expected_values)
# Then produce all of our step matches.
for step in self.dext_ir.steps:
self.step_matches.append(DebuggerStepMatch(step, script))
# Then, for each expect, produce the list of results for just that
variable.
for step_match in self.step_matches:
for expect, expect_match in step_match.expect_matches.items():
-
self.per_expect_results[expect].append((step_match.step.step_index,
expect_match))
+ self.per_expect_results[expect].append(
+ (step_match.step.step_index, expect_match)
+ )
# Finally, compare the match results against the expected values to
produce the metrics.
for expect, expect_results in self.per_expect_results.items():
expect_matches = [match for step, match in expect_results]
- expect_metrics = get_variable_metrics(expect,
expected_values[expect], expect_matches)
+ expect_metrics = get_variable_metrics(
+ expect, expected_values[expect], expect_matches
+ )
for metric_name, metric in expect_metrics.items():
if metric_name not in self.metrics:
self.metrics[metric_name] = metric
else:
- self.metrics[metric_name] =
self.metrics[metric_name].aggregate(metric)
-
+ self.metrics[metric_name] =
self.metrics[metric_name].aggregate(
+ metric
+ )
def dump_step_results(self) -> str:
result = ""
for step_match in self.step_matches:
result += f"Step {step_match.step.step_index}:\n"
@@ -89,19 +113,33 @@
for where, (frame_idx, expects) in step_match.state_match.items():
frame_active_wheres[frame_idx].append(str(where))
if not frame_active_wheres:
result += f" No active !where nodes.\n"
continue
- frame_active_wheres_list = sorted([(frame_idx, wheres) for
frame_idx, wheres in frame_active_wheres.items()], key=lambda entry: entry[0])
+ frame_active_wheres_list = sorted(
+ [
+ (frame_idx, wheres)
+ for frame_idx, wheres in frame_active_wheres.items()
+ ],
+ key=lambda entry: entry[0],
+ )
result += f" Active !where nodes:\n"
for frame_idx, wheres in frame_active_wheres_list:
result += f" Frame {frame_idx}: [{', '.join(wheres)}]\n"
if not step_match.expect_matches:
continue
result += f" Active !expect nodes:\n"
- matching_expects = [(expect, match) for expect, match in
step_match.expect_matches.items() if match.match_result]
- non_matching_expects = [(expect, match) for expect, match in
step_match.expect_matches.items() if not match.match_result]
+ matching_expects = [
+ (expect, match)
+ for expect, match in step_match.expect_matches.items()
+ if match.match_result
+ ]
+ non_matching_expects = [
+ (expect, match)
+ for expect, match in step_match.expect_matches.items()
+ if not match.match_result
+ ]
if matching_expects:
result += f" Matching nodes: [{',
'.join(f'{expect}={match.actual_result}' for expect, match in
matching_expects)}]\n"
if non_matching_expects:
result += f" Non-matching nodes: [{',
'.join(f'{expect}={match.actual_result}' for expect, match in
non_matching_expects)}]\n"
return result
@@ -115,6 +153,9 @@
return "\n".join(lines) + "\n"
def get_metric_json_output(self):
if not self.metrics:
return "No expects found."
- return {metric_type: serialize_metric_to_json(metric) for metric_type,
metric in self.metrics.items()}
+ return {
+ metric_type: serialize_metric_to_json(metric)
+ for metric_type, metric in self.metrics.items()
+ }
--- evaluation/StateMatch.py 2026-05-20 15:01:31.000000 +0000
+++ evaluation/StateMatch.py 2026-05-20 15:11:09.791508 +0000
@@ -47,10 +47,11 @@
raise NotImplementedError(
"!where hit counts and conditions currently unsupported."
)
return True
+
def get_active_where_expects(
script: DexterScript, step_info: StepIR
) -> Dict[Where, Tuple[int, List[Value]]]:
"""Match the script against the step_info, producing a dict that maps each
!where that matches a stack frame to the
index of the (outermost) stack frame that it matches, and if the frame
that it matches is the current stack frame
--- tools/test/Tool.py 2026-05-20 15:01:31.000000 +0000
+++ tools/test/Tool.py 2026-05-20 15:11:09.913627 +0000
@@ -32,11 +32,18 @@
from dex.utils.PrettyOutputBase import Stream
from dex.utils.ReturnCode import ReturnCode
class TestCase(object):
- def __init__(self, context, name, heuristic: Optional[Heuristic]=None,
error=None, run_match: Optional[DebuggerRunMatch]=None):
+ def __init__(
+ self,
+ context,
+ name,
+ heuristic: Optional[Heuristic] = None,
+ error=None,
+ run_match: Optional[DebuggerRunMatch] = None,
+ ):
self.context = context
self.name = name
self.heuristic = heuristic
self.run_match = run_match
self.error = error
@@ -308,11 +315,13 @@
self._record_metrics(test_name, run_match)
self._record_successful_test_match(test_name, steps, run_match)
else:
heuristic_score = Heuristic(self.context, steps)
self._record_heuristic(test_name, heuristic_score)
- self._record_successful_test_heuristic(test_name, steps,
heuristic_score)
+ self._record_successful_test_heuristic(
+ test_name, steps, heuristic_score
+ )
except (BuildScriptException, DebuggerException, HeuristicException)
as e:
self._record_failed_test(test_name, e)
def _handle_results(self) -> ReturnCode:
return_code = ReturnCode.OK
``````````
</details>
https://github.com/llvm/llvm-project/pull/198803
_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits