Skip to content

BaseValueObject

Base class for value objects -- immutable domain elements without identity, defined entirely by their attributes. Two value objects with the same attributes are considered equal.

See Value Objects guide for practical usage and Value Objects concept for design rationale.

Bases: BaseModel, OptionsMixin

Base class for value objects -- immutable domain elements without identity, defined entirely by their attributes.

Two value objects with the same attribute values are considered equal. Value objects are always embedded within aggregates or entities and cannot exist independently. They become immutable after construction -- any attempt to modify an attribute raises IncorrectUsageError.

Fields are declared using standard Python type annotations with optional Field constraints. Value objects cannot contain identifier or unique fields, and cannot have associations (HasOne, HasMany).

Supports @invariant.post decorators for validation rules that are checked after construction.

Source code in src/protean/core/value_object.py
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
def __init__(self, *args: Any, **kwargs: Any) -> None:
    # Support template dict pattern: VO({"key": "val"}, key2="val2")
    # Keyword args take precedence over template dict values.
    if args:
        merged: dict[str, Any] = {}
        for template in args:
            if not isinstance(template, dict):
                raise AssertionError(
                    f"Positional argument {template} passed must be a dict. "
                    f"This argument serves as a template for loading common "
                    f"values.",
                )
            merged.update(template)
        merged.update(kwargs)
        kwargs = merged
    try:
        super().__init__(**kwargs)
    except PydanticValidationError as e:
        raise ValidationError(convert_pydantic_errors(e))

defaults

defaults() -> None

Placeholder for defaults. Override in subclass when an attribute's default depends on other attribute values.

Source code in src/protean/core/value_object.py
229
230
231
def defaults(self) -> None:
    """Placeholder for defaults. Override in subclass when
    an attribute's default depends on other attribute values."""

to_dict

to_dict() -> dict[str, Any]

Return data as a dictionary.

Source code in src/protean/core/value_object.py
254
255
256
257
258
259
def to_dict(self) -> dict[str, Any]:
    """Return data as a dictionary."""
    result: dict[str, Any] = {}
    for fname, shim in getattr(self, _FIELDS, {}).items():
        result[fname] = shim.as_dict(getattr(self, fname, None))
    return result