Implementation:Evidentlyai Evidently Legacy Base Metric
| Knowledge Sources | |
|---|---|
| Domains | ML Monitoring, Metrics Framework |
| Last Updated | 2026-02-14 12:00 GMT |
Overview
Defines the foundational base classes for the legacy metric system, providing the abstract Metric class, result containers (MetricResult, ErrorResult), column-aware data accessors (InputData, ColumnName), and supporting metaclasses used throughout the Evidently legacy pipeline.
Description
This module is the backbone of the legacy Evidently metric system. It establishes the core abstractions that every concrete metric implementation must follow:
- MetricResult -- a polymorphic Pydantic model that every metric calculation must return. It inherits from both PolymorphicModel and BaseResult, and includes a custom metaclass (WithFieldsPathMetaclass) that exposes a fields class property for navigating result field paths at the type level.
- ErrorResult -- a lightweight wrapper that captures exceptions raised during metric calculation. When a metric errors out during a pipeline run, the result is stored as an ErrorResult so the pipeline can continue.
- Metric[TResult] -- the main generic abstract base class that all concrete metrics extend. It is parameterized by a MetricResult subclass. Key responsibilities include:
- calculate(data: InputData) -> TResult -- the abstract method subclasses implement to compute the metric.
- get_result() -- retrieves the computed result from the suite context; raises if the metric has not yet been calculated or if the calculation produced an error.
- get_parameters() -- returns a hashable tuple of metric parameters for deduplication.
- required_features() -- discovers any GeneratedFeatures referenced in the metric's fields.
- get_options() -- merges global, display, and metric-level options.
- InputData -- a concrete specialization of GenericInputData[pd.DataFrame] that provides helper methods to extract columns from current and reference DataFrames by ColumnName, supporting both main and additional (generated feature) datasets.
- ColumnName -- a Pydantic model representing a column reference that carries a raw name, a display name, a dataset indicator (DatasetType.MAIN or DatasetType.ADDITIONAL), and an optional GeneratedFeatures class for derived columns.
- ColumnMetric and ColumnMetricResult -- specializations of Metric and MetricResult scoped to a single named column.
- BasePreset -- a minimal base class for metric presets (groups of metrics).
- UsesRawDataMixin -- a mixin that includes the raw data render option in the metric fingerprint.
Usage
Use this module when implementing a new legacy metric. Subclass Metric[YourResult] where YourResult extends MetricResult, then implement the calculate method. Use InputData within calculate to access current and reference datasets. For column-specific metrics, subclass ColumnMetric instead.
Code Reference
Source Location
- Repository: Evidentlyai_Evidently
- File:
src/evidently/legacy/base_metric.py
Signature
class MetricResult(PolymorphicModel, BaseResult, metaclass=WithFieldsPathMetaclass):
...
class ErrorResult(BaseResult):
_exception: Optional[BaseException]
def __init__(self, exception: Optional[BaseException]): ...
class DatasetType(Enum):
MAIN = "main"
ADDITIONAL = "additional"
class ColumnName(EnumValueMixin, EvidentlyBaseModel):
name: str
display_name: DisplayName
dataset: DatasetType
@staticmethod
def main_dataset(name: str) -> "ColumnName": ...
@classmethod
def from_any(cls, column_name: Union[str, "ColumnName"]) -> "ColumnName": ...
class GenericInputData(Generic[TEngineDataType]):
reference_data: Optional[TEngineDataType]
current_data: TEngineDataType
column_mapping: ColumnMapping
data_definition: DataDefinition
additional_data: Dict[str, Any]
class InputData(GenericInputData[pd.DataFrame]):
def get_current_column(self, column: Union[str, ColumnName]) -> pd.Series: ...
def get_reference_column(self, column: Union[str, ColumnName]) -> Optional[pd.Series]: ...
def get_data(self, column: Union[str, ColumnName]) -> Tuple[ColumnType, pd.Series, Optional[pd.Series]]: ...
def has_column(self, column_name: Union[str, ColumnName]) -> bool: ...
class Metric(WithTestAndMetricDependencies, Generic[TResult], metaclass=WithResultFieldPathMetaclass):
options: Optional[Options]
@abc.abstractmethod
def calculate(self, data: InputData) -> TResult: ...
def get_result(self) -> TResult: ...
def get_parameters(self) -> Optional[tuple]: ...
def required_features(self, data_definition: DataDefinition) -> List["GeneratedFeatures"]: ...
class ColumnMetricResult(MetricResult):
column_name: str
column_type: str
class ColumnMetric(Metric[ColumnTResult], Generic[ColumnTResult], abc.ABC):
column_name: ColumnName
Import
from evidently.legacy.base_metric import Metric, MetricResult, InputData, ColumnName
from evidently.legacy.base_metric import ColumnMetric, ColumnMetricResult
from evidently.legacy.base_metric import ErrorResult, DatasetType, GenericInputData
from evidently.legacy.base_metric import BasePreset, UsesRawDataMixin
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| data | InputData |
Yes | Container holding current DataFrame, optional reference DataFrame, column mapping, data definition, and additional data. Passed to Metric.calculate().
|
| column_mapping | ColumnMapping |
Yes | Mapping describing which DataFrame columns serve as target, prediction, features, etc. |
| data_definition | DataDefinition |
Yes | Schema-level description of all columns and their types. |
| options | AnyOptions |
No | Per-metric or global configuration options that override defaults. |
| column_name | Union[str, ColumnName] |
Yes (for ColumnMetric) | The column to compute the metric on. |
Outputs
| Name | Type | Description |
|---|---|---|
| result | TResult (MetricResult subclass) |
The computed metric result, retrieved via Metric.get_result().
|
| ErrorResult | ErrorResult |
Wraps an exception if the metric calculation fails. |
Usage Examples
# Defining a custom metric
from evidently.legacy.base_metric import Metric, MetricResult, InputData
class MyCustomResult(MetricResult):
class Config:
type_alias = "evidently:metric_result:MyCustomResult"
score: float
class MyCustomMetric(Metric[MyCustomResult]):
def calculate(self, data: InputData) -> MyCustomResult:
current = data.current_data
ref = data.reference_data
score = current.shape[0] / ref.shape[0] if ref is not None else 1.0
return MyCustomResult(score=score)
# Using ColumnName to reference a column
from evidently.legacy.base_metric import ColumnName, DatasetType
col = ColumnName.main_dataset("age")
col_from_string = ColumnName.from_any("age")
# Accessing data inside calculate()
class ExampleMetric(Metric[MyCustomResult]):
def calculate(self, data: InputData) -> MyCustomResult:
col_type, current_series, ref_series = data.get_data("feature_1")
return MyCustomResult(score=current_series.mean())
Related Pages
- Environment:Evidentlyai_Evidently_Python_Core_Environment
- Evidentlyai_Evidently_Legacy_Metric_Results -- Data models returned by metrics
- Evidentlyai_Evidently_Legacy_Report -- Report orchestrator that runs metrics
- Evidentlyai_Evidently_Legacy_HTML_Widgets -- Rendering layer for metric results