Coverage for backend/django/core/auxiliary/services/result_summary/stats.py: 87%
65 statements
« prev ^ index » next coverage.py v7.10.7, created at 2026-07-22 05:22 +0000
« prev ^ index » next coverage.py v7.10.7, created at 2026-07-22 05:22 +0000
1from collections import Counter
2from math import isfinite
3from typing import NamedTuple
5from core.auxiliary.services.result_summary.aggregation import aggregate_values
6from core.auxiliary.services.result_summary.contracts import (
7 ResultMetricMatchKind,
8 ResultMetricRowTarget,
9 ResultMetricTargets,
10 ResultStats,
11)
14class FiniteResultValuePoint(NamedTuple):
15 row_index: int
16 value: float
19def finite_values(values) -> list[FiniteResultValuePoint]:
20 finite_result_values = []
21 for point in values:
22 if point.value is None: 22 ↛ 23line 22 didn't jump to line 23 because the condition on line 22 was never true
23 continue
24 try:
25 numeric_value = float(point.value)
26 except (TypeError, ValueError):
27 continue
28 if isfinite(numeric_value): 28 ↛ 21line 28 didn't jump to line 21 because the condition on line 28 was always true
29 finite_result_values.append(
30 FiniteResultValuePoint(
31 row_index=point.row_index,
32 value=numeric_value,
33 )
34 )
35 return finite_result_values
38def format_metric_value(value: float) -> str:
39 return f"{value:.4g}"
42def result_stats(
43 finite_result_values: list[FiniteResultValuePoint],
44 total_value_count: int,
45) -> ResultStats:
46 omitted_count = total_value_count - len(finite_result_values)
48 if not finite_result_values: 48 ↛ 49line 48 didn't jump to line 49 because the condition on line 48 was never true
49 return ResultStats(
50 count=0,
51 omitted_count=omitted_count,
52 mean=None,
53 median=None,
54 mode=None,
55 mode_label="Unavailable",
56 min=None,
57 max=None,
58 )
60 numeric_values = [point.value for point in finite_result_values]
61 median = float(aggregate_values(numeric_values, "percentile", percentile=50))
63 frequencies = Counter(numeric_values)
64 highest_frequency = max(frequencies.values())
65 modes = sorted(
66 value
67 for value, frequency in frequencies.items()
68 if frequency == highest_frequency
69 )
70 if highest_frequency == 1:
71 mode = None
72 mode_label = "No repeated value"
73 elif len(modes) == 1:
74 mode = modes[0]
75 mode_label = format_metric_value(mode)
76 else:
77 mode = None
78 mode_label = "Multiple repeated values"
80 return ResultStats(
81 count=len(finite_result_values),
82 omitted_count=omitted_count,
83 mean=float(aggregate_values(numeric_values, "mean")),
84 median=median,
85 mode=mode,
86 mode_label=mode_label,
87 min=float(aggregate_values(numeric_values, "min")),
88 max=float(aggregate_values(numeric_values, "max")),
89 )
92def metric_targets(
93 finite_result_values: list[FiniteResultValuePoint],
94 stats: ResultStats,
95) -> ResultMetricTargets:
96 return ResultMetricTargets(
97 first=_first_target(finite_result_values),
98 mean=_closest_target(finite_result_values, stats.mean),
99 median=_target_for_metric(finite_result_values, stats.median),
100 mode=_target_for_metric(finite_result_values, stats.mode),
101 min=_target_for_metric(finite_result_values, stats.min),
102 max=_target_for_metric(finite_result_values, stats.max),
103 )
106def _first_target(
107 finite_result_values: list[FiniteResultValuePoint],
108) -> ResultMetricRowTarget | None:
109 if not finite_result_values: 109 ↛ 110line 109 didn't jump to line 110 because the condition on line 109 was never true
110 return None
111 first_point = finite_result_values[0]
112 return ResultMetricRowTarget(
113 row_index=first_point.row_index,
114 value=first_point.value,
115 target_value=first_point.value,
116 match_count=1,
117 match_kind=ResultMetricMatchKind.first,
118 )
121def _target_for_metric(
122 finite_result_values: list[FiniteResultValuePoint],
123 target_value: float | None,
124) -> ResultMetricRowTarget | None:
125 if target_value is None:
126 return None
127 exact_target = _exact_target(finite_result_values, target_value)
128 return exact_target or _closest_target(finite_result_values, target_value)
131def _exact_target(
132 finite_result_values: list[FiniteResultValuePoint],
133 target_value: float,
134) -> ResultMetricRowTarget | None:
135 matching_points = [
136 point for point in finite_result_values if point.value == target_value
137 ]
138 if not matching_points:
139 return None
140 first_point = matching_points[0]
141 return ResultMetricRowTarget(
142 row_index=first_point.row_index,
143 value=first_point.value,
144 target_value=target_value,
145 match_count=len(matching_points),
146 match_kind=ResultMetricMatchKind.exact,
147 )
150def _closest_target(
151 finite_result_values: list[FiniteResultValuePoint],
152 target_value: float | None,
153) -> ResultMetricRowTarget | None:
154 if target_value is None or not finite_result_values: 154 ↛ 155line 154 didn't jump to line 155 because the condition on line 154 was never true
155 return None
157 closest_distance = min(
158 abs(point.value - target_value) for point in finite_result_values
159 )
160 closest_points = [
161 point
162 for point in finite_result_values
163 if abs(point.value - target_value) == closest_distance
164 ]
165 first_point = closest_points[0]
166 return ResultMetricRowTarget(
167 row_index=first_point.row_index,
168 value=first_point.value,
169 target_value=target_value,
170 match_count=len(closest_points),
171 match_kind=ResultMetricMatchKind.closest,
172 )