Skip to content

API Reference

Complete API documentation for Cobjectric.

Core Model Classes

See BaseModel Guide for detailed usage examples.

BaseModel(**kwargs)

Base class for models with typed fields.

Fields are defined as class attributes with type annotations. Fields can be accessed via the .fields attribute, which provides readonly access to Field instances.

Initialize a BaseModel instance.

Parameters:

Name Type Description Default
**kwargs Any

Field values to set. Fields not provided will have MissingValue. Fields with invalid types will also have MissingValue.

{}
Source code in src/cobjectric/base_model.py
def __init__(self, **kwargs: t.Any) -> None:
    """
    Initialize a BaseModel instance.

    Args:
        **kwargs: Field values to set. Fields not provided will have
            MissingValue. Fields with invalid types will also have MissingValue.
    """
    annotations = getattr(self.__class__, "__annotations__", {})
    fields: dict[str, Field | BaseModel] = {}

    # Collect decorator normalizers once per class
    field_normalizers = self._collect_field_normalizers()

    for field_name, field_type in annotations.items():
        if field_name.startswith("_"):
            continue

        self._validate_field_type(field_type)

        value = kwargs.get(field_name, MissingValue)

        # Get FieldSpec from class attribute (if Spec() was used)
        class_default = getattr(self.__class__, field_name, None)
        if isinstance(class_default, FieldSpec):
            spec = class_default
        else:
            spec = FieldSpec()  # Default

        # Apply normalizers before type validation
        if value is not MissingValue:
            # Create context for contextual normalizers
            context = FieldContext(
                name=field_name, field_type=field_type, spec=spec
            )
            combined_normalizer = self._build_combined_normalizer(
                spec.normalizer,
                field_normalizers.get(field_name, []),
                context=context,
            )
            if combined_normalizer:
                value = combined_normalizer(value)
                # Create new FieldSpec with combined normalizer,
                # preserving all other spec attributes
                spec = FieldSpec(
                    metadata=spec.metadata,
                    normalizer=combined_normalizer,
                    fill_rate_func=spec.fill_rate_func,
                    fill_rate_weight=spec.fill_rate_weight,
                    fill_rate_accuracy_func=spec.fill_rate_accuracy_func,
                    fill_rate_accuracy_weight=spec.fill_rate_accuracy_weight,
                    similarity_func=spec.similarity_func,
                    similarity_weight=spec.similarity_weight,
                    list_compare_strategy=spec.list_compare_strategy,
                )

            # Then validate type
            value = self._validate_and_process_value(value, field_type)

        # Check if this is a nested model
        is_nested_model = self._is_base_model_type(field_type)

        if is_nested_model:
            if value is not MissingValue and isinstance(value, BaseModel):
                fields[field_name] = value
            else:
                fields[field_name] = Field(
                    name=field_name,
                    type=field_type,
                    value=value,
                    spec=spec,
                )
        else:
            fields[field_name] = Field(
                name=field_name,
                type=field_type,
                value=value,
                spec=spec,
            )

    setattr(self, "_fields", fields)  # noqa: B010
    setattr(self, "_initialized", True)  # noqa: B010

Attributes

fields property

Get the FieldCollection for this instance.

Returns:

Type Description
FieldCollection

The FieldCollection containing all fields.

Functions

__getitem__(path)

Get a field value by path.

Parameters:

Name Type Description Default
path str

Path to the field (e.g., "name", "address.city", "items[0].name").

required

Returns:

Type Description
Any

The field value.

Raises:

Type Description
KeyError

If the path is invalid.

Source code in src/cobjectric/base_model.py
def __getitem__(self, path: str) -> t.Any:
    """
    Get a field value by path.

    Args:
        path: Path to the field (e.g., "name", "address.city", "items[0].name").

    Returns:
        The field value.

    Raises:
        KeyError: If the path is invalid.
    """
    return self.fields[path]

__repr__()

Return a string representation of the BaseModel instance.

Format: ClassName(field1=value1, field2=MISSING, ...) Similar to Pydantic's representation style.

Returns:

Type Description
str

String representation of the model.

Source code in src/cobjectric/base_model.py
def __repr__(self) -> str:
    """
    Return a string representation of the BaseModel instance.

    Format: ClassName(field1=value1, field2=MISSING, ...)
    Similar to Pydantic's representation style.

    Returns:
        String representation of the model.
    """
    parts: list[str] = []
    for name, field in self._fields.items():
        if isinstance(field, BaseModel):
            parts.append(f"{name}={field!r}")
        elif field.value is MissingValue:
            parts.append(f"{name}=MISSING")
        elif isinstance(field.value, list):
            # Handle lists of BaseModel or primitives
            items_repr: list[str] = []
            for item in field.value:
                if isinstance(item, BaseModel):
                    items_repr.append(repr(item))
                else:
                    items_repr.append(repr(item))
            parts.append(f"{name}=[{', '.join(items_repr)}]")
        else:
            parts.append(f"{name}={field.value!r}")
    return f"{self.__class__.__name__}({', '.join(parts)})"

__setattr__(name, value)

Prevent setting attributes after initialization.

Parameters:

Name Type Description Default
name str

The attribute name.

required
value Any

The value to set.

required

Raises:

Type Description
AttributeError

If trying to set an attribute after initialization.

Source code in src/cobjectric/base_model.py
def __setattr__(self, name: str, value: t.Any) -> None:
    """
    Prevent setting attributes after initialization.

    Args:
        name: The attribute name.
        value: The value to set.

    Raises:
        AttributeError: If trying to set an attribute after initialization.
    """
    if hasattr(self, "_initialized") and self._initialized:
        raise AttributeError(
            f"'{self.__class__.__name__}' object attributes are readonly"
        )
    object.__setattr__(self, name, value)

compute_fill_rate()

Compute fill rate for all fields in this model.

Returns:

Type Description
ModelResult

ModelResult containing fill rates for all fields.

Raises:

Type Description
DuplicateFillRateFuncError

If multiple fill_rate_func are defined for the same field.

InvalidFillRateValueError

If a fill_rate_func returns an invalid value.

Source code in src/cobjectric/base_model.py
def compute_fill_rate(self) -> ModelResult:
    """
    Compute fill rate for all fields in this model.

    Returns:
        ModelResult containing fill rates for all fields.

    Raises:
        DuplicateFillRateFuncError: If multiple fill_rate_func are defined
            for the same field.
        InvalidFillRateValueError: If a fill_rate_func returns an invalid value.
    """
    # Collect decorator fill_rate_funcs once per class
    decorator_fill_rate_funcs = self._collect_fill_rate_funcs()

    result_fields: dict[str, FieldResult | ModelResult | ListResult] = {}

    for field_name, field in self._fields.items():
        # Get FieldSpec
        if isinstance(field, Field):
            spec = field.spec
        else:
            # Nested model - use default spec
            spec = FieldSpec()

        # Check for duplicates
        spec_func = spec.fill_rate_func
        decorator_funcs = decorator_fill_rate_funcs.get(field_name, [])

        # Only consider it a duplicate if spec_func is not the default
        if (
            spec_func is not None
            and spec_func != not_missing_fill_rate
            and decorator_funcs
        ):
            raise DuplicateFillRateFuncError(field_name)

        if len(decorator_funcs) > 1:
            raise DuplicateFillRateFuncError(field_name)

        # Get the fill_rate_func to use
        # Decorator takes precedence, otherwise use spec (which has a default)
        fill_rate_func_to_use: FillRateFunc = (
            decorator_funcs[0].func if decorator_funcs else spec_func
        )

        # Get the weight to use (decorator > Spec > default 1.0)
        weight_to_use: float = 1.0
        if decorator_funcs:
            # Decorator weight takes precedence
            weight_to_use = decorator_funcs[0].weight
        elif spec.fill_rate_weight != 1.0:
            # Use Spec weight if different from default
            weight_to_use = spec.fill_rate_weight

        # Check if this is a nested model
        if isinstance(field, BaseModel):
            # Recursively compute fill rate for nested model
            nested_result = field.compute_fill_rate()
            result_fields[field_name] = nested_result
            continue

        # Check if this field is a list type
        if isinstance(field, Field) and self._is_list_type(field.type):
            element_type = self._get_list_element_type(field.type)

            if self._is_base_model_type(element_type):
                # list[BaseModel] → ListResult
                if field.value is MissingValue:
                    result_fields[field_name] = ListResult(
                        _items=[], weight=weight_to_use, _element_type=element_type
                    )
                elif not field.value:  # Liste vide
                    result_fields[field_name] = ListResult(
                        _items=[], weight=weight_to_use, _element_type=element_type
                    )
                else:
                    items_results = [
                        item.compute_fill_rate() for item in field.value
                    ]
                    result_fields[field_name] = ListResult(
                        _items=items_results,
                        weight=weight_to_use,
                        _element_type=element_type,
                    )
            else:
                # list[Primitive] → FieldResult
                # Empty list should return 0.0, otherwise use the function
                if field.value is MissingValue or not field.value:
                    fill_value = 0.0
                else:
                    fill_value = fill_rate_func_to_use(field.value)
                fill_value = self._validate_fill_rate_value(field_name, fill_value)

                result_fields[field_name] = FieldResult(
                    value=fill_value, weight=weight_to_use
                )
            continue

        # Check if this field is a nested model type but MissingValue
        is_nested_model_type = self._is_base_model_type(field.type)
        if is_nested_model_type and field.value is MissingValue:
            # Create a ModelResult with all fields at 0.0
            result_fields[field_name] = self._create_empty_model_result(
                field.type, 0.0
            )
        else:
            # Compute fill rate for this field
            field_value = field.value
            fill_rate_value = fill_rate_func_to_use(field_value)
            validated_value = self._validate_fill_rate_value(
                field_name, fill_rate_value
            )
            result_fields[field_name] = FieldResult(
                value=validated_value, weight=weight_to_use
            )

    return ModelResult(_fields=result_fields)

compute_fill_rate_accuracy(expected)

Compute fill rate accuracy for all fields compared to expected model.

Parameters:

Name Type Description Default
expected BaseModel

The expected model to compare against (same type).

required

Returns:

Type Description
ModelResult

ModelResult containing accuracy scores for all fields.

ModelResult

Uses fill_rate_accuracy_weight (not fill_rate_weight) for weighted mean.

Raises:

Type Description
DuplicateFillRateAccuracyFuncError

If multiple fill_rate_accuracy_func are defined for the same field.

InvalidFillRateAccuracyValueError

If a fill_rate_accuracy_func returns an invalid value.

InvalidListCompareStrategyError

If list_compare_strategy is used on a non-list field.

Source code in src/cobjectric/base_model.py
def compute_fill_rate_accuracy(self, expected: BaseModel) -> ModelResult:
    """
    Compute fill rate accuracy for all fields compared to expected model.

    Args:
        expected: The expected model to compare against (same type).

    Returns:
        ModelResult containing accuracy scores for all fields.
        Uses fill_rate_accuracy_weight (not fill_rate_weight) for weighted mean.

    Raises:
        DuplicateFillRateAccuracyFuncError: If multiple
            fill_rate_accuracy_func are defined for the same field.
        InvalidFillRateAccuracyValueError: If a fill_rate_accuracy_func returns
            an invalid value.
        InvalidListCompareStrategyError: If list_compare_strategy is used on
            a non-list field.
    """
    # Collect decorator fill_rate_accuracy_funcs once per class
    decorator_fill_rate_accuracy_funcs = self._collect_fill_rate_accuracy_funcs()

    result_fields: dict[str, FieldResult | ModelResult | ListResult] = {}

    for field_name, field in self._fields.items():
        # Get corresponding field from expected model
        expected_field = expected._fields.get(field_name)
        if expected_field is None:
            # Field doesn't exist in expected, treat as MissingValue
            expected_value: t.Any = MissingValue
        elif isinstance(expected_field, BaseModel):
            expected_value = expected_field
        else:
            expected_value = expected_field.value

        # Get FieldSpec
        if isinstance(field, Field):
            spec = field.spec
        else:
            # Nested model - use default spec
            spec = FieldSpec()

        # Validate list_compare_strategy is only used on list[BaseModel]
        if isinstance(field, Field):
            if spec.list_compare_strategy != ListCompareStrategy.PAIRWISE:
                if not self._is_list_type(field.type):
                    raise InvalidListCompareStrategyError(field_name)
                element_type = self._get_list_element_type(field.type)
                if not self._is_base_model_type(element_type):
                    raise InvalidListCompareStrategyError(field_name)

        # Check for duplicates
        spec_func = spec.fill_rate_accuracy_func
        decorator_funcs = decorator_fill_rate_accuracy_funcs.get(field_name, [])

        # Only consider it a duplicate if spec_func is not the default
        if (
            spec_func is not None
            and spec_func != same_state_fill_rate_accuracy
            and decorator_funcs
        ):
            raise DuplicateFillRateAccuracyFuncError(field_name)

        if len(decorator_funcs) > 1:
            raise DuplicateFillRateAccuracyFuncError(field_name)

        # Get the fill_rate_accuracy_func to use
        # Decorator takes precedence, otherwise use spec (which has a default)
        fill_rate_accuracy_func_to_use: FillRateAccuracyFunc = (
            decorator_funcs[0].func if decorator_funcs else spec_func
        )

        # Get the weight to use (decorator > Spec > default 1.0)
        weight_to_use: float = 1.0
        if decorator_funcs:
            # Decorator weight takes precedence
            weight_to_use = decorator_funcs[0].weight
        elif spec.fill_rate_accuracy_weight != 1.0:
            # Use Spec weight if different from default
            weight_to_use = spec.fill_rate_accuracy_weight

        # Check if this is a nested model
        if isinstance(field, BaseModel):
            # Recursively compute fill rate accuracy for nested model
            if isinstance(expected_value, BaseModel):
                nested_result = field.compute_fill_rate_accuracy(expected_value)
            else:
                # Expected is MissingValue, create empty result
                nested_result = self._create_empty_model_result(
                    field.__class__, 0.0
                )
            result_fields[field_name] = nested_result
            continue

        # Check if this field is a list type
        if isinstance(field, Field) and self._is_list_type(field.type):
            element_type = self._get_list_element_type(field.type)

            if self._is_base_model_type(element_type):
                # list[BaseModel] → ListResult
                got_list = field.value if field.value is not MissingValue else []
                expected_list = (
                    expected_value
                    if expected_value is not MissingValue
                    and isinstance(expected_value, list)
                    else []
                )

                # Get alignment based on strategy
                strategy = spec.list_compare_strategy

                def compute_accuracy(
                    got_item: BaseModel,
                    expected_item: BaseModel,
                ) -> ModelResult:
                    return got_item.compute_fill_rate_accuracy(expected_item)

                alignment = self._get_list_alignment(
                    got_list, expected_list, strategy, compute_accuracy
                )

                # Compare items based on alignment
                items_results = []
                for got_idx, expected_idx in alignment:
                    got_item = got_list[got_idx]
                    expected_item = expected_list[expected_idx]

                    # Both present - recursively compute
                    if isinstance(got_item, BaseModel) and isinstance(
                        expected_item, BaseModel
                    ):
                        item_result = got_item.compute_fill_rate_accuracy(
                            expected_item
                        )
                        items_results.append(item_result)
                    else:
                        # Type mismatch - create empty result
                        items_results.append(
                            self._create_empty_model_result(element_type, 0.0)
                        )

                result_fields[field_name] = ListResult(
                    _items=items_results,
                    weight=weight_to_use,
                    _element_type=element_type,
                )
            else:
                # list[Primitive] → FieldResult
                accuracy_value = fill_rate_accuracy_func_to_use(
                    field.value, expected_value
                )
                validated_value = self._validate_metric_value(
                    field_name, accuracy_value, "fill_rate_accuracy"
                )
                result_fields[field_name] = FieldResult(
                    value=validated_value, weight=weight_to_use
                )
            continue

        # Check if this field is a nested model type but MissingValue
        is_nested_model_type = self._is_base_model_type(field.type)
        if is_nested_model_type:
            if field.value is MissingValue and expected_value is MissingValue:
                # Both missing -> accuracy = 1.0 for all nested fields
                result_fields[field_name] = self._create_empty_model_result(
                    field.type, 1.0
                )
            elif field.value is MissingValue or expected_value is MissingValue:
                # One missing -> accuracy = 0.0 for all nested fields
                result_fields[field_name] = self._create_empty_model_result(
                    field.type, 0.0
                )
            else:
                # Both present - recursively compute
                got_nested = field.value
                expected_nested = expected_value
                if isinstance(expected_nested, BaseModel):
                    nested_result = got_nested.compute_fill_rate_accuracy(
                        expected_nested
                    )
                else:
                    # Expected is not BaseModel, treat as missing
                    nested_result = self._create_empty_model_result(field.type, 0.0)
                result_fields[field_name] = nested_result
        else:
            # Compute fill rate accuracy for this field
            got_value = field.value
            accuracy_value = fill_rate_accuracy_func_to_use(
                got_value, expected_value
            )
            validated_value = self._validate_metric_value(
                field_name, accuracy_value, "fill_rate_accuracy"
            )
            result_fields[field_name] = FieldResult(
                value=validated_value, weight=weight_to_use
            )

    return ModelResult(_fields=result_fields)

compute_similarity(expected)

Compute similarity for all fields compared to expected model.

Parameters:

Name Type Description Default
expected BaseModel

The expected model to compare against (same type).

required

Returns:

Type Description
ModelResult

ModelResult containing similarity scores for all fields.

ModelResult

Uses similarity_weight for weighted mean.

Raises:

Type Description
DuplicateSimilarityFuncError

If multiple similarity_func are defined for the same field.

InvalidSimilarityValueError

If a similarity_func returns an invalid value.

InvalidListCompareStrategyError

If list_compare_strategy is used on a non-list field.

Source code in src/cobjectric/base_model.py
def compute_similarity(self, expected: BaseModel) -> ModelResult:
    """
    Compute similarity for all fields compared to expected model.

    Args:
        expected: The expected model to compare against (same type).

    Returns:
        ModelResult containing similarity scores for all fields.
        Uses similarity_weight for weighted mean.

    Raises:
        DuplicateSimilarityFuncError: If multiple similarity_func are defined
            for the same field.
        InvalidSimilarityValueError: If a similarity_func returns an invalid value.
        InvalidListCompareStrategyError: If list_compare_strategy is used on
            a non-list field.
    """
    # Collect decorator similarity_funcs once per class
    decorator_similarity_funcs = self._collect_similarity_funcs()

    result_fields: dict[str, FieldResult | ModelResult | ListResult] = {}

    for field_name, field in self._fields.items():
        # Get corresponding field from expected model
        expected_field = expected._fields.get(field_name)
        if expected_field is None:
            # Field doesn't exist in expected, treat as MissingValue
            expected_value: t.Any = MissingValue
        elif isinstance(expected_field, BaseModel):
            expected_value = expected_field
        else:
            expected_value = expected_field.value

        # Get FieldSpec
        if isinstance(field, Field):
            spec = field.spec
        else:
            # Nested model - use default spec
            spec = FieldSpec()

        # Validate list_compare_strategy is only used on list[BaseModel]
        if isinstance(field, Field):
            if spec.list_compare_strategy != ListCompareStrategy.PAIRWISE:
                if not self._is_list_type(field.type):
                    raise InvalidListCompareStrategyError(field_name)
                element_type = self._get_list_element_type(field.type)
                if not self._is_base_model_type(element_type):
                    raise InvalidListCompareStrategyError(field_name)

        # Check for duplicates
        spec_func = spec.similarity_func
        decorator_funcs = decorator_similarity_funcs.get(field_name, [])

        # Only consider it a duplicate if spec_func is not the default
        if (
            spec_func is not None
            and spec_func != exact_similarity
            and decorator_funcs
        ):
            raise DuplicateSimilarityFuncError(field_name)

        if len(decorator_funcs) > 1:
            raise DuplicateSimilarityFuncError(field_name)

        # Get the similarity_func to use
        # Decorator takes precedence, otherwise use spec (which has a default)
        similarity_func_to_use: SimilarityFunc = (
            decorator_funcs[0].func if decorator_funcs else spec_func
        )

        # Get the weight to use (decorator > Spec > default 1.0)
        weight_to_use: float = 1.0
        if decorator_funcs:
            # Decorator weight takes precedence
            weight_to_use = decorator_funcs[0].weight
        elif spec.similarity_weight != 1.0:
            # Use Spec weight if different from default
            weight_to_use = spec.similarity_weight

        # Check if this is a nested model
        if isinstance(field, BaseModel):
            # Recursively compute similarity for nested model
            if isinstance(expected_value, BaseModel):
                nested_result = field.compute_similarity(expected_value)
            else:
                # Expected is MissingValue, create empty result
                nested_result = self._create_empty_model_result(
                    field.__class__, 0.0
                )
            result_fields[field_name] = nested_result
            continue

        # Check if this field is a list type
        if isinstance(field, Field) and self._is_list_type(field.type):
            element_type = self._get_list_element_type(field.type)

            if self._is_base_model_type(element_type):
                # list[BaseModel] → ListResult
                got_list = field.value if field.value is not MissingValue else []
                expected_list = (
                    expected_value
                    if expected_value is not MissingValue
                    and isinstance(expected_value, list)
                    else []
                )

                # Get alignment based on strategy
                strategy = spec.list_compare_strategy

                def compute_sim(
                    got_item: BaseModel,
                    expected_item: BaseModel,
                ) -> ModelResult:
                    return got_item.compute_similarity(expected_item)

                alignment = self._get_list_alignment(
                    got_list, expected_list, strategy, compute_sim
                )

                # Compare items based on alignment
                items_results = []
                for got_idx, expected_idx in alignment:
                    got_item = got_list[got_idx]
                    expected_item = expected_list[expected_idx]

                    # Both present - recursively compute
                    if isinstance(got_item, BaseModel) and isinstance(
                        expected_item, BaseModel
                    ):
                        item_result = got_item.compute_similarity(expected_item)
                        items_results.append(item_result)
                    else:
                        # Type mismatch - create empty result
                        items_results.append(
                            self._create_empty_model_result(element_type, 0.0)
                        )

                result_fields[field_name] = ListResult(
                    _items=items_results,
                    weight=weight_to_use,
                    _element_type=element_type,
                )
            else:
                # list[Primitive] → FieldResult
                similarity_value = similarity_func_to_use(
                    field.value, expected_value
                )
                validated_value = self._validate_metric_value(
                    field_name, similarity_value, "similarity"
                )
                result_fields[field_name] = FieldResult(
                    value=validated_value, weight=weight_to_use
                )
            continue

        # Check if this field is a nested model type but MissingValue
        is_nested_model_type = self._is_base_model_type(field.type)
        if is_nested_model_type:
            if field.value is MissingValue and expected_value is MissingValue:
                # Both missing -> similarity = 1.0 for all nested fields
                result_fields[field_name] = self._create_empty_model_result(
                    field.type, 1.0
                )
            elif field.value is MissingValue or expected_value is MissingValue:
                # One missing -> similarity = 0.0 for all nested fields
                result_fields[field_name] = self._create_empty_model_result(
                    field.type, 0.0
                )
            else:
                # Both present - recursively compute
                got_nested = field.value
                expected_nested = expected_value
                if isinstance(expected_nested, BaseModel):
                    nested_result = got_nested.compute_similarity(expected_nested)
                else:
                    # Expected is not BaseModel, treat as missing
                    nested_result = self._create_empty_model_result(field.type, 0.0)
                result_fields[field_name] = nested_result
        else:
            # Compute similarity for this field
            got_value = field.value
            similarity_value = similarity_func_to_use(got_value, expected_value)
            validated_value = self._validate_metric_value(
                field_name, similarity_value, "similarity"
            )
            result_fields[field_name] = FieldResult(
                value=validated_value, weight=weight_to_use
            )

    return ModelResult(_fields=result_fields)

from_dict(data) classmethod

Create a BaseModel instance from a dictionary.

Parameters:

Name Type Description Default
data dict[str, Any]

Dictionary mapping field names to values.

required

Returns:

Type Description
Self

A new instance of the model with fields populated from the dictionary.

Source code in src/cobjectric/base_model.py
@classmethod
def from_dict(cls, data: dict[str, t.Any]) -> t.Self:
    """
    Create a BaseModel instance from a dictionary.

    Args:
        data: Dictionary mapping field names to values.

    Returns:
        A new instance of the model with fields populated from the dictionary.
    """
    return cls(**data)

FieldSpec(metadata=dict(), normalizer=None, fill_rate_func=not_missing_fill_rate, fill_rate_weight=1.0, fill_rate_accuracy_func=same_state_fill_rate_accuracy, fill_rate_accuracy_weight=1.0, similarity_func=exact_similarity, similarity_weight=1.0, list_compare_strategy=ListCompareStrategy.PAIRWISE) dataclass

Specification for a field in a BaseModel.

Spec(metadata=None, normalizer=None, fill_rate_func=None, fill_rate_weight=1.0, fill_rate_accuracy_func=None, fill_rate_accuracy_weight=1.0, similarity_func=None, similarity_weight=1.0, list_compare_strategy=None)

Create a FieldSpec for a field.

Parameters:

Name Type Description Default
metadata dict[str, Any] | None

Optional metadata for the field.

None
normalizer AnyNormalizer | None

Optional normalizer function for the field. Can be a simple normalizer (1 param: value) or contextual (2 params: value, context).

None
fill_rate_func FillRateFunc | None

Optional fill rate function for the field.

None
fill_rate_weight float

Weight for fill rate computation (default: 1.0, must be >= 0.0).

1.0
fill_rate_accuracy_func FillRateAccuracyFunc | None

Optional fill rate accuracy function.

None
fill_rate_accuracy_weight float

Weight for fill rate accuracy computation (default: 1.0, must be >= 0.0).

1.0
similarity_func SimilarityFunc | None

Optional similarity function.

None
similarity_weight float

Weight for similarity computation (default: 1.0, must be >= 0.0).

1.0
list_compare_strategy ListCompareStrategy | str | None

Strategy for comparing list[BaseModel] items. Valid values: "pairwise", "levenshtein", "optimal_assignment", or ListCompareStrategy enum values. Only valid for list[BaseModel] fields (default: PAIRWISE).

None

Returns:

Name Type Description
Any Any

A FieldSpec instance (typed as Any for type checker compatibility).

Raises:

Type Description
InvalidWeightError

If weight is negative (< 0.0).

ValueError

If list_compare_strategy is an invalid string value.

Source code in src/cobjectric/field_spec.py
def Spec(  # noqa: N802
    metadata: dict[str, t.Any] | None = None,
    normalizer: AnyNormalizer | None = None,
    fill_rate_func: FillRateFunc | None = None,
    fill_rate_weight: float = 1.0,
    fill_rate_accuracy_func: FillRateAccuracyFunc | None = None,
    fill_rate_accuracy_weight: float = 1.0,
    similarity_func: SimilarityFunc | None = None,
    similarity_weight: float = 1.0,
    list_compare_strategy: ListCompareStrategy | str | None = None,
) -> t.Any:
    """
    Create a FieldSpec for a field.

    Args:
        metadata (dict[str, Any] | None): Optional metadata for the field.
        normalizer (AnyNormalizer | None): Optional normalizer function for the field.
            Can be a simple normalizer (1 param: value) or contextual
            (2 params: value, context).
        fill_rate_func (FillRateFunc | None): Optional fill rate function for the field.
        fill_rate_weight (float): Weight for fill rate computation
            (default: 1.0, must be >= 0.0).
        fill_rate_accuracy_func (FillRateAccuracyFunc | None): Optional
            fill rate accuracy function.
        fill_rate_accuracy_weight (float): Weight for fill rate accuracy computation
            (default: 1.0, must be >= 0.0).
        similarity_func (SimilarityFunc | None): Optional similarity function.
        similarity_weight (float): Weight for similarity computation
            (default: 1.0, must be >= 0.0).
        list_compare_strategy (ListCompareStrategy | str | None): Strategy for
            comparing list[BaseModel] items. Valid values: "pairwise", "levenshtein",
            "optimal_assignment", or ListCompareStrategy enum values.
            Only valid for list[BaseModel] fields (default: PAIRWISE).

    Returns:
        Any: A FieldSpec instance (typed as Any for type checker compatibility).

    Raises:
        InvalidWeightError: If weight is negative (< 0.0).
        ValueError: If list_compare_strategy is an invalid string value.
    """
    if fill_rate_weight < 0.0:
        raise InvalidWeightError(fill_rate_weight, "Spec", "fill_rate")
    if fill_rate_accuracy_weight < 0.0:
        raise InvalidWeightError(
            fill_rate_accuracy_weight, "Spec", "fill_rate_accuracy"
        )
    if similarity_weight < 0.0:
        raise InvalidWeightError(similarity_weight, "Spec", "similarity")

    # Convert string to enum if needed
    strategy: ListCompareStrategy = ListCompareStrategy.PAIRWISE
    if list_compare_strategy is not None:
        if isinstance(list_compare_strategy, ListCompareStrategy):
            strategy = list_compare_strategy
        elif isinstance(list_compare_strategy, str):
            try:
                strategy = ListCompareStrategy(list_compare_strategy)
            except ValueError as e:
                raise ValueError(
                    f"Invalid list_compare_strategy: {list_compare_strategy}. "
                    f"Valid values: {[s.value for s in ListCompareStrategy]}"
                ) from e
        else:
            raise ValueError(
                f"list_compare_strategy must be str or ListCompareStrategy, "
                f"got {type(list_compare_strategy).__name__}"
            )

    return FieldSpec(
        metadata=metadata if metadata is not None else {},
        normalizer=normalizer,
        fill_rate_func=(
            fill_rate_func if fill_rate_func is not None else not_missing_fill_rate
        ),
        fill_rate_weight=fill_rate_weight,
        fill_rate_accuracy_func=(
            fill_rate_accuracy_func
            if fill_rate_accuracy_func is not None
            else same_state_fill_rate_accuracy
        ),
        fill_rate_accuracy_weight=fill_rate_accuracy_weight,
        similarity_func=(
            similarity_func if similarity_func is not None else exact_similarity
        ),
        similarity_weight=similarity_weight,
        list_compare_strategy=strategy,
    )

See Field Specifications Guide for advanced customization.

Sentinel Values

MissingValue = Sentinel('MissingValue') module-attribute

Context

FieldContext(name, field_type, spec) dataclass

Context information passed to contextual normalizers.

Attributes:

Name Type Description
name str

The field name.

field_type type

The declared Python type of the field.

spec FieldSpec

The FieldSpec associated with the field.

Field Results

See Fill Rate Guide for usage and examples.

Fill Rate Results

FieldResult(value, weight=1.0) dataclass

Result of metric computation for a single field.

Attributes:

Name Type Description
value float

The metric value (float between 0.0 and 1.0).

weight float

Weight for this field in weighted mean calculation (default: 1.0).

Functions

__repr__()

Return a string representation of the FieldResult.

Source code in src/cobjectric/results.py
def __repr__(self) -> str:
    """Return a string representation of the FieldResult."""
    return f"FieldResult(value={self.value}, weight={self.weight})"

FieldResultCollection(fields)

Collection of metric results for a model instance.

Provides attribute-based access to metric results.

Initialize a FieldResultCollection.

Parameters:

Name Type Description Default
fields dict[str, FieldResult | ModelResult | ListResult]

Dictionary mapping field names to FieldResult, ModelResult, or ListResult instances.

required
Source code in src/cobjectric/results.py
def __init__(
    self,
    fields: dict[
        str,
        FieldResult | ModelResult | ListResult,
    ],
) -> None:
    """
    Initialize a FieldResultCollection.

    Args:
        fields: Dictionary mapping field names to FieldResult,
            ModelResult, or ListResult instances.
    """
    self._fields = fields

Functions

__getattr__(name)

Get a metric result by field name.

Parameters:

Name Type Description Default
name str

The name of the field.

required

Returns:

Type Description
FieldResult | ModelResult | ListResult

The FieldResult or ModelResult instance.

Raises:

Type Description
AttributeError

If the field does not exist.

Source code in src/cobjectric/results.py
def __getattr__(self, name: str) -> FieldResult | ModelResult | ListResult:
    """
    Get a metric result by field name.

    Args:
        name: The name of the field.

    Returns:
        The FieldResult or ModelResult instance.

    Raises:
        AttributeError: If the field does not exist.
    """
    if name in self._fields:
        return self._fields[name]
    raise AttributeError(
        f"'{self.__class__.__name__}' object has no attribute '{name}'"
    )

__getitem__(path)

Get a fill rate result by path.

Parameters:

Name Type Description Default
path str

Path to the field (e.g., "name", "address.city", "items[0].name").

required

Returns:

Type Description
FieldResult | ModelResult | ListResult

The FieldResult or ModelResult instance.

Raises:

Type Description
KeyError

If the path is invalid.

Source code in src/cobjectric/results.py
def __getitem__(self, path: str) -> FieldResult | ModelResult | ListResult:
    """
    Get a fill rate result by path.

    Args:
        path: Path to the field (e.g., "name", "address.city", "items[0].name").

    Returns:
        The FieldResult or ModelResult instance.

    Raises:
        KeyError: If the path is invalid.
    """
    segments = parse_path(path)
    return self._resolve_path(segments)

__iter__()

Iterate over all metric results.

Source code in src/cobjectric/results.py
def __iter__(
    self,
) -> t.Iterator[FieldResult | ModelResult | ListResult]:
    """Iterate over all metric results."""
    return iter(self._fields.values())

__repr__()

Return a string representation of the FieldResultCollection.

Source code in src/cobjectric/results.py
def __repr__(self) -> str:
    """Return a string representation of the FieldResultCollection."""
    fields_repr = ", ".join(f"{name}=..." for name in self._fields.keys())
    return f"FieldResultCollection({fields_repr})"

ModelResult(_fields) dataclass

Bases: StatsMixin

Result of metric computation for a model instance.

Attributes:

Name Type Description
_fields dict[str, FieldResult | ModelResult | ListResult]

Dictionary mapping field names to FieldResult, ModelResult, or ListResult instances.

Attributes

fields property

Get the FieldResultCollection for this result.

Returns:

Type Description
FieldResultCollection

The FieldResultCollection containing all metric results.

Functions

__add__(other)

Combine two ModelResults into a collection.

Parameters:

Name Type Description Default
other 'ModelResult'

Another ModelResult to combine.

required

Returns:

Type Description
'ModelResultCollection'

ModelResultCollection containing both results.

Raises:

Type Description
IncompatibleModelResultError

If results come from different model types.

Source code in src/cobjectric/results.py
def __add__(self, other: "ModelResult") -> "ModelResultCollection":
    """
    Combine two ModelResults into a collection.

    Args:
        other: Another ModelResult to combine.

    Returns:
        ModelResultCollection containing both results.

    Raises:
        IncompatibleModelResultError: If results come from different model types.
    """
    from cobjectric.exceptions import IncompatibleModelResultError  # noqa: PLC0415

    # Check if both results come from the same model type
    # We can infer this by checking if they have the same field structure
    self_fields = set(self._fields.keys())
    other_fields = set(other._fields.keys())

    if self_fields != other_fields:
        # Try to get model types from the results if possible
        # For now, we'll use a generic error message
        raise IncompatibleModelResultError(type(self), type(other))

    return ModelResultCollection([self, other])

__getitem__(path)

Get a fill rate result by path.

Parameters:

Name Type Description Default
path str

Path to the field (e.g., "name", "address.city", "items[0].name").

required

Returns:

Type Description
FieldResult | ModelResult | ListResult

The FieldResult or ModelResult instance.

Raises:

Type Description
KeyError

If the path is invalid.

Source code in src/cobjectric/results.py
def __getitem__(self, path: str) -> FieldResult | ModelResult | ListResult:
    """
    Get a fill rate result by path.

    Args:
        path: Path to the field (e.g., "name", "address.city", "items[0].name").

    Returns:
        The FieldResult or ModelResult instance.

    Raises:
        KeyError: If the path is invalid.
    """
    return self.fields[path]

__repr__()

Return a string representation of the ModelResult.

Source code in src/cobjectric/results.py
def __repr__(self) -> str:
    """Return a string representation of the ModelResult."""
    fields_repr = ", ".join(
        f"{name}={field!r}" for name, field in self._fields.items()
    )
    return f"ModelResult({fields_repr})"

to_series()

Export to pandas Series (requires cobjectric[pandas]).

Returns:

Type Description
Any

pandas.Series with field paths as index and values as data.

Raises:

Type Description
ImportError

If pandas is not installed.

Source code in src/cobjectric/results.py
def to_series(self) -> t.Any:
    """
    Export to pandas Series (requires cobjectric[pandas]).

    Returns:
        pandas.Series with field paths as index and values as data.

    Raises:
        ImportError: If pandas is not installed.
    """
    from cobjectric.pandas_export import (  # noqa: PLC0415
        _flatten_to_dict,
        _get_pandas,
    )

    pd = _get_pandas()
    flattened = _flatten_to_dict(self)
    return pd.Series(flattened)

See Pandas Export Guide for exporting ModelResult to pandas Series.

Fill Rate Accuracy Results

See Fill Rate Accuracy Guide for usage and examples.

FieldResult(value, weight=1.0) dataclass

Result of metric computation for a single field.

Attributes:

Name Type Description
value float

The metric value (float between 0.0 and 1.0).

weight float

Weight for this field in weighted mean calculation (default: 1.0).

Functions

__repr__()

Return a string representation of the FieldResult.

Source code in src/cobjectric/results.py
def __repr__(self) -> str:
    """Return a string representation of the FieldResult."""
    return f"FieldResult(value={self.value}, weight={self.weight})"

FieldResultCollection(fields)

Collection of metric results for a model instance.

Provides attribute-based access to metric results.

Initialize a FieldResultCollection.

Parameters:

Name Type Description Default
fields dict[str, FieldResult | ModelResult | ListResult]

Dictionary mapping field names to FieldResult, ModelResult, or ListResult instances.

required
Source code in src/cobjectric/results.py
def __init__(
    self,
    fields: dict[
        str,
        FieldResult | ModelResult | ListResult,
    ],
) -> None:
    """
    Initialize a FieldResultCollection.

    Args:
        fields: Dictionary mapping field names to FieldResult,
            ModelResult, or ListResult instances.
    """
    self._fields = fields

Functions

__getattr__(name)

Get a metric result by field name.

Parameters:

Name Type Description Default
name str

The name of the field.

required

Returns:

Type Description
FieldResult | ModelResult | ListResult

The FieldResult or ModelResult instance.

Raises:

Type Description
AttributeError

If the field does not exist.

Source code in src/cobjectric/results.py
def __getattr__(self, name: str) -> FieldResult | ModelResult | ListResult:
    """
    Get a metric result by field name.

    Args:
        name: The name of the field.

    Returns:
        The FieldResult or ModelResult instance.

    Raises:
        AttributeError: If the field does not exist.
    """
    if name in self._fields:
        return self._fields[name]
    raise AttributeError(
        f"'{self.__class__.__name__}' object has no attribute '{name}'"
    )

__getitem__(path)

Get a fill rate result by path.

Parameters:

Name Type Description Default
path str

Path to the field (e.g., "name", "address.city", "items[0].name").

required

Returns:

Type Description
FieldResult | ModelResult | ListResult

The FieldResult or ModelResult instance.

Raises:

Type Description
KeyError

If the path is invalid.

Source code in src/cobjectric/results.py
def __getitem__(self, path: str) -> FieldResult | ModelResult | ListResult:
    """
    Get a fill rate result by path.

    Args:
        path: Path to the field (e.g., "name", "address.city", "items[0].name").

    Returns:
        The FieldResult or ModelResult instance.

    Raises:
        KeyError: If the path is invalid.
    """
    segments = parse_path(path)
    return self._resolve_path(segments)

__iter__()

Iterate over all metric results.

Source code in src/cobjectric/results.py
def __iter__(
    self,
) -> t.Iterator[FieldResult | ModelResult | ListResult]:
    """Iterate over all metric results."""
    return iter(self._fields.values())

__repr__()

Return a string representation of the FieldResultCollection.

Source code in src/cobjectric/results.py
def __repr__(self) -> str:
    """Return a string representation of the FieldResultCollection."""
    fields_repr = ", ".join(f"{name}=..." for name in self._fields.keys())
    return f"FieldResultCollection({fields_repr})"

ModelResult(_fields) dataclass

Bases: StatsMixin

Result of metric computation for a model instance.

Attributes:

Name Type Description
_fields dict[str, FieldResult | ModelResult | ListResult]

Dictionary mapping field names to FieldResult, ModelResult, or ListResult instances.

Attributes

fields property

Get the FieldResultCollection for this result.

Returns:

Type Description
FieldResultCollection

The FieldResultCollection containing all metric results.

Functions

__add__(other)

Combine two ModelResults into a collection.

Parameters:

Name Type Description Default
other 'ModelResult'

Another ModelResult to combine.

required

Returns:

Type Description
'ModelResultCollection'

ModelResultCollection containing both results.

Raises:

Type Description
IncompatibleModelResultError

If results come from different model types.

Source code in src/cobjectric/results.py
def __add__(self, other: "ModelResult") -> "ModelResultCollection":
    """
    Combine two ModelResults into a collection.

    Args:
        other: Another ModelResult to combine.

    Returns:
        ModelResultCollection containing both results.

    Raises:
        IncompatibleModelResultError: If results come from different model types.
    """
    from cobjectric.exceptions import IncompatibleModelResultError  # noqa: PLC0415

    # Check if both results come from the same model type
    # We can infer this by checking if they have the same field structure
    self_fields = set(self._fields.keys())
    other_fields = set(other._fields.keys())

    if self_fields != other_fields:
        # Try to get model types from the results if possible
        # For now, we'll use a generic error message
        raise IncompatibleModelResultError(type(self), type(other))

    return ModelResultCollection([self, other])

__getitem__(path)

Get a fill rate result by path.

Parameters:

Name Type Description Default
path str

Path to the field (e.g., "name", "address.city", "items[0].name").

required

Returns:

Type Description
FieldResult | ModelResult | ListResult

The FieldResult or ModelResult instance.

Raises:

Type Description
KeyError

If the path is invalid.

Source code in src/cobjectric/results.py
def __getitem__(self, path: str) -> FieldResult | ModelResult | ListResult:
    """
    Get a fill rate result by path.

    Args:
        path: Path to the field (e.g., "name", "address.city", "items[0].name").

    Returns:
        The FieldResult or ModelResult instance.

    Raises:
        KeyError: If the path is invalid.
    """
    return self.fields[path]

__repr__()

Return a string representation of the ModelResult.

Source code in src/cobjectric/results.py
def __repr__(self) -> str:
    """Return a string representation of the ModelResult."""
    fields_repr = ", ".join(
        f"{name}={field!r}" for name, field in self._fields.items()
    )
    return f"ModelResult({fields_repr})"

to_series()

Export to pandas Series (requires cobjectric[pandas]).

Returns:

Type Description
Any

pandas.Series with field paths as index and values as data.

Raises:

Type Description
ImportError

If pandas is not installed.

Source code in src/cobjectric/results.py
def to_series(self) -> t.Any:
    """
    Export to pandas Series (requires cobjectric[pandas]).

    Returns:
        pandas.Series with field paths as index and values as data.

    Raises:
        ImportError: If pandas is not installed.
    """
    from cobjectric.pandas_export import (  # noqa: PLC0415
        _flatten_to_dict,
        _get_pandas,
    )

    pd = _get_pandas()
    flattened = _flatten_to_dict(self)
    return pd.Series(flattened)

Similarity Results

See Similarity Guide for fuzzy matching and advanced strategies.

FieldResult(value, weight=1.0) dataclass

Result of metric computation for a single field.

Attributes:

Name Type Description
value float

The metric value (float between 0.0 and 1.0).

weight float

Weight for this field in weighted mean calculation (default: 1.0).

Functions

__repr__()

Return a string representation of the FieldResult.

Source code in src/cobjectric/results.py
def __repr__(self) -> str:
    """Return a string representation of the FieldResult."""
    return f"FieldResult(value={self.value}, weight={self.weight})"

FieldResultCollection(fields)

Collection of metric results for a model instance.

Provides attribute-based access to metric results.

Initialize a FieldResultCollection.

Parameters:

Name Type Description Default
fields dict[str, FieldResult | ModelResult | ListResult]

Dictionary mapping field names to FieldResult, ModelResult, or ListResult instances.

required
Source code in src/cobjectric/results.py
def __init__(
    self,
    fields: dict[
        str,
        FieldResult | ModelResult | ListResult,
    ],
) -> None:
    """
    Initialize a FieldResultCollection.

    Args:
        fields: Dictionary mapping field names to FieldResult,
            ModelResult, or ListResult instances.
    """
    self._fields = fields

Functions

__getattr__(name)

Get a metric result by field name.

Parameters:

Name Type Description Default
name str

The name of the field.

required

Returns:

Type Description
FieldResult | ModelResult | ListResult

The FieldResult or ModelResult instance.

Raises:

Type Description
AttributeError

If the field does not exist.

Source code in src/cobjectric/results.py
def __getattr__(self, name: str) -> FieldResult | ModelResult | ListResult:
    """
    Get a metric result by field name.

    Args:
        name: The name of the field.

    Returns:
        The FieldResult or ModelResult instance.

    Raises:
        AttributeError: If the field does not exist.
    """
    if name in self._fields:
        return self._fields[name]
    raise AttributeError(
        f"'{self.__class__.__name__}' object has no attribute '{name}'"
    )

__getitem__(path)

Get a fill rate result by path.

Parameters:

Name Type Description Default
path str

Path to the field (e.g., "name", "address.city", "items[0].name").

required

Returns:

Type Description
FieldResult | ModelResult | ListResult

The FieldResult or ModelResult instance.

Raises:

Type Description
KeyError

If the path is invalid.

Source code in src/cobjectric/results.py
def __getitem__(self, path: str) -> FieldResult | ModelResult | ListResult:
    """
    Get a fill rate result by path.

    Args:
        path: Path to the field (e.g., "name", "address.city", "items[0].name").

    Returns:
        The FieldResult or ModelResult instance.

    Raises:
        KeyError: If the path is invalid.
    """
    segments = parse_path(path)
    return self._resolve_path(segments)

__iter__()

Iterate over all metric results.

Source code in src/cobjectric/results.py
def __iter__(
    self,
) -> t.Iterator[FieldResult | ModelResult | ListResult]:
    """Iterate over all metric results."""
    return iter(self._fields.values())

__repr__()

Return a string representation of the FieldResultCollection.

Source code in src/cobjectric/results.py
def __repr__(self) -> str:
    """Return a string representation of the FieldResultCollection."""
    fields_repr = ", ".join(f"{name}=..." for name in self._fields.keys())
    return f"FieldResultCollection({fields_repr})"

ModelResult(_fields) dataclass

Bases: StatsMixin

Result of metric computation for a model instance.

Attributes:

Name Type Description
_fields dict[str, FieldResult | ModelResult | ListResult]

Dictionary mapping field names to FieldResult, ModelResult, or ListResult instances.

Attributes

fields property

Get the FieldResultCollection for this result.

Returns:

Type Description
FieldResultCollection

The FieldResultCollection containing all metric results.

Functions

__add__(other)

Combine two ModelResults into a collection.

Parameters:

Name Type Description Default
other 'ModelResult'

Another ModelResult to combine.

required

Returns:

Type Description
'ModelResultCollection'

ModelResultCollection containing both results.

Raises:

Type Description
IncompatibleModelResultError

If results come from different model types.

Source code in src/cobjectric/results.py
def __add__(self, other: "ModelResult") -> "ModelResultCollection":
    """
    Combine two ModelResults into a collection.

    Args:
        other: Another ModelResult to combine.

    Returns:
        ModelResultCollection containing both results.

    Raises:
        IncompatibleModelResultError: If results come from different model types.
    """
    from cobjectric.exceptions import IncompatibleModelResultError  # noqa: PLC0415

    # Check if both results come from the same model type
    # We can infer this by checking if they have the same field structure
    self_fields = set(self._fields.keys())
    other_fields = set(other._fields.keys())

    if self_fields != other_fields:
        # Try to get model types from the results if possible
        # For now, we'll use a generic error message
        raise IncompatibleModelResultError(type(self), type(other))

    return ModelResultCollection([self, other])

__getitem__(path)

Get a fill rate result by path.

Parameters:

Name Type Description Default
path str

Path to the field (e.g., "name", "address.city", "items[0].name").

required

Returns:

Type Description
FieldResult | ModelResult | ListResult

The FieldResult or ModelResult instance.

Raises:

Type Description
KeyError

If the path is invalid.

Source code in src/cobjectric/results.py
def __getitem__(self, path: str) -> FieldResult | ModelResult | ListResult:
    """
    Get a fill rate result by path.

    Args:
        path: Path to the field (e.g., "name", "address.city", "items[0].name").

    Returns:
        The FieldResult or ModelResult instance.

    Raises:
        KeyError: If the path is invalid.
    """
    return self.fields[path]

__repr__()

Return a string representation of the ModelResult.

Source code in src/cobjectric/results.py
def __repr__(self) -> str:
    """Return a string representation of the ModelResult."""
    fields_repr = ", ".join(
        f"{name}={field!r}" for name, field in self._fields.items()
    )
    return f"ModelResult({fields_repr})"

to_series()

Export to pandas Series (requires cobjectric[pandas]).

Returns:

Type Description
Any

pandas.Series with field paths as index and values as data.

Raises:

Type Description
ImportError

If pandas is not installed.

Source code in src/cobjectric/results.py
def to_series(self) -> t.Any:
    """
    Export to pandas Series (requires cobjectric[pandas]).

    Returns:
        pandas.Series with field paths as index and values as data.

    Raises:
        ImportError: If pandas is not installed.
    """
    from cobjectric.pandas_export import (  # noqa: PLC0415
        _flatten_to_dict,
        _get_pandas,
    )

    pd = _get_pandas()
    flattened = _flatten_to_dict(self)
    return pd.Series(flattened)

List Results

See List Comparison Strategies Guide for list handling and aggregation.

ListResult(_items, weight=1.0, _element_type=None) dataclass

Bases: StatsMixin

Result for a list[BaseModel] field.

Provides two access modes: - By index: items[0] -> ModelResult - Aggregated (required): items.aggregated_fields.name -> AggregatedFieldResult

Attributes

aggregated_fields property

Get aggregated fields collection for accessing fields across all items.

Returns:

Type Description
AggregatedFieldResultCollection

AggregatedFieldResultCollection instance.

value property

Get the mean fill rate across all items.

Returns:

Type Description
float

Mean fill rate.

Functions

__getitem__(index)

Get fill rate result for a specific item by index.

Parameters:

Name Type Description Default
index int

The item index.

required

Returns:

Type Description
ModelResult

ModelResult for the item.

Raises:

Type Description
IndexError

If index is out of range.

Source code in src/cobjectric/results.py
def __getitem__(self, index: int) -> ModelResult:
    """
    Get fill rate result for a specific item by index.

    Args:
        index: The item index.

    Returns:
        ModelResult for the item.

    Raises:
        IndexError: If index is out of range.
    """
    return self._items[index]

__iter__()

Iterate over all items.

Source code in src/cobjectric/results.py
def __iter__(self) -> t.Iterator[ModelResult]:
    """Iterate over all items."""
    return iter(self._items)

__len__()

Get the number of items.

Source code in src/cobjectric/results.py
def __len__(self) -> int:
    """Get the number of items."""
    return len(self._items)

__repr__()

Return a string representation.

Source code in src/cobjectric/results.py
def __repr__(self) -> str:
    """Return a string representation."""
    return f"ListResult(items={len(self._items)}, weight={self.weight})"

AggregatedFieldResult(_values, _weights) dataclass

Bases: StatsMixin

Aggregated fill rate result for a field across list items.

Provides statistical methods (mean, std, etc.) over all values of a specific field across multiple items in a list.

Attributes

values property

Get all fill rate values for this field across items.

Returns:

Type Description
list[float]

List of fill rate values.

Functions

__repr__()

Return a string representation.

Source code in src/cobjectric/results.py
def __repr__(self) -> str:
    """Return a string representation."""
    return f"AggregatedFieldResult(values={self._values})"

AggregatedFieldResultCollection(items)

Collection for aggregated field access on a list of fill rate results.

Provides access to aggregated field results across all items in the list.

Note

For nested lists (list[list[BaseModel]]), accessing a nested list field returns the mean fill rate of each list, not individual field access. Use indexed access to access nested list items individually.

Initialize the collection.

Parameters:

Name Type Description Default
items list[ModelResult]

List of ModelResult instances.

required
Source code in src/cobjectric/results.py
def __init__(self, items: list[ModelResult]) -> None:
    """
    Initialize the collection.

    Args:
        items: List of ModelResult instances.
    """
    self._items = items

Functions

__getattr__(name)

Get aggregated result for a field name across all items.

Parameters:

Name Type Description Default
name str

The field name.

required

Returns:

Type Description
AggregatedFieldResult | AggregatedModelResult | NestedListAggregatedResult

AggregatedFieldResult, AggregatedModelResult,

AggregatedFieldResult | AggregatedModelResult | NestedListAggregatedResult

or NestedListAggregatedResult.

Raises:

Type Description
InvalidAggregatedFieldError

If the field doesn't exist in the model.

Source code in src/cobjectric/results.py
def __getattr__(
    self, name: str
) -> AggregatedFieldResult | AggregatedModelResult | NestedListAggregatedResult:
    """
    Get aggregated result for a field name across all items.

    Args:
        name: The field name.

    Returns:
        AggregatedFieldResult, AggregatedModelResult,
        or NestedListAggregatedResult.

    Raises:
        InvalidAggregatedFieldError: If the field doesn't exist in the model.
    """
    # Validate field exists
    if self._items and name not in self._items[0]._fields:
        available = self._get_available_fields()
        raise InvalidAggregatedFieldError(name, available)

    values: list[float] = []
    weights: list[float] = []
    nested_items: list[ModelResult] = []
    nested_lists: list[ListResult] = []

    for item in self._items:
        if name in item._fields:
            field = item._fields[name]
            if isinstance(field, FieldResult):
                values.append(field.value)
                weights.append(field.weight)
            elif isinstance(field, ModelResult):
                nested_items.append(field)
            elif isinstance(field, ListResult):
                # Nested list - collect for NestedListAggregatedResult
                nested_lists.append(field)

    # If we have nested lists, return NestedListAggregatedResult
    if nested_lists:
        element_type = nested_lists[0]._element_type if nested_lists else None
        return NestedListAggregatedResult(nested_lists, element_type)

    if nested_items:
        return AggregatedModelResult(_items=nested_items)
    return AggregatedFieldResult(_values=values, _weights=weights)

__repr__()

Return a string representation with available fields.

Source code in src/cobjectric/results.py
def __repr__(self) -> str:
    """Return a string representation with available fields."""
    if not self._items:
        return "AggregatedFieldResultCollection()"
    # Get available fields from first item
    available_fields = list(self._items[0]._fields.keys())
    fields_str = ", ".join(f"{name}=..." for name in available_fields)
    return f"AggregatedFieldResultCollection({fields_str})"

AggregatedModelResult(_items) dataclass

Bases: StatsMixin

Aggregated result for a nested model field across list items.

Allows chained access: items.aggregated_fields.address.city

Note

For nested lists (list[list[BaseModel]]), accessing a nested list field returns the mean fill rate of each list, not individual field access. For example, if items have a tags field of type list[Tag], accessing items.aggregated_fields.tags returns a AggregatedFieldResult with the mean fill rate of each tags list, not access to individual tag fields.

Functions

__getattr__(name)

Get aggregated result for a field name across items.

Parameters:

Name Type Description Default
name str

The field name.

required

Returns:

Type Description
AggregatedFieldResult | AggregatedModelResult | NestedListAggregatedResult

AggregatedFieldResult, AggregatedModelResult,

AggregatedFieldResult | AggregatedModelResult | NestedListAggregatedResult

or NestedListAggregatedResult.

Raises:

Type Description
InvalidAggregatedFieldError

If the field doesn't exist in the model.

Source code in src/cobjectric/results.py
def __getattr__(
    self, name: str
) -> AggregatedFieldResult | AggregatedModelResult | NestedListAggregatedResult:
    """
    Get aggregated result for a field name across items.

    Args:
        name: The field name.

    Returns:
        AggregatedFieldResult, AggregatedModelResult,
        or NestedListAggregatedResult.

    Raises:
        InvalidAggregatedFieldError: If the field doesn't exist in the model.
    """
    # Validate field exists
    if self._items and name not in self._items[0]._fields:
        available = list(self._items[0]._fields.keys())
        raise InvalidAggregatedFieldError(name, available)

    values: list[float] = []
    weights: list[float] = []
    nested_items: list[ModelResult] = []
    nested_lists: list[ListResult] = []

    for item in self._items:
        if name in item._fields:
            field = item._fields[name]
            if isinstance(field, FieldResult):
                values.append(field.value)
                weights.append(field.weight)
            elif isinstance(field, ModelResult):
                nested_items.append(field)
            elif isinstance(field, ListResult):
                # Nested list - collect for NestedListAggregatedResult
                nested_lists.append(field)

    # If we have nested lists, return NestedListAggregatedResult
    if nested_lists:
        element_type = nested_lists[0]._element_type if nested_lists else None
        return NestedListAggregatedResult(nested_lists, element_type)

    if nested_items:
        return AggregatedModelResult(_items=nested_items)
    return AggregatedFieldResult(_values=values, _weights=weights)

__repr__()

Return a string representation.

Source code in src/cobjectric/results.py
def __repr__(self) -> str:
    """Return a string representation."""
    return f"AggregatedModelResult(items={len(self._items)})"

NestedListAggregatedResult(lists, element_type=None)

Aggregated result for nested lists in fill rate results.

When accessing a list field through aggregated_fields, this allows chaining to further aggregate nested lists and access their fields.

Initialize NestedListAggregatedResult.

Parameters:

Name Type Description Default
lists list[ListResult]

List of ListResult instances.

required
element_type type | None

The element type of the list (optional).

None
Source code in src/cobjectric/results.py
def __init__(
    self, lists: list[ListResult], element_type: type | None = None
) -> None:
    """
    Initialize NestedListAggregatedResult.

    Args:
        lists: List of ListResult instances.
        element_type: The element type of the list (optional).
    """
    self._lists = lists
    self._element_type = element_type

Attributes

aggregated_fields property

Get aggregated fields across all nested lists.

Flattens the nested lists and returns a collection for accessing fields across all items.

Returns:

Type Description
AggregatedFieldResultCollection

AggregatedFieldResultCollection instance.

values property

Get fill rate values for nested lists.

By default, returns the mean fill rate of each list (one value per list). This is the hierarchical view. To get flattened values, use NestedListAggregatedResult.aggregated_fields to access individual items and their fields.

Returns:

Type Description
list[float]

List of mean fill rates (one per list).

Functions

__repr__()

Return a string representation.

Source code in src/cobjectric/results.py
def __repr__(self) -> str:
    """Return a string representation."""
    return f"NestedListAggregatedResult(lists={len(self._lists)})"

max(hierarchical=False)

Get maximum fill rate.

Parameters:

Name Type Description Default
hierarchical bool

If False (default), returns max of flattened values. If True, returns max of means for each list.

False

Returns:

Type Description
float

Maximum fill rate.

Source code in src/cobjectric/results.py
def max(self, hierarchical: bool = False) -> float:
    """
    Get maximum fill rate.

    Args:
        hierarchical: If False (default), returns max of flattened values.
            If True, returns max of means for each list.

    Returns:
        Maximum fill rate.
    """
    if not self._lists:
        return 0.0

    if hierarchical:
        means = [lst.mean() for lst in self._lists]
        return max(means) if means else 0.0

    values = self.values
    return max(values) if values else 0.0

mean(hierarchical=False)

Calculate mean fill rate across nested lists.

Parameters:

Name Type Description Default
hierarchical bool

If False (default), flattens all values and calculates mean. If True, calculates mean of means for each list.

False

Returns:

Type Description
float

Mean fill rate.

Source code in src/cobjectric/results.py
def mean(self, hierarchical: bool = False) -> float:
    """
    Calculate mean fill rate across nested lists.

    Args:
        hierarchical: If False (default), flattens all values and calculates
            mean. If True, calculates mean of means for each list.

    Returns:
        Mean fill rate.
    """
    if not self._lists:
        return 0.0

    if hierarchical:
        # Mean of means: calculate mean for each list, then mean of those
        means = [lst.mean() for lst in self._lists]
        return sum(means) / len(means) if means else 0.0

    # Flatten: collect all values and calculate mean
    all_values, all_weights = self._collect_all_values_and_weights()
    if not all_values:
        return 0.0
    total_weight = sum(all_weights)
    if total_weight == 0.0:
        return 0.0
    return (
        sum(v * w for v, w in zip(all_values, all_weights, strict=True))
        / total_weight
    )

min(hierarchical=False)

Get minimum fill rate.

Parameters:

Name Type Description Default
hierarchical bool

If False (default), returns min of flattened values. If True, returns min of means for each list.

False

Returns:

Type Description
float

Minimum fill rate.

Source code in src/cobjectric/results.py
def min(self, hierarchical: bool = False) -> float:
    """
    Get minimum fill rate.

    Args:
        hierarchical: If False (default), returns min of flattened values.
            If True, returns min of means for each list.

    Returns:
        Minimum fill rate.
    """
    if not self._lists:
        return 0.0

    if hierarchical:
        means = [lst.mean() for lst in self._lists]
        return min(means) if means else 0.0

    values = self.values
    return min(values) if values else 0.0

quantile(q, hierarchical=False)

Calculate quantile of fill rates.

Parameters:

Name Type Description Default
q float

The quantile to compute (float between 0.0 and 1.0).

required
hierarchical bool

If False (default), calculates quantile of flattened values. If True, calculates quantile of means for each list.

False

Returns:

Type Description
float

The quantile value.

Raises:

Type Description
ValueError

If q is not in [0, 1].

Source code in src/cobjectric/results.py
def quantile(self, q: float, hierarchical: bool = False) -> float:
    """
    Calculate quantile of fill rates.

    Args:
        q: The quantile to compute (float between 0.0 and 1.0).
        hierarchical: If False (default), calculates quantile of flattened values.
            If True, calculates quantile of means for each list.

    Returns:
        The quantile value.

    Raises:
        ValueError: If q is not in [0, 1].
    """
    if not 0.0 <= q <= 1.0:
        raise ValueError(f"Quantile q must be between 0.0 and 1.0, got {q}")

    if not self._lists:
        return 0.0

    if hierarchical:
        means = [lst.mean() for lst in self._lists]
        values = sorted(means)
    else:
        values = sorted(self.values)

    assert len(values) > 0  # because list is not empty

    if q == 0.0:
        return values[0]
    if q == 1.0:
        return values[-1]

    n = len(values)
    index = q * (n - 1)
    lower_index = int(index)
    upper_index = min(lower_index + 1, n - 1)
    weight = index - lower_index

    return values[lower_index] * (1 - weight) + values[upper_index] * weight

std(hierarchical=False)

Calculate standard deviation across nested lists.

Parameters:

Name Type Description Default
hierarchical bool

If False (default), calculates std of flattened values. If True, calculates std of means for each list.

False

Returns:

Type Description
float

Standard deviation.

Source code in src/cobjectric/results.py
def std(self, hierarchical: bool = False) -> float:
    """
    Calculate standard deviation across nested lists.

    Args:
        hierarchical: If False (default), calculates std of flattened values.
            If True, calculates std of means for each list.

    Returns:
        Standard deviation.
    """
    if len(self._lists) <= 1:
        return 0.0

    if hierarchical:
        # Std of means
        means = [lst.mean() for lst in self._lists]
        m = self.mean(hierarchical=True)
        return (sum((x - m) ** 2 for x in means) / len(means)) ** 0.5

    # Std of flattened values
    values = self.values
    assert len(values) > 1  # because list is not empty
    m = self.mean(hierarchical=False)
    return (sum((x - m) ** 2 for x in values) / len(values)) ** 0.5

var(hierarchical=False)

Calculate variance across nested lists.

Parameters:

Name Type Description Default
hierarchical bool

If False (default), calculates variance of flattened values. If True, calculates variance of means for each list.

False

Returns:

Type Description
float

Variance.

Source code in src/cobjectric/results.py
def var(self, hierarchical: bool = False) -> float:
    """
    Calculate variance across nested lists.

    Args:
        hierarchical: If False (default), calculates variance of flattened values.
            If True, calculates variance of means for each list.

    Returns:
        Variance.
    """
    if len(self._lists) <= 1:
        return 0.0

    if hierarchical:
        # Var of means
        means = [lst.mean() for lst in self._lists]
        m = self.mean(hierarchical=True)
        return sum((x - m) ** 2 for x in means) / len(means)

    # Var of flattened values
    values = self.values
    assert len(values) > 1  # because list is not empty
    m = self.mean(hierarchical=False)
    return sum((x - m) ** 2 for x in values) / len(values)

Result Collections

See Pandas Export Guide for exporting results to pandas Series and DataFrames.

ModelResultCollection(results)

Collection of ModelResult for aggregated statistics.

Created by adding ModelResults together: result1 + result2 Provides methods to aggregate results and export to pandas DataFrame.

Initialize a ModelResultCollection.

Parameters:

Name Type Description Default
results list[ModelResult]

List of ModelResult instances (must be from same model type).

required
Source code in src/cobjectric/results.py
def __init__(self, results: list[ModelResult]) -> None:
    """
    Initialize a ModelResultCollection.

    Args:
        results: List of ModelResult instances (must be from same model type).
    """
    self._results = results
    self._model_type: type | None = None

Functions

__add__(other)

Add a ModelResult or merge another collection.

Parameters:

Name Type Description Default
other ModelResult | 'ModelResultCollection'

ModelResult or ModelResultCollection to add.

required

Returns:

Type Description
'ModelResultCollection'

New ModelResultCollection with combined results.

Raises:

Type Description
IncompatibleModelResultError

If results come from different model types.

Source code in src/cobjectric/results.py
def __add__(
    self, other: ModelResult | "ModelResultCollection"
) -> "ModelResultCollection":
    """
    Add a ModelResult or merge another collection.

    Args:
        other: ModelResult or ModelResultCollection to add.

    Returns:
        New ModelResultCollection with combined results.

    Raises:
        IncompatibleModelResultError: If results come from different model types.
    """
    from cobjectric.exceptions import IncompatibleModelResultError  # noqa: PLC0415

    if isinstance(other, ModelResult):
        # Validate compatibility
        if self._results:
            self_fields = set(self._results[0]._fields.keys())
            other_fields = set(other._fields.keys())
            if self_fields != other_fields:
                raise IncompatibleModelResultError(
                    type(self._results[0]), type(other)
                )
        return ModelResultCollection(self._results + [other])
    elif isinstance(other, ModelResultCollection):
        # Merge two collections
        if self._results and other._results:
            self_fields = set(self._results[0]._fields.keys())
            other_fields = set(other._results[0]._fields.keys())
            if self_fields != other_fields:
                raise IncompatibleModelResultError(
                    type(self._results[0]), type(other._results[0])
                )
        return ModelResultCollection(self._results + other._results)
    else:
        raise TypeError(
            f"Cannot add {type(other)} to ModelResultCollection. "
            "Only ModelResult and ModelResultCollection are supported."
        )

__len__()

Get the number of results in the collection.

Source code in src/cobjectric/results.py
def __len__(self) -> int:
    """Get the number of results in the collection."""
    return len(self._results)

__repr__()

Return a string representation.

Source code in src/cobjectric/results.py
def __repr__(self) -> str:
    """Return a string representation."""
    return f"ModelResultCollection(results={len(self._results)})"

max()

Get maximum value for each field across all results.

Returns:

Type Description
dict[str, float]

Dictionary mapping field paths to maximum values.

Source code in src/cobjectric/results.py
def max(self) -> dict[str, float]:
    """
    Get maximum value for each field across all results.

    Returns:
        Dictionary mapping field paths to maximum values.
    """
    if not self._results:
        return {}

    from cobjectric.pandas_export import _flatten_to_dict  # noqa: PLC0415

    first_flattened = _flatten_to_dict(self._results[0])
    field_paths = list(first_flattened.keys())

    maxs: dict[str, float] = {}
    for path in field_paths:
        values = []
        for result in self._results:
            flattened = _flatten_to_dict(result)
            if path in flattened:
                values.append(flattened[path])
        if values:
            maxs[path] = max(values)

    return maxs

mean()

Calculate mean value for each field across all results.

Returns:

Type Description
dict[str, float]

Dictionary mapping field paths to mean values.

Source code in src/cobjectric/results.py
def mean(self) -> dict[str, float]:
    """
    Calculate mean value for each field across all results.

    Returns:
        Dictionary mapping field paths to mean values.
    """
    if not self._results:
        return {}

    # Get all field paths from first result
    from cobjectric.pandas_export import _flatten_to_dict  # noqa: PLC0415

    first_flattened = _flatten_to_dict(self._results[0])
    field_paths = list(first_flattened.keys())

    # Calculate mean for each field
    means: dict[str, float] = {}
    for path in field_paths:
        values = []
        for result in self._results:
            flattened = _flatten_to_dict(result)
            if path in flattened:
                values.append(flattened[path])
        if values:
            means[path] = sum(values) / len(values)

    return means

min()

Get minimum value for each field across all results.

Returns:

Type Description
dict[str, float]

Dictionary mapping field paths to minimum values.

Source code in src/cobjectric/results.py
def min(self) -> dict[str, float]:
    """
    Get minimum value for each field across all results.

    Returns:
        Dictionary mapping field paths to minimum values.
    """
    if not self._results:
        return {}

    from cobjectric.pandas_export import _flatten_to_dict  # noqa: PLC0415

    first_flattened = _flatten_to_dict(self._results[0])
    field_paths = list(first_flattened.keys())

    mins: dict[str, float] = {}
    for path in field_paths:
        values = []
        for result in self._results:
            flattened = _flatten_to_dict(result)
            if path in flattened:
                values.append(flattened[path])
        if values:
            mins[path] = min(values)

    return mins

quantile(q)

Calculate quantile for each field across all results.

Parameters:

Name Type Description Default
q float

The quantile to compute (float between 0.0 and 1.0).

required

Returns:

Type Description
dict[str, float]

Dictionary mapping field paths to quantile values.

Raises:

Type Description
ValueError

If q is not in [0, 1].

Source code in src/cobjectric/results.py
def quantile(self, q: float) -> dict[str, float]:
    """
    Calculate quantile for each field across all results.

    Args:
        q: The quantile to compute (float between 0.0 and 1.0).

    Returns:
        Dictionary mapping field paths to quantile values.

    Raises:
        ValueError: If q is not in [0, 1].
    """
    if not 0.0 <= q <= 1.0:
        raise ValueError(f"Quantile q must be between 0.0 and 1.0, got {q}")

    if not self._results:
        return {}

    from cobjectric.pandas_export import _flatten_to_dict  # noqa: PLC0415

    first_flattened = _flatten_to_dict(self._results[0])
    field_paths = list(first_flattened.keys())

    quantiles: dict[str, float] = {}
    for path in field_paths:
        values = []
        for result in self._results:
            flattened = _flatten_to_dict(result)
            if path in flattened:
                values.append(flattened[path])

        if not values:
            continue

        sorted_values = sorted(values)
        n = len(sorted_values)

        if q == 0.0:
            quantiles[path] = sorted_values[0]
        elif q == 1.0:
            quantiles[path] = sorted_values[-1]
        else:
            index = q * (n - 1)
            lower_index = int(index)
            upper_index = min(lower_index + 1, n - 1)
            weight = index - lower_index
            quantiles[path] = (
                sorted_values[lower_index] * (1 - weight)
                + sorted_values[upper_index] * weight
            )

    return quantiles

std()

Calculate standard deviation for each field across all results.

Returns:

Type Description
dict[str, float]

Dictionary mapping field paths to standard deviation values.

Source code in src/cobjectric/results.py
def std(self) -> dict[str, float]:
    """
    Calculate standard deviation for each field across all results.

    Returns:
        Dictionary mapping field paths to standard deviation values.
    """
    if not self._results:
        return {}

    from cobjectric.pandas_export import _flatten_to_dict  # noqa: PLC0415

    first_flattened = _flatten_to_dict(self._results[0])
    field_paths = list(first_flattened.keys())

    stds: dict[str, float] = {}
    for path in field_paths:
        values = []
        for result in self._results:
            flattened = _flatten_to_dict(result)
            if path in flattened:
                values.append(flattened[path])
        if len(values) <= 1:
            stds[path] = 0.0
        else:
            mean_val = sum(values) / len(values)
            variance = sum((x - mean_val) ** 2 for x in values) / len(values)
            stds[path] = variance**0.5

    return stds

to_dataframe()

Export to pandas DataFrame (requires cobjectric[pandas]).

Each row represents one ModelResult, columns are field paths.

Returns:

Type Description
Any

pandas.DataFrame with one row per ModelResult.

Raises:

Type Description
ImportError

If pandas is not installed.

Source code in src/cobjectric/results.py
def to_dataframe(self) -> t.Any:
    """
    Export to pandas DataFrame (requires cobjectric[pandas]).

    Each row represents one ModelResult, columns are field paths.

    Returns:
        pandas.DataFrame with one row per ModelResult.

    Raises:
        ImportError: If pandas is not installed.
    """
    from cobjectric.pandas_export import (  # noqa: PLC0415
        _flatten_to_dict,
        _get_pandas,
    )

    pd = _get_pandas()

    # Flatten each result
    rows: list[dict[str, float]] = []
    for result in self._results:
        flattened = _flatten_to_dict(result)
        rows.append(flattened)

    # Create DataFrame
    return pd.DataFrame(rows)

var()

Calculate variance for each field across all results.

Returns:

Type Description
dict[str, float]

Dictionary mapping field paths to variance values.

Source code in src/cobjectric/results.py
def var(self) -> dict[str, float]:
    """
    Calculate variance for each field across all results.

    Returns:
        Dictionary mapping field paths to variance values.
    """
    if not self._results:
        return {}

    from cobjectric.pandas_export import _flatten_to_dict  # noqa: PLC0415

    first_flattened = _flatten_to_dict(self._results[0])
    field_paths = list(first_flattened.keys())

    vars_dict: dict[str, float] = {}
    for path in field_paths:
        values = []
        for result in self._results:
            flattened = _flatten_to_dict(result)
            if path in flattened:
                values.append(flattened[path])
        if len(values) <= 1:
            vars_dict[path] = 0.0
        else:
            mean_val = sum(values) / len(values)
            vars_dict[path] = sum((x - mean_val) ** 2 for x in values) / len(values)

    return vars_dict

Decorator Info Classes

FillRateFuncInfo(field_patterns, func, weight=1.0) dataclass

Stores fill_rate_func info attached to a method.

Attributes:

Name Type Description
field_patterns tuple[str, ...]

Tuple of field names or glob patterns to match.

func FillRateFunc

The fill_rate_func to apply.

weight float

Weight for fill rate computation (default: 1.0, must be >= 0.0).

FillRateAccuracyFuncInfo(field_patterns, func, weight=1.0) dataclass

Stores fill_rate_accuracy_func info attached to a method.

Attributes:

Name Type Description
field_patterns tuple[str, ...]

Tuple of field names or glob patterns to match.

func FillRateAccuracyFunc

The fill_rate_accuracy_func to apply.

weight float

Weight for fill rate accuracy computation (default: 1.0, must be >= 0.0).

SimilarityFuncInfo(field_patterns, func, weight=1.0) dataclass

Stores similarity_func info attached to a method.

Attributes:

Name Type Description
field_patterns tuple[str, ...]

Tuple of field names or glob patterns to match.

func SimilarityFunc

The similarity_func to apply.

weight float

Weight for similarity computation (default: 1.0, must be >= 0.0).

List Comparison Strategies

ListCompareStrategy

Bases: str, Enum

Strategy for comparing list[BaseModel] items.

Attributes:

Name Type Description
PAIRWISE

Compare items by their index (default).

LEVENSHTEIN

Align items based on Levenshtein distance + similarity.

OPTIMAL_ASSIGNMENT

Find optimal one-to-one mapping using Hungarian algorithm.

Similarity Functions

See Similarity Guide for implementation details and best practices.

exact_similarity(a, b)

Exact equality similarity.

Returns 1.0 if a == b, else 0.0. Works with any type (str, int, float, bool, etc.)

Parameters:

Name Type Description Default
a Any

First value to compare.

required
b Any

Second value to compare.

required

Returns:

Name Type Description
float float

1.0 if values are equal, 0.0 otherwise.

Examples:

>>> exact_similarity("John", "John")
1.0
>>> exact_similarity("John", "Jane")
0.0
>>> exact_similarity(10, 10)
1.0
>>> exact_similarity(10, 11)
0.0
Source code in src/cobjectric/similarity.py
def exact_similarity(a: t.Any, b: t.Any) -> float:
    """
    Exact equality similarity.

    Returns 1.0 if a == b, else 0.0.
    Works with any type (str, int, float, bool, etc.)

    Args:
        a: First value to compare.
        b: Second value to compare.

    Returns:
        float: 1.0 if values are equal, 0.0 otherwise.

    Examples:
        >>> exact_similarity("John", "John")
        1.0
        >>> exact_similarity("John", "Jane")
        0.0
        >>> exact_similarity(10, 10)
        1.0
        >>> exact_similarity(10, 11)
        0.0
    """
    return 1.0 if a == b else 0.0

fuzzy_similarity_factory(scorer='ratio')

Factory to create fuzzy string similarity using rapidfuzz.

Parameters:

Name Type Description Default
scorer str

The rapidfuzz.fuzz scorer to use. Options: - "ratio" (default): Standard Levenshtein ratio - "partial_ratio": Best partial match ratio - "token_sort_ratio": Token sorted ratio - "token_set_ratio": Token set ratio - "WRatio": Weighted ratio (smart combination) - "QRatio": Quick ratio

'ratio'

Returns:

Type Description
SimilarityFunc

A similarity function that compares two string values.

Examples:

>>> fuzzy = fuzzy_similarity_factory()
>>> fuzzy("John Doe", "John Doe")
1.0
>>> fuzzy("John Doe", "john doe")  # case difference
0.9...
>>> fuzzy("John Doe", "Jane Doe")
0.75...
Source code in src/cobjectric/similarity.py
def fuzzy_similarity_factory(
    scorer: str = "ratio",
) -> SimilarityFunc:
    """
    Factory to create fuzzy string similarity using rapidfuzz.

    Args:
        scorer: The rapidfuzz.fuzz scorer to use. Options:
            - "ratio" (default): Standard Levenshtein ratio
            - "partial_ratio": Best partial match ratio
            - "token_sort_ratio": Token sorted ratio
            - "token_set_ratio": Token set ratio
            - "WRatio": Weighted ratio (smart combination)
            - "QRatio": Quick ratio

    Returns:
        A similarity function that compares two string values.

    Examples:
        >>> fuzzy = fuzzy_similarity_factory()
        >>> fuzzy("John Doe", "John Doe")
        1.0
        >>> fuzzy("John Doe", "john doe")  # case difference
        0.9...
        >>> fuzzy("John Doe", "Jane Doe")
        0.75...
    """
    scorer_func = getattr(fuzz, scorer)

    def fuzzy_similarity(a: t.Any, b: t.Any) -> float:
        if a is None or b is None:
            return 0.0
        return scorer_func(str(a), str(b)) / 100.0

    return fuzzy_similarity

numeric_similarity_factory(max_difference=None)

Factory for numeric similarity based on difference.

Parameters:

Name Type Description Default
max_difference float | None

Maximum absolute difference for comparison. - None (default): Exact match only (1.0 if a == b, 0.0 otherwise) - float > 0: Gradual similarity based on difference Formula: max(0.0, 1.0 - |a - b| / max_difference)

None

Returns:

Type Description
SimilarityFunc

A similarity function that compares two numeric values.

Examples:

>>> # Exact match required
>>> exact = numeric_similarity_factory()
>>> exact(10, 10)
1.0
>>> exact(10, 11)
0.0
>>>
>>> # Gradual decrease: up to 5 units of difference
>>> gradual = numeric_similarity_factory(max_difference=5.0)
>>> gradual(10, 10)
1.0
>>> gradual(10, 12)  # diff=2, 2/5=0.4, 1-0.4=0.6
0.6
>>> gradual(10, 15)  # diff=5, 5/5=1.0, 1-1.0=0.0
0.0
>>> gradual(10, 20)  # diff>max, capped at 0
0.0

Raises:

Type Description
ValueError

If max_difference is <= 0.

Source code in src/cobjectric/similarity.py
def numeric_similarity_factory(
    max_difference: float | None = None,
) -> SimilarityFunc:
    """
    Factory for numeric similarity based on difference.

    Args:
        max_difference: Maximum absolute difference for comparison.
            - None (default): Exact match only (1.0 if a == b, 0.0 otherwise)
            - float > 0: Gradual similarity based on difference
              Formula: max(0.0, 1.0 - |a - b| / max_difference)

    Returns:
        A similarity function that compares two numeric values.

    Examples:
        >>> # Exact match required
        >>> exact = numeric_similarity_factory()
        >>> exact(10, 10)
        1.0
        >>> exact(10, 11)
        0.0
        >>>
        >>> # Gradual decrease: up to 5 units of difference
        >>> gradual = numeric_similarity_factory(max_difference=5.0)
        >>> gradual(10, 10)
        1.0
        >>> gradual(10, 12)  # diff=2, 2/5=0.4, 1-0.4=0.6
        0.6
        >>> gradual(10, 15)  # diff=5, 5/5=1.0, 1-1.0=0.0
        0.0
        >>> gradual(10, 20)  # diff>max, capped at 0
        0.0

    Raises:
        ValueError: If max_difference is <= 0.
    """
    if max_difference is not None and max_difference <= 0:
        raise ValueError("max_difference must be > 0")

    def numeric_similarity(a: t.Any, b: t.Any) -> float:
        if a is None or b is None:
            return 0.0

        try:
            a_num = float(a)
            b_num = float(b)
        except (ValueError, TypeError):
            return 0.0

        if max_difference is None:
            return 1.0 if a_num == b_num else 0.0

        diff = abs(a_num - b_num)
        return max(0.0, 1.0 - diff / max_difference)

    return numeric_similarity

datetime_similarity_factory(max_difference=None)

Factory for datetime similarity based on time difference.

Parameters:

Name Type Description Default
max_difference timedelta | None

Maximum time difference as timedelta for comparison. - None (default): Exact match only (1.0 if a == b, 0.0 otherwise) - timedelta > 0: Gradual similarity based on time difference Formula: max(0.0, 1.0 - |time_diff| / max_difference)

None

Returns:

Type Description
SimilarityFunc

A similarity function that compares two datetime string values (ISO format).

Examples:

>>> from datetime import timedelta
>>> # Exact match required
>>> exact = datetime_similarity_factory()
>>> exact("2024-01-15T10:30:00Z", "2024-01-15T10:30:00Z")
1.0
>>> exact("2024-01-15T10:30:00Z", "2024-01-15T10:30:01Z")
0.0
>>>
>>> # Gradual decrease: up to 1 hour of difference
>>> gradual = datetime_similarity_factory(max_difference=timedelta(hours=1))
>>> gradual("2024-01-15T10:00:00Z", "2024-01-15T10:00:00Z")
1.0
>>> gradual("2024-01-15T10:00:00Z", "2024-01-15T10:30:00Z")  # 30 min
... # diff=30min, 30min/60min=0.5, 1-0.5=0.5
0.5
>>> gradual("2024-01-15T10:00:00Z", "2024-01-15T11:00:00Z")  # 1 hour
... # diff=1h, 1h/1h=1.0, 1-1.0=0.0
0.0

Raises:

Type Description
ValueError

If max_difference is <= 0.

Source code in src/cobjectric/similarity.py
def datetime_similarity_factory(
    max_difference: timedelta | None = None,
) -> SimilarityFunc:
    """
    Factory for datetime similarity based on time difference.

    Args:
        max_difference: Maximum time difference as timedelta for comparison.
            - None (default): Exact match only (1.0 if a == b, 0.0 otherwise)
            - timedelta > 0: Gradual similarity based on time difference
              Formula: max(0.0, 1.0 - |time_diff| / max_difference)

    Returns:
        A similarity function that compares two datetime string values (ISO format).

    Examples:
        >>> from datetime import timedelta
        >>> # Exact match required
        >>> exact = datetime_similarity_factory()
        >>> exact("2024-01-15T10:30:00Z", "2024-01-15T10:30:00Z")
        1.0
        >>> exact("2024-01-15T10:30:00Z", "2024-01-15T10:30:01Z")
        0.0
        >>>
        >>> # Gradual decrease: up to 1 hour of difference
        >>> gradual = datetime_similarity_factory(max_difference=timedelta(hours=1))
        >>> gradual("2024-01-15T10:00:00Z", "2024-01-15T10:00:00Z")
        1.0
        >>> gradual("2024-01-15T10:00:00Z", "2024-01-15T10:30:00Z")  # 30 min
        ... # diff=30min, 30min/60min=0.5, 1-0.5=0.5
        0.5
        >>> gradual("2024-01-15T10:00:00Z", "2024-01-15T11:00:00Z")  # 1 hour
        ... # diff=1h, 1h/1h=1.0, 1-1.0=0.0
        0.0

    Raises:
        ValueError: If max_difference is <= 0.
    """
    if max_difference is not None and max_difference.total_seconds() <= 0:
        raise ValueError("max_difference must be > 0")

    def parse_datetime(value: t.Any) -> datetime | None:
        """Parse datetime from string, trying common ISO formats."""
        assert value is not None  # Already handled by datetime_similarity
        if isinstance(value, datetime):
            return value

        if not isinstance(value, str):
            return None

        # Try common ISO formats
        formats = [
            "%Y-%m-%dT%H:%M:%S",
            "%Y-%m-%dT%H:%M:%S",
            "%Y-%m-%dT%H:%M:%SZ",
            "%Y-%m-%dT%H:%M:%S%z",
            "%Y-%m-%d %H:%M:%S",
            "%Y-%m-%d",
        ]

        for fmt in formats:
            try:
                return datetime.strptime(value, fmt)
            except ValueError:
                continue

        return None

    def datetime_similarity(a: t.Any, b: t.Any) -> float:
        if a is None or b is None:
            return 0.0

        dt_a = parse_datetime(a)
        dt_b = parse_datetime(b)

        if dt_a is None or dt_b is None:
            return 0.0

        if max_difference is None:
            return 1.0 if dt_a == dt_b else 0.0

        diff = abs(dt_a - dt_b)
        max_diff_seconds = max_difference.total_seconds()
        diff_seconds = diff.total_seconds()
        return max(0.0, 1.0 - diff_seconds / max_diff_seconds)

    return datetime_similarity

Pre-defined Specs

See Pre-defined Specs Guide for detailed usage and recommendations.

KeywordSpec

KeywordSpec(strip=True, convert_int_to_str=True, metadata=None, fill_rate_func=None, fill_rate_weight=1.0, fill_rate_accuracy_func=None, fill_rate_accuracy_weight=1.0, similarity_func=None, similarity_weight=1.0, list_compare_strategy=None)

Pre-defined Spec for keyword/identifier fields (exact matching).

Optimized for identifiers, codes, enums, etc. Uses exact similarity and optional string stripping and int-to-string conversion.

Parameters:

Name Type Description Default
strip bool

If True (default), strip leading/trailing whitespace.

True
convert_int_to_str bool

If True (default), convert int values to string. Useful when IDs come as integers from JSON but should be compared as strings.

True
metadata dict[str, Any] | None

Optional metadata for the field.

None
fill_rate_func Any

Optional fill rate function.

None
fill_rate_weight float

Weight for fill rate computation (default: 1.0).

1.0
fill_rate_accuracy_func Any

Optional fill rate accuracy function.

None
fill_rate_accuracy_weight float

Weight for fill rate accuracy (default: 1.0).

1.0
similarity_func Any

Optional similarity function (default: exact_similarity).

None
similarity_weight float

Weight for similarity computation (default: 1.0).

1.0
list_compare_strategy Any

Strategy for comparing list[BaseModel] items.

None

Returns:

Type Description
Any

FieldSpec instance optimized for keyword fields.

Example
class Person(BaseModel):
    id: str = KeywordSpec()  # Converts 123 -> "123"
Source code in src/cobjectric/specs.py
def KeywordSpec(  # noqa: N802
    strip: bool = True,
    convert_int_to_str: bool = True,
    metadata: dict[str, t.Any] | None = None,
    fill_rate_func: t.Any = None,
    fill_rate_weight: float = 1.0,
    fill_rate_accuracy_func: t.Any = None,
    fill_rate_accuracy_weight: float = 1.0,
    similarity_func: t.Any = None,
    similarity_weight: float = 1.0,
    list_compare_strategy: t.Any = None,
) -> t.Any:
    """
    Pre-defined Spec for keyword/identifier fields (exact matching).

    Optimized for identifiers, codes, enums, etc. Uses exact similarity
    and optional string stripping and int-to-string conversion.

    Args:
        strip: If True (default), strip leading/trailing whitespace.
        convert_int_to_str: If True (default), convert int values to string.
            Useful when IDs come as integers from JSON but should be
            compared as strings.
        metadata: Optional metadata for the field.
        fill_rate_func: Optional fill rate function.
        fill_rate_weight: Weight for fill rate computation (default: 1.0).
        fill_rate_accuracy_func: Optional fill rate accuracy function.
        fill_rate_accuracy_weight: Weight for fill rate accuracy (default: 1.0).
        similarity_func: Optional similarity function (default: exact_similarity).
        similarity_weight: Weight for similarity computation (default: 1.0).
        list_compare_strategy: Strategy for comparing list[BaseModel] items.

    Returns:
        FieldSpec instance optimized for keyword fields.

    Example:
        ```python
        class Person(BaseModel):
            id: str = KeywordSpec()  # Converts 123 -> "123"
        ```
    """
    normalizer = None
    if strip or convert_int_to_str:

        def keyword_normalizer(value: t.Any) -> t.Any:
            # Convert int to string if enabled
            if convert_int_to_str and isinstance(value, int):
                value = str(value)
            # Strip whitespace if enabled
            if strip and isinstance(value, str):
                return value.strip()
            return value

        normalizer = keyword_normalizer

    return Spec(
        metadata=metadata,
        normalizer=normalizer,
        fill_rate_func=fill_rate_func,
        fill_rate_weight=fill_rate_weight,
        fill_rate_accuracy_func=fill_rate_accuracy_func,
        fill_rate_accuracy_weight=fill_rate_accuracy_weight,
        similarity_func=(
            similarity_func if similarity_func is not None else exact_similarity
        ),
        similarity_weight=similarity_weight,
        list_compare_strategy=list_compare_strategy,
    )

TextSpec

TextSpec(lower=True, strip=True, collapse_spaces=True, remove_accents=True, scorer='WRatio', metadata=None, fill_rate_func=None, fill_rate_weight=1.0, fill_rate_accuracy_func=None, fill_rate_accuracy_weight=1.0, similarity_func=None, similarity_weight=1.0, list_compare_strategy=None)

Pre-defined Spec for text fields (fuzzy matching).

Optimized for free-form text. Uses fuzzy similarity and comprehensive text normalization (lowercase, strip, collapse spaces, remove accents).

Parameters:

Name Type Description Default
lower bool

If True (default), convert to lowercase.

True
strip bool

If True (default), strip leading/trailing whitespace.

True
collapse_spaces bool

If True (default), collapse multiple spaces to single.

True
remove_accents bool

If True (default), remove accents from characters.

True
scorer str

The rapidfuzz scorer to use (default: "WRatio").

'WRatio'
metadata dict[str, Any] | None

Optional metadata for the field.

None
fill_rate_func Any

Optional fill rate function.

None
fill_rate_weight float

Weight for fill rate computation (default: 1.0).

1.0
fill_rate_accuracy_func Any

Optional fill rate accuracy function.

None
fill_rate_accuracy_weight float

Weight for fill rate accuracy (default: 1.0).

1.0
similarity_func Any

Optional similarity function (default: fuzzy).

None
similarity_weight float

Weight for similarity computation (default: 1.0).

1.0
list_compare_strategy Any

Strategy for comparing list[BaseModel] items.

None

Returns:

Type Description
Any

FieldSpec instance optimized for text fields.

Example
class Person(BaseModel):
    name: str = TextSpec()
Source code in src/cobjectric/specs.py
def TextSpec(  # noqa: N802
    lower: bool = True,
    strip: bool = True,
    collapse_spaces: bool = True,
    remove_accents: bool = True,
    scorer: str = "WRatio",
    metadata: dict[str, t.Any] | None = None,
    fill_rate_func: t.Any = None,
    fill_rate_weight: float = 1.0,
    fill_rate_accuracy_func: t.Any = None,
    fill_rate_accuracy_weight: float = 1.0,
    similarity_func: t.Any = None,
    similarity_weight: float = 1.0,
    list_compare_strategy: t.Any = None,
) -> t.Any:
    """
    Pre-defined Spec for text fields (fuzzy matching).

    Optimized for free-form text. Uses fuzzy similarity and comprehensive
    text normalization (lowercase, strip, collapse spaces, remove accents).

    Args:
        lower: If True (default), convert to lowercase.
        strip: If True (default), strip leading/trailing whitespace.
        collapse_spaces: If True (default), collapse multiple spaces to single.
        remove_accents: If True (default), remove accents from characters.
        scorer: The rapidfuzz scorer to use (default: "WRatio").
        metadata: Optional metadata for the field.
        fill_rate_func: Optional fill rate function.
        fill_rate_weight: Weight for fill rate computation (default: 1.0).
        fill_rate_accuracy_func: Optional fill rate accuracy function.
        fill_rate_accuracy_weight: Weight for fill rate accuracy (default: 1.0).
        similarity_func: Optional similarity function (default: fuzzy).
        similarity_weight: Weight for similarity computation (default: 1.0).
        list_compare_strategy: Strategy for comparing list[BaseModel] items.

    Returns:
        FieldSpec instance optimized for text fields.

    Example:
        ```python
        class Person(BaseModel):
            name: str = TextSpec()
        ```
    """
    normalizer = None
    if lower or strip or collapse_spaces or remove_accents:

        def text_normalizer(value: t.Any) -> t.Any:
            if isinstance(value, str):
                return _normalize_text(
                    value,
                    lower=lower,
                    strip=strip,
                    collapse_spaces=collapse_spaces,
                    remove_accents=remove_accents,
                )
            return value

        normalizer = text_normalizer

    return Spec(
        metadata=metadata,
        normalizer=normalizer,
        fill_rate_func=fill_rate_func,
        fill_rate_weight=fill_rate_weight,
        fill_rate_accuracy_func=fill_rate_accuracy_func,
        fill_rate_accuracy_weight=fill_rate_accuracy_weight,
        similarity_func=(
            similarity_func
            if similarity_func is not None
            else fuzzy_similarity_factory(scorer=scorer)
        ),
        similarity_weight=similarity_weight,
        list_compare_strategy=list_compare_strategy,
    )

NumericSpec

NumericSpec(max_difference=None, coerce_type=True, metadata=None, fill_rate_func=None, fill_rate_weight=1.0, fill_rate_accuracy_func=None, fill_rate_accuracy_weight=1.0, similarity_func=None, similarity_weight=1.0, list_compare_strategy=None)

Pre-defined Spec for numeric fields.

Optimized for numbers (int, float). Uses numeric similarity with optional tolerance. Can coerce JSON Number to int/float based on field type.

Parameters:

Name Type Description Default
max_difference float | None

Maximum difference for similarity (None = exact match).

None
coerce_type bool

If True (default), coerce to int/float based on field type. Handles JSON Number -> Python int/float conversion.

True
metadata dict[str, Any] | None

Optional metadata for the field.

None
fill_rate_func Any

Optional fill rate function.

None
fill_rate_weight float

Weight for fill rate computation (default: 1.0).

1.0
fill_rate_accuracy_func Any

Optional fill rate accuracy function.

None
fill_rate_accuracy_weight float

Weight for fill rate accuracy (default: 1.0).

1.0
similarity_func Any

Optional similarity function (default: numeric).

None
similarity_weight float

Weight for similarity computation (default: 1.0).

1.0
list_compare_strategy Any

Strategy for comparing list[BaseModel] items.

None

Returns:

Type Description
Any

FieldSpec instance optimized for numeric fields.

Example
class Person(BaseModel):
    age: int = NumericSpec()  # 30.0 from JSON -> 30 (int)
    score: float = NumericSpec(max_difference=0.5)
Source code in src/cobjectric/specs.py
def NumericSpec(  # noqa: N802
    max_difference: float | None = None,
    coerce_type: bool = True,
    metadata: dict[str, t.Any] | None = None,
    fill_rate_func: t.Any = None,
    fill_rate_weight: float = 1.0,
    fill_rate_accuracy_func: t.Any = None,
    fill_rate_accuracy_weight: float = 1.0,
    similarity_func: t.Any = None,
    similarity_weight: float = 1.0,
    list_compare_strategy: t.Any = None,
) -> t.Any:
    """
    Pre-defined Spec for numeric fields.

    Optimized for numbers (int, float). Uses numeric similarity with optional
    tolerance. Can coerce JSON Number to int/float based on field type.

    Args:
        max_difference: Maximum difference for similarity (None = exact match).
        coerce_type: If True (default), coerce to int/float based on field type.
            Handles JSON Number -> Python int/float conversion.
        metadata: Optional metadata for the field.
        fill_rate_func: Optional fill rate function.
        fill_rate_weight: Weight for fill rate computation (default: 1.0).
        fill_rate_accuracy_func: Optional fill rate accuracy function.
        fill_rate_accuracy_weight: Weight for fill rate accuracy (default: 1.0).
        similarity_func: Optional similarity function (default: numeric).
        similarity_weight: Weight for similarity computation (default: 1.0).
        list_compare_strategy: Strategy for comparing list[BaseModel] items.

    Returns:
        FieldSpec instance optimized for numeric fields.

    Example:
        ```python
        class Person(BaseModel):
            age: int = NumericSpec()  # 30.0 from JSON -> 30 (int)
            score: float = NumericSpec(max_difference=0.5)
        ```
    """
    normalizer = None
    if coerce_type:

        def numeric_normalizer(value: t.Any, context: FieldContext) -> t.Any:
            if value is None:
                return value

            try:
                base_type = _extract_numeric_type(context.field_type)
                if base_type is int:
                    return int(float(value))  # 10.0 -> 10
                elif base_type is float:
                    return float(value)  # 10 -> 10.0
            except (ValueError, TypeError):
                pass

            return value

        normalizer = numeric_normalizer

    return Spec(
        metadata=metadata,
        normalizer=normalizer,
        fill_rate_func=fill_rate_func,
        fill_rate_weight=fill_rate_weight,
        fill_rate_accuracy_func=fill_rate_accuracy_func,
        fill_rate_accuracy_weight=fill_rate_accuracy_weight,
        similarity_func=(
            similarity_func
            if similarity_func is not None
            else numeric_similarity_factory(max_difference=max_difference)
        ),
        similarity_weight=similarity_weight,
        list_compare_strategy=list_compare_strategy,
    )

BooleanSpec

BooleanSpec(metadata=None, fill_rate_func=None, fill_rate_weight=1.0, fill_rate_accuracy_func=None, fill_rate_accuracy_weight=1.0, similarity_func=None, similarity_weight=1.0, list_compare_strategy=None)

Pre-defined Spec for boolean fields.

Optimized for boolean values. Uses exact similarity and converts various values to bool.

Parameters:

Name Type Description Default
metadata dict[str, Any] | None

Optional metadata for the field.

None
fill_rate_func Any

Optional fill rate function.

None
fill_rate_weight float

Weight for fill rate computation (default: 1.0).

1.0
fill_rate_accuracy_func Any

Optional fill rate accuracy function.

None
fill_rate_accuracy_weight float

Weight for fill rate accuracy (default: 1.0).

1.0
similarity_func Any

Optional similarity function (default: exact_similarity).

None
similarity_weight float

Weight for similarity computation (default: 1.0).

1.0
list_compare_strategy Any

Strategy for comparing list[BaseModel] items.

None

Returns:

Type Description
Any

FieldSpec instance optimized for boolean fields.

Example
class Person(BaseModel):
    is_active: bool = BooleanSpec()
Source code in src/cobjectric/specs.py
def BooleanSpec(  # noqa: N802
    metadata: dict[str, t.Any] | None = None,
    fill_rate_func: t.Any = None,
    fill_rate_weight: float = 1.0,
    fill_rate_accuracy_func: t.Any = None,
    fill_rate_accuracy_weight: float = 1.0,
    similarity_func: t.Any = None,
    similarity_weight: float = 1.0,
    list_compare_strategy: t.Any = None,
) -> t.Any:
    """
    Pre-defined Spec for boolean fields.

    Optimized for boolean values. Uses exact similarity and converts
    various values to bool.

    Args:
        metadata: Optional metadata for the field.
        fill_rate_func: Optional fill rate function.
        fill_rate_weight: Weight for fill rate computation (default: 1.0).
        fill_rate_accuracy_func: Optional fill rate accuracy function.
        fill_rate_accuracy_weight: Weight for fill rate accuracy (default: 1.0).
        similarity_func: Optional similarity function (default: exact_similarity).
        similarity_weight: Weight for similarity computation (default: 1.0).
        list_compare_strategy: Strategy for comparing list[BaseModel] items.

    Returns:
        FieldSpec instance optimized for boolean fields.

    Example:
        ```python
        class Person(BaseModel):
            is_active: bool = BooleanSpec()
        ```
    """

    def boolean_normalizer(value: t.Any) -> t.Any:
        if value is None:
            return None
        return bool(value)

    return Spec(
        metadata=metadata,
        normalizer=boolean_normalizer,
        fill_rate_func=fill_rate_func,
        fill_rate_weight=fill_rate_weight,
        fill_rate_accuracy_func=fill_rate_accuracy_func,
        fill_rate_accuracy_weight=fill_rate_accuracy_weight,
        similarity_func=(
            similarity_func if similarity_func is not None else exact_similarity
        ),
        similarity_weight=similarity_weight,
        list_compare_strategy=list_compare_strategy,
    )

DatetimeSpec

DatetimeSpec(format=None, max_difference=None, metadata=None, fill_rate_func=None, fill_rate_weight=1.0, fill_rate_accuracy_func=None, fill_rate_accuracy_weight=1.0, similarity_func=None, similarity_weight=1.0, list_compare_strategy=None)

Pre-defined Spec for datetime fields.

Optimized for datetime strings (ISO format). Uses datetime similarity with optional time difference tolerance. Normalizes all datetime values to ISO format strings.

Parameters:

Name Type Description Default
format str | None

Optional datetime format string for parsing (auto-detect if None). If specified, uses datetime.strptime() with this format. Example: "%Y-%m-%d %H:%M:%S", "%d/%m/%Y", etc.

None
max_difference timedelta | None

Maximum time difference as timedelta (None = exact). Use timedelta(days=1), timedelta(hours=1), timedelta(minutes=30), etc.

None
metadata dict[str, Any] | None

Optional metadata for the field.

None
fill_rate_func Any

Optional fill rate function.

None
fill_rate_weight float

Weight for fill rate computation (default: 1.0).

1.0
fill_rate_accuracy_func Any

Optional fill rate accuracy function.

None
fill_rate_accuracy_weight float

Weight for fill rate accuracy (default: 1.0).

1.0
similarity_func Any

Optional similarity function (default: datetime).

None
similarity_weight float

Weight for similarity computation (default: 1.0).

1.0
list_compare_strategy Any

Strategy for comparing list[BaseModel] items.

None

Returns:

Type Description
Any

FieldSpec instance optimized for datetime fields.

Example
from datetime import timedelta

class Event(BaseModel):
    # Auto-detect format
    created_at: str = DatetimeSpec(max_difference=timedelta(hours=1))

    # Custom format
    updated_at: str = DatetimeSpec(format="%Y-%m-%d %H:%M:%S")
Source code in src/cobjectric/specs.py
def DatetimeSpec(  # noqa: N802
    format: str | None = None,
    max_difference: timedelta | None = None,
    metadata: dict[str, t.Any] | None = None,
    fill_rate_func: t.Any = None,
    fill_rate_weight: float = 1.0,
    fill_rate_accuracy_func: t.Any = None,
    fill_rate_accuracy_weight: float = 1.0,
    similarity_func: t.Any = None,
    similarity_weight: float = 1.0,
    list_compare_strategy: t.Any = None,
) -> t.Any:
    """
    Pre-defined Spec for datetime fields.

    Optimized for datetime strings (ISO format). Uses datetime similarity
    with optional time difference tolerance. Normalizes all datetime values
    to ISO format strings.

    Args:
        format: Optional datetime format string for parsing (auto-detect if None).
            If specified, uses datetime.strptime() with this format.
            Example: "%Y-%m-%d %H:%M:%S", "%d/%m/%Y", etc.
        max_difference: Maximum time difference as timedelta (None = exact).
            Use timedelta(days=1), timedelta(hours=1), timedelta(minutes=30), etc.
        metadata: Optional metadata for the field.
        fill_rate_func: Optional fill rate function.
        fill_rate_weight: Weight for fill rate computation (default: 1.0).
        fill_rate_accuracy_func: Optional fill rate accuracy function.
        fill_rate_accuracy_weight: Weight for fill rate accuracy (default: 1.0).
        similarity_func: Optional similarity function (default: datetime).
        similarity_weight: Weight for similarity computation (default: 1.0).
        list_compare_strategy: Strategy for comparing list[BaseModel] items.

    Returns:
        FieldSpec instance optimized for datetime fields.

    Example:
        ```python
        from datetime import timedelta

        class Event(BaseModel):
            # Auto-detect format
            created_at: str = DatetimeSpec(max_difference=timedelta(hours=1))

            # Custom format
            updated_at: str = DatetimeSpec(format="%Y-%m-%d %H:%M:%S")
        ```
    """

    def datetime_normalizer(value: t.Any) -> t.Any:
        return _normalize_datetime_to_iso(value, format_str=format)

    return Spec(
        metadata=metadata,
        normalizer=datetime_normalizer,
        fill_rate_func=fill_rate_func,
        fill_rate_weight=fill_rate_weight,
        fill_rate_accuracy_func=fill_rate_accuracy_func,
        fill_rate_accuracy_weight=fill_rate_accuracy_weight,
        similarity_func=(
            similarity_func
            if similarity_func is not None
            else datetime_similarity_factory(max_difference=max_difference)
        ),
        similarity_weight=similarity_weight,
        list_compare_strategy=list_compare_strategy,
    )

Default Functions

Fill Rate Functions

not_missing_fill_rate(value)

Fill rate function: returns 0.0 if MissingValue, else 1.0.

Parameters:

Name Type Description Default
value Any

The field value.

required

Returns:

Name Type Description
float float

0.0 if MissingValue, 1.0 otherwise.

Examples:

>>> from cobjectric.fill_rate import not_missing_fill_rate
>>> from cobjectric import MissingValue
>>> not_missing_fill_rate("John")
1.0
>>> not_missing_fill_rate(MissingValue)
0.0
Source code in src/cobjectric/fill_rate.py
def not_missing_fill_rate(value: t.Any) -> float:
    """
    Fill rate function: returns 0.0 if MissingValue, else 1.0.

    Args:
        value: The field value.

    Returns:
        float: 0.0 if MissingValue, 1.0 otherwise.

    Examples:
        >>> from cobjectric.fill_rate import not_missing_fill_rate
        >>> from cobjectric import MissingValue
        >>> not_missing_fill_rate("John")
        1.0
        >>> not_missing_fill_rate(MissingValue)
        0.0
    """
    return 0.0 if value is MissingValue else 1.0

Fill Rate Accuracy Functions

same_state_fill_rate_accuracy(got, expected)

Fill rate accuracy function: returns 1.0 if both have same state, else 0.0.

Parameters:

Name Type Description Default
got Any

The field value from the model being evaluated.

required
expected Any

The field value from the expected model.

required

Returns:

Name Type Description
float float

1.0 if both are filled or both are MissingValue, 0.0 otherwise.

Examples:

>>> from cobjectric.fill_rate_accuracy import same_state_fill_rate_accuracy
>>> from cobjectric import MissingValue
>>> same_state_fill_rate_accuracy("John", "Jane")
1.0
>>> same_state_fill_rate_accuracy("John", MissingValue)
0.0
>>> same_state_fill_rate_accuracy(MissingValue, MissingValue)
1.0
Source code in src/cobjectric/fill_rate_accuracy.py
def same_state_fill_rate_accuracy(got: t.Any, expected: t.Any) -> float:
    """
    Fill rate accuracy function: returns 1.0 if both have same state, else 0.0.

    Args:
        got: The field value from the model being evaluated.
        expected: The field value from the expected model.

    Returns:
        float: 1.0 if both are filled or both are MissingValue, 0.0 otherwise.

    Examples:
        >>> from cobjectric.fill_rate_accuracy import same_state_fill_rate_accuracy
        >>> from cobjectric import MissingValue
        >>> same_state_fill_rate_accuracy("John", "Jane")
        1.0
        >>> same_state_fill_rate_accuracy("John", MissingValue)
        0.0
        >>> same_state_fill_rate_accuracy(MissingValue, MissingValue)
        1.0
    """
    got_filled = got is not MissingValue
    expected_filled = expected is not MissingValue
    return 1.0 if got_filled == expected_filled else 0.0

Decorator Functions

fill_rate_func(*field_patterns, weight=1.0)

Decorator to define a fill_rate_func for one or more fields.

Parameters:

Name Type Description Default
*field_patterns str

Field names or glob patterns (e.g., "name", "email", "name_*")

()
weight float

Weight for fill rate computation (default: 1.0, must be >= 0.0).

1.0

Returns:

Type Description
Callable[[FillRateFunc], FillRateFunc]

Decorated function

Raises:

Type Description
InvalidWeightError

If weight is negative (< 0.0).

Example
class Person(BaseModel):
    name: str
    email: str

    @fill_rate_func("name", "email", weight=2.0)
    def fill_rate_name_email(x: t.Any) -> float:
        return len(x) / 100 if x is not MissingValue else 0.0
Source code in src/cobjectric/fill_rate.py
def fill_rate_func(
    *field_patterns: str,
    weight: float = 1.0,
) -> t.Callable[[FillRateFunc], FillRateFunc]:
    """
    Decorator to define a fill_rate_func for one or more fields.

    Args:
        *field_patterns: Field names or glob patterns (e.g., "name", "email", "name_*")
        weight: Weight for fill rate computation (default: 1.0, must be >= 0.0).

    Returns:
        Decorated function

    Raises:
        InvalidWeightError: If weight is negative (< 0.0).

    Example:
        ```python
        class Person(BaseModel):
            name: str
            email: str

            @fill_rate_func("name", "email", weight=2.0)
            def fill_rate_name_email(x: t.Any) -> float:
                return len(x) / 100 if x is not MissingValue else 0.0
        ```
    """
    if weight < 0.0:
        raise InvalidWeightError(weight, "decorator")

    def decorator(func: FillRateFunc) -> FillRateFunc:
        if not hasattr(func, "_fill_rate_funcs"):
            func._fill_rate_funcs = []  # type: ignore[attr-defined]
        func._fill_rate_funcs.append(  # type: ignore[attr-defined]
            FillRateFuncInfo(field_patterns, func, weight)
        )
        return func

    return decorator

fill_rate_accuracy_func(*field_patterns, weight=1.0)

Decorator to define a fill_rate_accuracy_func for one or more fields.

Parameters:

Name Type Description Default
*field_patterns str

Field names or glob patterns (e.g., "name", "email", "name_*")

()
weight float

Weight for fill rate accuracy computation (default: 1.0, must be >= 0.0).

1.0

Returns:

Type Description
Callable[[FillRateAccuracyFunc], FillRateAccuracyFunc]

Decorated function

Raises:

Type Description
InvalidWeightError

If weight is negative (< 0.0).

Example
class Person(BaseModel):
    name: str
    email: str

    @fill_rate_accuracy_func("name", "email", weight=2.0)
    def accuracy_name_email(got: t.Any, expected: t.Any) -> float:
        return (
            1.0
            if (got is not MissingValue) == (expected is not MissingValue)
            else 0.0
        )
Source code in src/cobjectric/fill_rate_accuracy.py
def fill_rate_accuracy_func(
    *field_patterns: str,
    weight: float = 1.0,
) -> t.Callable[[FillRateAccuracyFunc], FillRateAccuracyFunc]:
    """
    Decorator to define a fill_rate_accuracy_func for one or more fields.

    Args:
        *field_patterns: Field names or glob patterns (e.g., "name", "email", "name_*")
        weight: Weight for fill rate accuracy computation
            (default: 1.0, must be >= 0.0).

    Returns:
        Decorated function

    Raises:
        InvalidWeightError: If weight is negative (< 0.0).

    Example:
        ```python
        class Person(BaseModel):
            name: str
            email: str

            @fill_rate_accuracy_func("name", "email", weight=2.0)
            def accuracy_name_email(got: t.Any, expected: t.Any) -> float:
                return (
                    1.0
                    if (got is not MissingValue) == (expected is not MissingValue)
                    else 0.0
                )
        ```
    """
    if weight < 0.0:
        raise InvalidWeightError(weight, "decorator", "fill_rate_accuracy")

    def decorator(func: FillRateAccuracyFunc) -> FillRateAccuracyFunc:
        if not hasattr(func, "_fill_rate_accuracy_funcs"):
            func._fill_rate_accuracy_funcs = []  # type: ignore[attr-defined]
        func._fill_rate_accuracy_funcs.append(  # type: ignore[attr-defined]
            FillRateAccuracyFuncInfo(field_patterns, func, weight)
        )
        return func

    return decorator

similarity_func(*field_patterns, weight=1.0)

Decorator to define a similarity_func for one or more fields.

Parameters:

Name Type Description Default
*field_patterns str

Field names or glob patterns (e.g., "name", "email", "name_*")

()
weight float

Weight for similarity computation (default: 1.0, must be >= 0.0).

1.0

Returns:

Type Description
Callable[[SimilarityFunc], SimilarityFunc]

Decorated function

Raises:

Type Description
InvalidWeightError

If weight is negative (< 0.0).

Example
class Person(BaseModel):
    name: str
    email: str

    @similarity_func("name", "email", weight=2.0)
    def similarity_name_email(x: t.Any, y: t.Any) -> float:
        return 1.0 if x == y else 0.0
Source code in src/cobjectric/similarity.py
def similarity_func(
    *field_patterns: str,
    weight: float = 1.0,
) -> t.Callable[[SimilarityFunc], SimilarityFunc]:
    """
    Decorator to define a similarity_func for one or more fields.

    Args:
        *field_patterns: Field names or glob patterns (e.g., "name", "email", "name_*")
        weight: Weight for similarity computation (default: 1.0, must be >= 0.0).

    Returns:
        Decorated function

    Raises:
        InvalidWeightError: If weight is negative (< 0.0).

    Example:
        ```python
        class Person(BaseModel):
            name: str
            email: str

            @similarity_func("name", "email", weight=2.0)
            def similarity_name_email(x: t.Any, y: t.Any) -> float:
                return 1.0 if x == y else 0.0
        ```
    """
    if weight < 0.0:
        raise InvalidWeightError(weight, "decorator", "similarity")

    def decorator(func: SimilarityFunc) -> SimilarityFunc:
        if not hasattr(func, "_similarity_funcs"):
            func._similarity_funcs = []  # type: ignore[attr-defined]
        func._similarity_funcs.append(  # type: ignore[attr-defined]
            SimilarityFuncInfo(field_patterns, func, weight)
        )
        return func

    return decorator

field_normalizer(*field_patterns)

Decorator to define a normalizer for one or more fields.

Parameters:

Name Type Description Default
*field_patterns str

Field names or glob patterns (e.g., "name", "email", "name_*")

()

Returns:

Type Description
Callable[[Callable[..., Any]], Callable[..., Any]]

Decorated function

Source code in src/cobjectric/normalizer.py
def field_normalizer(
    *field_patterns: str,
) -> t.Callable[[t.Callable[..., t.Any]], t.Callable[..., t.Any]]:
    """
    Decorator to define a normalizer for one or more fields.

    Args:
        *field_patterns: Field names or glob patterns (e.g., "name", "email", "name_*")

    Returns:
        Decorated function
    """

    def decorator(func: t.Callable[..., t.Any]) -> t.Callable[..., t.Any]:
        if not hasattr(func, "_field_normalizers"):
            func._field_normalizers = []  # type: ignore[attr-defined]
        func._field_normalizers.append(  # type: ignore[attr-defined]
            FieldNormalizerInfo(field_patterns, func)
        )
        return func

    return decorator

Exceptions

All exceptions inherit from CobjectricError. Handle them appropriately in your error handling logic.

Base Exception

CobjectricError

Bases: Exception

Base exception for all cobjectric errors.

Type Exceptions

UnsupportedTypeError(unsupported_type)

Bases: CobjectricError

Exception raised when a field type is not supported.

This exception is raised when a field type is not JSON-compatible. Only str, int, float, bool, list[T], or BaseModel subclasses are allowed.

Initialize UnsupportedTypeError.

Parameters:

Name Type Description Default
unsupported_type type

The unsupported type that was detected.

required
Source code in src/cobjectric/exceptions.py
def __init__(self, unsupported_type: type) -> None:
    """
    Initialize UnsupportedTypeError.

    Args:
        unsupported_type: The unsupported type that was detected.
    """
    self.unsupported_type = unsupported_type
    type_name = getattr(unsupported_type, "__name__", str(unsupported_type))
    super().__init__(
        f"Unsupported type: {type_name}. "
        "Only JSON-compatible types are allowed: str, int, float, bool, "
        "list[T], or BaseModel subclasses."
    )

Functions

UnsupportedListTypeError(unsupported_type)

Bases: CobjectricError

Exception raised when a list field has an unsupported type.

This exception is raised when a list field contains a Union type, which is not supported. Only single types are allowed in lists.

Initialize UnsupportedListTypeError.

Parameters:

Name Type Description Default
unsupported_type type

The unsupported type that was detected.

required
Source code in src/cobjectric/exceptions.py
def __init__(self, unsupported_type: type) -> None:
    """
    Initialize UnsupportedListTypeError.

    Args:
        unsupported_type: The unsupported type that was detected.
    """
    self.unsupported_type = unsupported_type
    type_name = getattr(unsupported_type, "__name__", str(unsupported_type))
    super().__init__(
        f"Unsupported list type: list[{type_name}]. "
        "List fields must contain a single type (e.g., list[str], list[int], "
        "list[MyModel]). Union types like list[str | int] are not supported."
    )

Functions

MissingListTypeArgError()

Bases: CobjectricError

Exception raised when a list type is used without type arguments.

This exception is raised when using bare 'list' or 't.List' without specifying the element type.

Initialize MissingListTypeArgError.

Source code in src/cobjectric/exceptions.py
def __init__(self) -> None:
    """Initialize MissingListTypeArgError."""
    super().__init__(
        "List type must specify an element type. "
        "Use list[str], list[int], list[MyModel], etc. instead of bare 'list'."
    )

Functions

Function Definition Exceptions

DuplicateFillRateFuncError(field_name)

Bases: CobjectricError

Exception raised when multiple fill_rate_func are defined for the same field.

This exception is raised when a field has both a Spec(fill_rate_func=...) and a @fill_rate_func decorator, or multiple @fill_rate_func decorators.

Initialize DuplicateFillRateFuncError.

Parameters:

Name Type Description Default
field_name str

The name of the field with duplicate fill_rate_func.

required
Source code in src/cobjectric/exceptions.py
def __init__(self, field_name: str) -> None:
    """
    Initialize DuplicateFillRateFuncError.

    Args:
        field_name: The name of the field with duplicate fill_rate_func.
    """
    self.field_name = field_name
    super().__init__(
        f"Multiple fill_rate_func defined for field '{field_name}'. "
        "A field can only have one fill_rate_func (either from Spec() or "
        "@fill_rate_func decorator, not both)."
    )

Functions

DuplicateFillRateAccuracyFuncError(field_name)

Bases: CobjectricError

Exception raised when multiple fill_rate_accuracy_func are defined.

This exception is raised when a field has both a Spec(fill_rate_accuracy_func=...) and a @fill_rate_accuracy_func decorator, or multiple @fill_rate_accuracy_func decorators.

Initialize DuplicateFillRateAccuracyFuncError.

Parameters:

Name Type Description Default
field_name str

The name of the field with duplicate fill_rate_accuracy_func.

required
Source code in src/cobjectric/exceptions.py
def __init__(self, field_name: str) -> None:
    """
    Initialize DuplicateFillRateAccuracyFuncError.

    Args:
        field_name: The name of the field with duplicate fill_rate_accuracy_func.
    """
    self.field_name = field_name
    super().__init__(
        f"Multiple fill_rate_accuracy_func defined for field '{field_name}'. "
        "A field can only have one fill_rate_accuracy_func (either from Spec() or "
        "@fill_rate_accuracy_func decorator, not both)."
    )

Functions

DuplicateSimilarityFuncError(field_name)

Bases: CobjectricError

Exception raised when multiple similarity_func are defined.

This exception is raised when a field has both a Spec(similarity_func=...) and a @similarity_func decorator, or multiple @similarity_func decorators.

Initialize DuplicateSimilarityFuncError.

Parameters:

Name Type Description Default
field_name str

The name of the field with duplicate similarity_func.

required
Source code in src/cobjectric/exceptions.py
def __init__(self, field_name: str) -> None:
    """
    Initialize DuplicateSimilarityFuncError.

    Args:
        field_name: The name of the field with duplicate similarity_func.
    """
    self.field_name = field_name
    super().__init__(
        f"Multiple similarity_func defined for field '{field_name}'. "
        "A field can only have one similarity_func (either from Spec() or "
        "@similarity_func decorator, not both)."
    )

Functions

Validation Exceptions

InvalidFillRateValueError(field_name, value)

Bases: CobjectricError

Exception raised when fill_rate_func returns an invalid value.

This exception is raised when fill_rate_func returns a value that is not a float (or int convertible to float) or is not in the range [0, 1].

Initialize InvalidFillRateValueError.

Parameters:

Name Type Description Default
field_name str

The name of the field with invalid fill_rate value.

required
value Any

The invalid value that was returned.

required
Source code in src/cobjectric/exceptions.py
def __init__(self, field_name: str, value: t.Any) -> None:
    """
    Initialize InvalidFillRateValueError.

    Args:
        field_name: The name of the field with invalid fill_rate value.
        value: The invalid value that was returned.
    """
    self.field_name = field_name
    self.value = value
    value_type = type(value).__name__
    super().__init__(
        f"Invalid fill_rate value for field '{field_name}': {value!r} "
        f"(type: {value_type}). Fill rate must be a float between 0.0 and 1.0."
    )

Functions

InvalidWeightError(weight, source, weight_type='fill_rate')

Bases: CobjectricError

Exception raised when weight is invalid.

This exception is raised when weight is negative (< 0.0). Weight must be >= 0.0.

Initialize InvalidWeightError.

Parameters:

Name Type Description Default
weight float

The invalid weight value.

required
source str

The source of the weight ("Spec" or "decorator").

required
weight_type str

The type of weight ("fill_rate" or "fill_rate_accuracy").

'fill_rate'
Source code in src/cobjectric/exceptions.py
def __init__(
    self, weight: float, source: str, weight_type: str = "fill_rate"
) -> None:
    """
    Initialize InvalidWeightError.

    Args:
        weight: The invalid weight value.
        source: The source of the weight ("Spec" or "decorator").
        weight_type: The type of weight ("fill_rate" or "fill_rate_accuracy").
    """
    self.weight = weight
    self.source = source
    self.weight_type = weight_type
    if weight_type == "fill_rate":
        super().__init__(
            f"Invalid weight in {source}: {weight}. Weight must be >= 0.0."
        )
    else:
        super().__init__(
            f"Invalid {weight_type}_weight in {source}: {weight}. "
            "Weight must be >= 0.0."
        )

Functions

InvalidAggregatedFieldError(field_name, available_fields, model_type=None)

Bases: CobjectricError

Exception raised when accessing an invalid field in aggregated_fields.

This exception is raised when trying to access a field that doesn't exist in the aggregated model through aggregated_fields property.

Initialize InvalidAggregatedFieldError.

Parameters:

Name Type Description Default
field_name str

The name of the field that was accessed.

required
available_fields list[str]

List of available field names.

required
model_type type | None

The model type (optional) for additional context.

None
Source code in src/cobjectric/exceptions.py
def __init__(
    self,
    field_name: str,
    available_fields: list[str],
    model_type: type | None = None,
) -> None:
    """
    Initialize InvalidAggregatedFieldError.

    Args:
        field_name: The name of the field that was accessed.
        available_fields: List of available field names.
        model_type: The model type (optional) for additional context.
    """
    self.field_name = field_name
    self.available_fields = available_fields
    self.model_type = model_type
    fields_str = ", ".join(repr(f) for f in available_fields)
    type_str = f" (from {model_type.__name__})" if model_type else ""
    super().__init__(
        f"Invalid aggregated field '{field_name}'{type_str}. "
        f"Available fields: [{fields_str}]"
    )

Functions

InvalidListCompareStrategyError(field_name)

Bases: CobjectricError

Exception raised when list_compare_strategy is used on a non-list field.

This exception is raised when trying to use list_compare_strategy on a field that is not a list[BaseModel] type.

Initialize InvalidListCompareStrategyError.

Parameters:

Name Type Description Default
field_name str

The name of the field with invalid list_compare_strategy.

required
Source code in src/cobjectric/exceptions.py
def __init__(self, field_name: str) -> None:
    """
    Initialize InvalidListCompareStrategyError.

    Args:
        field_name: The name of the field with invalid list_compare_strategy.
    """
    self.field_name = field_name
    super().__init__(
        f"list_compare_strategy can only be used on list[BaseModel] fields. "
        f"Field '{field_name}' is not a list[BaseModel] type."
    )

Functions