# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbs/utils/04_custom_base_model.ipynb.

# %% auto 0
__all__ = ['CustomBaseModel']

# %% ../../nbs/utils/04_custom_base_model.ipynb 2
from typing import Any

from pydantic import BaseModel, ConfigDict, Field, computed_field, field_validator, model_validator  # noqa: F401

# %% ../../nbs/utils/04_custom_base_model.ipynb 4
class CustomBaseModel(BaseModel):
    model_config = ConfigDict(
        arbitrary_types_allowed=True,
        extra="ignore",
        validate_default=True,
        validate_assignment=True,
        validate_return=True,
    )

    def get(self, key: str, default: Any = None) -> Any:
        """Returns the value of the key if it exists, otherwise returns the default value."""
        return getattr(self, key, default)

    def setdefault(self, key: str, value: Any) -> None:
        """Sets the default value of the key if it does not exist."""
        if not hasattr(self, key):
            setattr(self, key, value)

    @classmethod
    def model_validate(cls, obj, cast_to_super: bool = False, **kwargs):
        """Base class method for validating data before creating the model."""
        if cast_to_super:
            # if the provided data is an instance of a subclass of the desired model, the validated model remains an
            # instance of the subclass. This is not desired in this repo, so we convert CustomBaseModel instances to
            # dictionaries before validating
            if isinstance(obj, CustomBaseModel):
                obj = obj.model_dump()
        validated = super().model_validate(obj, **kwargs)
        return validated

    @model_validator(mode="before")
    @classmethod
    def validate_before(cls, data):
        """Base class method for validating data before creating the model."""
        return data

    @model_validator(mode="after")
    def validate(self):
        """Base method for validating the model after creation."""
        return self

    def __contains__(self, key):
        return hasattr(self, key)

    def __or__(self, other: dict):
        if not isinstance(other, (dict, CustomBaseModel)):
            raise TypeError(f"Cannot merge object of type {type(other)} with {self.__class__.__name__}")
        if isinstance(other, CustomBaseModel):
            other = other.model_dump()
        updated = self.model_copy(update=other, deep=True)  # Pydantic v2 way of updating fields
        return updated
