Domain Models and Pydantic Integration
Relevant source files
The following files were used as context for generating this wiki page:
- src/flext_core/models.py
- src/flext_core/_models/__init__.py
- src/flext_core/_models/_base_parts/flextmodelsbase_part_02.py
- src/flext_core/_models/_project_metadata_parts/flextmodelsprojectmetadata_part_02.py
- src/flext_core/_models/_project_metadata_parts/flextmodelsprojectmetadata_part_03.py
- src/flext_core/_models/_project_metadata_parts/flextmodelsprojectmetadata_part_04.py
- tests/unit/_models/test_base.py
- tests/_models/_mixins/domain.py
The flext-core project utilizes Pydantic v2 as its foundational validation and serialization engine, providing a robust set of base classes for Domain-Driven Design (DDD). These models are designed to integrate seamlessly with the project's dispatcher-driven CQRS layer, ensuring that entities, value objects, and domain events maintain strict invariants through strong typing and runtime validation.
The architecture follows a facade pattern where FlextModels (aliased as m) serves as a single point of access for all domain building blocks. This includes base models for immutable values, identifiable entities, and complex project metadata structures that adhere to strict immutability rules (frozen=True) to prevent state drift after initialization.
Sources: src/flext_core/models.py:11-23, src/flext_core/models.py:53-73, src/flext_core/_models/_project_metadata_parts/flextmodelsprojectmetadata_part_02.py:1-18
Model Hierarchy and Base Presets
The framework provides several standardized model presets to enforce specific behavioral contracts across the ecosystem. These presets range from simple validated models to immutable value objects with custom hashing logic.
Core Model Presets
| Preset | Description | Key Configuration |
|---|---|---|
| StrictModel | Reusable preset for validated domain boundaries. | Strict validation enforced. |
| ContractModel | Immutable base model with strict validation and return-type verification. | frozen=True, validate_return=True, hide_input_in_errors=True. |
| FrozenValueModel | Value object pattern; equality and hashing are determined by attribute values. | frozen=True, custom __eq__ and __hash__ implementations. |
| Metadata | Standard audit model for timestamps, versioning, and tags. | frozen=True, extra="forbid", populate_by_name=True. |
Sources: src/flext_core/_models/_base_parts/flextmodelsbase_part_02.py:31-90
Specialized Mixins
To support identity and mutability requirements, the following mixins are provided:
- IdentifiableMixin: Adds a
unique_idfield (UUID v4 by default) to models. It uses whitespace normalization for string identifiers. - MutableConfiguredMixin: A preset for models that require
validate_assignment=Truebut are not necessarily frozen.
Sources: src/flext_core/_models/_base_parts/flextmodelsbase_part_02.py:113-138
Class Relationships
The following diagram illustrates the relationship between Pydantic's BaseModel and the specialized DDD base classes in the framework.
The diagram shows the inheritance chain from Pydantic's BaseModel to the core domain presets used for Value Objects and Metadata.
Sources: src/flext_core/_models/_base_parts/flextmodelsbase_part_02.py:34-138
Project Metadata Validation
A significant use case for Pydantic integration within flext-core is the validation and normalization of pyproject.toml data. The FlextModelsProjectMetadata component handles complex transformations, such as converting PEP 621 author dictionaries into simple string sequences and normalizing version requirements.
Normalization Logic
The PyprojectProject model uses Pydantic's BeforeValidator and field_validator to ensure data consistency:
- License: Converts license dictionaries (e.g.,
{"text": "MIT"}) to a flat string. - Authors: Extracts name fields from sequences of author mappings.
- Requires Python: Normalizes version strings by stripping operators and splitting ranges (e.g.,
>=3.13,<3.14becomes3.13).
Sources: src/flext_core/_models/_project_metadata_parts/flextmodelsprojectmetadata_part_02.py:37-82
Metadata Configuration Table
| Field | Type | Default | Description |
|---|---|---|---|
name | str | N/A | Project name (min length 1). |
version | str | N/A | Semantic version string. |
license | str | "UNLICENSED" | Normalized license identifier. |
authors | tuple[str, ...] | () | Sequence of author names. |
requires_python | str | "" | Normalized Python version requirement. |
Sources: src/flext_core/_models/_project_metadata_parts/flextmodelsprojectmetadata_part_02.py:46-77
Implementation Patterns
Value Object Equality
The FrozenValueModel overrides standard equality to ensure comparison is based on the result of model_dump(). The hash is computed by sorting serialized items to maintain stability.
# From src/flext_core/_models/_base_parts/flextmodelsbase_part_02.py
def __hash__(self) -> int:
data = self.model_dump()
return hash(tuple(sorted(((k, str(v)) for k, v in data.items()))))
Sources: src/flext_core/_models/_base_parts/flextmodelsbase_part_02.py:97-100
Domain Entity Definition
Domain entities typically combine IdentifiableMixin with customized Pydantic field configurations. Tests indicate that entities maintain identity even if other attributes change, unlike value objects which are defined by their data.
# Derived from usage in tests/_models/_mixins/domain.py
class DomainTestEntity(m.Entity):
model_config: ClassVar[m.ConfigDict] = m.ConfigDict(frozen=False)
name: Annotated[str, m.Field(description="Entity display name.")]
value: Annotated[t.JsonValue, m.Field(description="Entity payload value.")]
Sources: tests/_models/_mixins/domain.py:24-32
Workflow of Metadata Aggregation
The system aggregates multiple tables from pyproject.toml into a single root ProjectToolFlext model. This model follows a nested structure where each sub-table (docs, namespace, aliases, workspace) is its own validated Pydantic model.
The flow shows how the root configuration model aggregates specialized sub-models for different project aspects.
Sources: src/flext_core/_models/_project_metadata_parts/flextmodelsprojectmetadata_part_04.py:34-71
Conclusion
Domain Models and Pydantic Integration in flext-core provide a rigorous framework for data integrity and architectural clarity. By leveraging Pydantic v2's performance and expressive validation features, the framework enforces DDD principles—such as value object immutability and entity identity—at the type-hint level. This structure facilitates safe data transformations, especially during project metadata ingestion, and provides a stable foundation for the CQRS and dispatcher layers.