Coverage for src/polars_eval_metrics/evaluation_context.py: 95%
80 statements
« prev ^ index » next coverage.py v7.10.7, created at 2025-09-29 15:04 +0000
« prev ^ index » next coverage.py v7.10.7, created at 2025-09-29 15:04 +0000
1from __future__ import annotations
3from dataclasses import dataclass, field
4from types import MappingProxyType
5from typing import Mapping, Sequence
7from .metric_define import MetricDefine
10@dataclass(frozen=True)
11class EstimateCatalog:
12 """Read-only view over configured estimates with lookup helpers."""
14 entries: tuple[tuple[str, str], ...]
15 _key_to_label: Mapping[str, str] = field(init=False, repr=False)
16 _label_to_key: Mapping[str, str] = field(init=False, repr=False)
17 _label_order: Mapping[str, int] = field(init=False, repr=False)
19 def __post_init__(self) -> None:
20 key_to_label = dict(self.entries)
21 label_to_key = {label: key for key, label in self.entries}
22 label_order = {label: idx for idx, label in enumerate(label_to_key)}
23 object.__setattr__(self, "_key_to_label", MappingProxyType(key_to_label))
24 object.__setattr__(self, "_label_to_key", MappingProxyType(label_to_key))
25 object.__setattr__(self, "_label_order", MappingProxyType(label_order))
27 @classmethod
28 def build(cls, mapping: Mapping[str, str]) -> "EstimateCatalog":
29 return cls(tuple(mapping.items()))
31 @property
32 def key_to_label(self) -> Mapping[str, str]:
33 return self._key_to_label
35 @property
36 def label_to_key(self) -> Mapping[str, str]:
37 return self._label_to_key
39 @property
40 def label_order(self) -> Mapping[str, int]:
41 return self._label_order
43 @property
44 def keys(self) -> tuple[str, ...]:
45 return tuple(key for key, _ in self.entries)
47 @property
48 def labels(self) -> tuple[str, ...]:
49 return tuple(label for _, label in self.entries)
51 def label_for(self, key: str) -> str:
52 return self._key_to_label.get(key, key)
55@dataclass(frozen=True)
56class MetricCatalog:
57 """Read-only view over configured metrics with ordering helpers."""
59 metrics: tuple[MetricDefine, ...]
60 _labels: tuple[str, ...] = field(init=False, repr=False)
61 _names: tuple[str, ...] = field(init=False, repr=False)
62 _name_order: Mapping[str, int] = field(init=False, repr=False)
63 _label_order: Mapping[str, int] = field(init=False, repr=False)
64 _name_set: frozenset[str] = field(init=False, repr=False)
66 def __post_init__(self) -> None:
67 labels = tuple(metric.label or metric.name for metric in self.metrics)
68 names = tuple(metric.name for metric in self.metrics)
69 name_order = {name: idx for idx, name in enumerate(names)}
70 label_order = {label: idx for idx, label in enumerate(labels)}
71 object.__setattr__(self, "_labels", labels)
72 object.__setattr__(self, "_names", names)
73 object.__setattr__(self, "_name_order", MappingProxyType(name_order))
74 object.__setattr__(self, "_label_order", MappingProxyType(label_order))
75 object.__setattr__(self, "_name_set", frozenset(names))
77 @property
78 def entries(self) -> tuple[MetricDefine, ...]:
79 return self.metrics
81 @property
82 def labels(self) -> tuple[str, ...]:
83 return self._labels
85 @property
86 def names(self) -> tuple[str, ...]:
87 return self._names
89 @property
90 def name_order(self) -> Mapping[str, int]:
91 return self._name_order
93 @property
94 def label_order(self) -> Mapping[str, int]:
95 return self._label_order
97 def contains(self, name: str) -> bool:
98 return name in self._name_set
101@dataclass(frozen=True)
102class FormatterContext:
103 """Lightweight bundle of formatting-related configuration."""
105 group_by: Mapping[str, str]
106 subgroup_by: Mapping[str, str]
107 estimate_catalog: EstimateCatalog
108 metric_catalog: MetricCatalog
109 subgroup_categories: Sequence[str] = ()