Coverage for backend/django/core/auxiliary/services/result_summary/histograms.py: 86%
41 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 core.auxiliary.services.result_summary.contracts import (
2 HistogramBin,
3 HistogramBinSelection,
4 ResultHistogramOptions,
5)
6from core.auxiliary.services.result_summary.stats import (
7 FiniteResultValuePoint,
8 format_metric_value,
9)
10from pydantic import BaseModel, ConfigDict, Field
13class CachedHistogramVariants(BaseModel):
14 model_config = ConfigDict(extra="forbid", populate_by_name=True)
16 auto: list[HistogramBin]
17 ten: list[HistogramBin] = Field(alias="10")
18 twenty: list[HistogramBin] = Field(alias="20")
19 thirty: list[HistogramBin] = Field(alias="30")
20 fifty: list[HistogramBin] = Field(alias="50")
23def histogram_bins(
24 finite_values: list[FiniteResultValuePoint],
25 options: ResultHistogramOptions,
26) -> list[HistogramBin]:
27 if not finite_values: 27 ↛ 28line 27 didn't jump to line 28 because the condition on line 27 was never true
28 return []
30 numeric_values = [point.value for point in finite_values]
31 min_value = min(numeric_values)
32 max_value = max(numeric_values)
33 if min_value == max_value:
34 return [
35 HistogramBin(
36 label=format_metric_value(min_value),
37 start=min_value,
38 end=max_value,
39 count=len(numeric_values),
40 )
41 ]
43 bin_count = options.bin_count_for(len(numeric_values))
44 bin_width = (max_value - min_value) / bin_count
45 bins = []
46 for index in range(bin_count):
47 start = min_value + index * bin_width
48 end = max_value if index == bin_count - 1 else start + bin_width
49 bins.append(
50 HistogramBin(
51 label=f"{format_metric_value(start)}-{format_metric_value(end)}",
52 start=start,
53 end=end,
54 count=0,
55 )
56 )
58 for value in numeric_values:
59 # Include the exact max value in the final bin; floor division would put
60 # it one bin past the array when value == max_value.
61 index = (
62 bin_count - 1
63 if value == max_value
64 else int((value - min_value) // bin_width)
65 )
66 bins[index].count += 1
68 return bins
71def cached_histogram_variants(
72 finite_values: list[FiniteResultValuePoint],
73) -> CachedHistogramVariants:
74 return CachedHistogramVariants(
75 auto=histogram_bins(
76 finite_values,
77 ResultHistogramOptions(histogram_bins=HistogramBinSelection.auto),
78 ),
79 ten=histogram_bins(
80 finite_values,
81 ResultHistogramOptions(histogram_bins=HistogramBinSelection.ten),
82 ),
83 twenty=histogram_bins(
84 finite_values,
85 ResultHistogramOptions(histogram_bins=HistogramBinSelection.twenty),
86 ),
87 thirty=histogram_bins(
88 finite_values,
89 ResultHistogramOptions(histogram_bins=HistogramBinSelection.thirty),
90 ),
91 fifty=histogram_bins(
92 finite_values,
93 ResultHistogramOptions(histogram_bins=HistogramBinSelection.fifty),
94 ),
95 )
98def cached_histogram_bins_for(
99 variants: CachedHistogramVariants,
100 options: ResultHistogramOptions,
101) -> list[HistogramBin]:
102 if options.histogram_bins == HistogramBinSelection.ten:
103 return variants.ten
104 if options.histogram_bins == HistogramBinSelection.twenty: 104 ↛ 105line 104 didn't jump to line 105 because the condition on line 104 was never true
105 return variants.twenty
106 if options.histogram_bins == HistogramBinSelection.thirty: 106 ↛ 107line 106 didn't jump to line 107 because the condition on line 106 was never true
107 return variants.thirty
108 if options.histogram_bins == HistogramBinSelection.fifty: 108 ↛ 109line 108 didn't jump to line 109 because the condition on line 108 was never true
109 return variants.fifty
110 return variants.auto