Implementation:Evidentlyai Evidently Pydantic Utils
| Knowledge Sources | |
|---|---|
| Domains | Serialization, Framework Infrastructure, Type System |
| Last Updated | 2026-02-14 12:00 GMT |
Overview
Provides foundational pydantic utility classes for Evidently's type system, including polymorphic model serialization/deserialization, frozen immutable models, fingerprint computation, field path navigation, and configuration management.
Description
The pydantic_utils module is a core infrastructure module that powers Evidently's serialization, type aliasing, and model identity system. All metric types, descriptors, tests, and configuration objects inherit from the classes defined here.
Key Classes:
- FrozenBaseModel -- An immutable pydantic BaseModel with a custom metaclass (FrozenBaseMeta) that sets
frozen = True. Provides:- Immutable fields after initialization (raises AttributeError on reassignment).
- Custom
__hash__for use as dict keys and in sets. - Support for private attributes during initialization via
__init_values__.
- PolymorphicModel -- Enables polymorphic serialization/deserialization of model hierarchies. Features:
- Type aliasing: Each subclass gets a
typefield (Literal type) that identifies it during deserialization. - Auto-registration: Subclasses are automatically registered via
__init_subclass__. - Alias system:
register_type_alias(),register_loaded_alias(), and@autoregisterfor managing type lookups. - Dynamic import:
load_alias()can import subclasses by classpath with security prefix checks viaALLOWED_TYPE_PREFIXES. - Config options:
type_alias,alias_required,transitive_aliases,is_base_type.
- Type aliasing: Each subclass gets a
- EvidentlyBaseModel -- Combines FrozenBaseModel and PolymorphicModel. The primary base class for all Evidently configuration objects. Provides:
- Fingerprinting:
get_fingerprint()computes an MD5-based fingerprint from class path and field values.get_fingerprint_parts()returns the tuple of (field_name, field_value_fingerprint) pairs. - Serialization:
load(path, fmt)anddump(path, fmt)support both JSON and YAML formats. - Update:
update(**kwargs)creates a new instance with modified fields.
- Fingerprinting:
- AutoAliasMixin -- Mixin that auto-generates type aliases in the format
evidently:{alias_type}:{ClassName}. Used by MetricResult, MetricTest, BoundTest, and Metric classes.
- FieldPath -- A path navigation utility for traversing nested pydantic model structures. Supports:
- Attribute-style access:
path.field.subfield. - Mapping (dict) traversal with keys.
list_fields(),list_nested_fields(),list_nested_fields_with_tags()for introspecting model hierarchies.- Tag-based field filtering using FieldTags enum (Parameter, Current, Reference, Render, TypeField, Extra).
- Attribute-style access:
- FieldInfo -- Frozen model storing field path, tags, and classpath information for serialized field metadata.
Utility Functions:
- get_value_fingerprint(value) -- Recursively computes a hashable fingerprint part for any value (primitives, models, dicts, lists, sets, enums, callables).
- all_subclasses(cls) -- Recursively collects all subclasses of a type.
- get_base_class(cls) -- Finds the nearest base class marked with
is_base_type = Truein the MRO. - get_classpath(cls) -- Returns the full module path of a class.
- pydantic_type_validator(type_) -- Decorator for registering custom pydantic validators for specific types.
Mixins:
- EnumValueMixin -- Overrides
dict()to serialize enum fields as their raw values. - ExcludeNoneMixin -- Overrides
dict()to always exclude None values. - WithTestAndMetricDependencies -- Iterates over fields to yield metric/test dependencies.
Type Aliases:
- Fingerprint --
strtype alias for MD5 fingerprint strings. - FingerprintPart -- Recursive union type for fingerprint components.
Usage
Use this module when:
- Creating new Evidently model classes that need serialization, polymorphism, or fingerprinting.
- Building custom metrics, tests, or descriptors that extend the Evidently type system.
- Navigating model field hierarchies programmatically with FieldPath.
- Working with the type alias/registration system for plugin or extension development.
Code Reference
Source Location
- Repository: Evidentlyai_Evidently
- File:
src/evidently/pydantic_utils.py
Signature
class FrozenBaseModel(BaseModel, metaclass=FrozenBaseMeta):
def __init__(self, **data: Any): ...
def __hash__(self): ...
class PolymorphicModel(BaseModel):
type: str = Field("")
@classmethod
def __get_type__(cls) -> str: ...
@classmethod
def validate(cls, value: Any) -> TPM: ...
@classmethod
def load_alias(cls, typename): ...
class EvidentlyBaseModel(FrozenBaseModel, PolymorphicModel):
def get_fingerprint(self) -> Fingerprint: ...
def get_fingerprint_parts(self) -> Tuple[FingerprintPart, ...]: ...
def update(self, **kwargs) -> EBM: ...
@classmethod
def load(cls, path: str, fmt=None) -> EBM: ...
def dump(self, path: str, fmt=None): ...
class AutoAliasMixin:
__alias_type__: ClassVar[str]
@classmethod
def __get_type__(cls) -> str: ...
class FieldPath:
def __init__(self, path: List[Any], cls_or_instance, is_mapping=False): ...
def child(self, item: str) -> "FieldPath": ...
def list_fields(self) -> List[str]: ...
def list_nested_fields(self, exclude=None) -> List[str]: ...
def list_nested_fields_with_tags(self) -> List[Tuple[str, Set[IncludeTags]]]: ...
def get_value_fingerprint(value: Any) -> FingerprintPart: ...
def all_subclasses(cls: Type[T]) -> Set[Type[T]]: ...
def get_base_class(cls, ensure_parent=False) -> Type[PolymorphicModel]: ...
def register_type_alias(base_class, classpath: str, alias: str): ...
Import
from evidently.pydantic_utils import (
EvidentlyBaseModel,
FrozenBaseModel,
PolymorphicModel,
AutoAliasMixin,
Fingerprint,
FingerprintPart,
FieldPath,
FieldInfo,
FieldTags,
EnumValueMixin,
ExcludeNoneMixin,
get_value_fingerprint,
all_subclasses,
get_base_class,
get_classpath,
register_type_alias,
autoregister,
pydantic_type_validator,
)
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| **data | Dict[str, Any] | Yes | Keyword arguments for model field values (FrozenBaseModel/EvidentlyBaseModel constructors) |
| path | str | Yes (load/dump) | File path for loading or saving model configuration (JSON or YAML) |
| fmt | Literal["json", "yaml", None] | No | Format override; if None, inferred from file extension |
| value | Any | Yes (get_value_fingerprint) | Value to compute fingerprint for |
Outputs
| Name | Type | Description |
|---|---|---|
| Fingerprint | str | MD5 hex digest string identifying a model instance |
| FingerprintPart | Union[None, int, str, float, bool, bytes, Tuple] | Hashable component of a fingerprint |
| FieldPath | FieldPath | Path navigator object for model field traversal |
| FieldInfo | FieldInfo | Frozen model with path, tags, and classpath for a field |
Usage Examples
Creating a Custom EvidentlyBaseModel
from evidently.pydantic_utils import EvidentlyBaseModel
class MyConfig(EvidentlyBaseModel):
class Config:
type_alias = "evidently:custom:MyConfig"
threshold: float = 0.5
column: str = "target"
config = MyConfig(threshold=0.8, column="prediction")
fingerprint = config.get_fingerprint()
print(f"Fingerprint: {fingerprint}")
Loading and Saving Configurations
# Save to YAML
config.dump("my_config.yaml")
# Load from YAML
loaded = MyConfig.load("my_config.yaml")
# Save to JSON
config.dump("my_config.json")
from evidently.pydantic_utils import FieldPath
# Navigate from a model class
path = FieldPath([], MyConfig)
fields = path.list_fields() # ["threshold", "column", "type"]
# Navigate from an instance
path = FieldPath([], config)
nested = path.list_nested_fields()
Using Polymorphic Deserialization
from evidently._pydantic_compat import parse_obj_as
from evidently.pydantic_utils import EvidentlyBaseModel
# Deserialize with polymorphic type resolution
data = {"type": "evidently:custom:MyConfig", "threshold": 0.9, "column": "score"}
obj = parse_obj_as(EvidentlyBaseModel, data)
# obj is an instance of MyConfig
Related Pages
- Environment:Evidentlyai_Evidently_Python_Core_Environment
- Implementation:Evidentlyai_Evidently_Metric_Types -- Uses EvidentlyBaseModel, FrozenBaseModel, PolymorphicModel, AutoAliasMixin, and Fingerprint as the foundation for all metric types
- Implementation:Evidentlyai_Evidently_LLM_Templates -- Uses EnumValueMixin from this module for LLM prompt template serialization
- Implementation:Evidentlyai_Evidently_Generated_Descriptors -- All descriptors ultimately inherit from EvidentlyBaseModel