Skip to content

model

numerous.experimental.model

The model module.

The module defines a BaseModel class that dynamically creates a Pydantic model based on the declared fields and interfaces in the subclass.

It leverages Pydantic's create_model function to handle validation and type enforcement.

The BaseModel class provides methods to initialize the model, retrieve the validated data, and access the dynamically created Pydantic model object. Additionally, the module defines a Field class that represents a field in the model.

The Field class handles default values, type annotations, and other properties of the field.

  • BaseModel: Class representing a generic model that integrates with Pydantic for data validation.
  • Field: Class representing a field in the model.

BaseModel

Bases: _ModelInterface

Class representing a generic model that use with Pydantic for data validation.

This class constructs a Pydantic model dynamically based on the declared fields and interfaces in the class. It leverages Pydantic's create_model function to handle validation and type enforcement.

Attributes:

Name Type Description
pydantic_model_cls

Dynamically created Pydantic model class based on the fields defined in the subclass.

Source code in numerous/experimental/model.py
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
class BaseModel(_ModelInterface):
    """
    Class representing a generic model that use with Pydantic for data validation.

    This class constructs a Pydantic model dynamically based on the declared fields and
    interfaces in the class. It leverages Pydantic's `create_model` function to handle
    validation and type enforcement.

    Attributes:
        pydantic_model_cls:
            Dynamically created Pydantic model class based on the fields
            defined in the subclass.

    """

    def __init__(self, **kwargs: dict[str, Any]) -> None:
        """
        Initialize a model object with the given fields.

        Args:
            kwargs: Keyword arguments representing the field values.

        """
        _attrs = {}
        for key, val in self.__class__.__dict__.items():
            # Find all the fields in the class
            if isinstance(val, Field):
                _attrs[key] = val.field_attrs
            elif isinstance(val, _ModelInterface):
                # If the field is a subclass of Model, get the model attributes
                _attrs[key] = val.model_attrs

        # Create a Pydantic model class with the fields
        self.pydantic_model_cls = create_model(self.__class__.__name__, **_attrs)  # type: ignore[call-overload]

        # Set them as values to Field objects
        for key, val in kwargs.items():
            getattr(self, key)._field_value = val  # noqa: SLF001

        self._fields = {}
        for key, val in self.__class__.__dict__.items():
            # Find all the fields in the class
            if isinstance(val, (Field, _ModelInterface)):
                val._name = key  # noqa: SLF001
                self._fields[key] = val

        # Check if any non-optional fields are missing a value
        for val in self._fields.values():
            # By accessing the value property, the value is checked for validity
            _ = val.value
            # Add self as the parent model.
            # This is used to validate the model when a field is changed
            val._parent_model = self  # noqa: SLF001

        # Trigger a validation of the model by accessing the value property
        _ = self.pydantic_model

    @property
    def value(self) -> PydanticBaseModel:
        """The PydanticBaseModel instance associated with this object."""
        return self.pydantic_model

    @property
    def model_attrs(self) -> Tuple[Any, PydanticBaseModel]:
        """Data required to create a Pydantic model object."""
        return (type(self.pydantic_model), self.pydantic_model)

    @property
    def pydantic_model(self) -> PydanticBaseModel:
        """Get a Pydantic model object representing the model."""
        _kwargs = {}

        # Get the values from the fields
        for key, val in self._fields.items():
            _kwargs[key] = val.value

        # Create a Pydantic model object with the values
        pydantic_model = self.pydantic_model_cls(**_kwargs)
        if isinstance(pydantic_model, PydanticBaseModel):
            return pydantic_model

        error_msg = "Invalid Pydantic model object."
        raise TypeError(error_msg)

model_attrs: Tuple[Any, PydanticBaseModel] property

Data required to create a Pydantic model object.

pydantic_model: PydanticBaseModel property

Get a Pydantic model object representing the model.

value: PydanticBaseModel property

The PydanticBaseModel instance associated with this object.

__init__(**kwargs)

Initialize a model object with the given fields.

Parameters:

Name Type Description Default
kwargs dict[str, Any]

Keyword arguments representing the field values.

{}
Source code in numerous/experimental/model.py
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
def __init__(self, **kwargs: dict[str, Any]) -> None:
    """
    Initialize a model object with the given fields.

    Args:
        kwargs: Keyword arguments representing the field values.

    """
    _attrs = {}
    for key, val in self.__class__.__dict__.items():
        # Find all the fields in the class
        if isinstance(val, Field):
            _attrs[key] = val.field_attrs
        elif isinstance(val, _ModelInterface):
            # If the field is a subclass of Model, get the model attributes
            _attrs[key] = val.model_attrs

    # Create a Pydantic model class with the fields
    self.pydantic_model_cls = create_model(self.__class__.__name__, **_attrs)  # type: ignore[call-overload]

    # Set them as values to Field objects
    for key, val in kwargs.items():
        getattr(self, key)._field_value = val  # noqa: SLF001

    self._fields = {}
    for key, val in self.__class__.__dict__.items():
        # Find all the fields in the class
        if isinstance(val, (Field, _ModelInterface)):
            val._name = key  # noqa: SLF001
            self._fields[key] = val

    # Check if any non-optional fields are missing a value
    for val in self._fields.values():
        # By accessing the value property, the value is checked for validity
        _ = val.value
        # Add self as the parent model.
        # This is used to validate the model when a field is changed
        val._parent_model = self  # noqa: SLF001

    # Trigger a validation of the model by accessing the value property
    _ = self.pydantic_model

Field

Source code in numerous/experimental/model.py
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
class Field:
    def __init__(
        self,
        default: Union[str, float, None] = None,
        annotation: Union[type, None] = None,
        **kwargs: dict[str, Any],
    ) -> None:
        """
        Initialize a Field object.

        Args:
            default: The default value for the field, by default ...
            annotation: The type annotation for the field, by default None
            kwargs: Additional properties for the field.

        """
        self._default = default
        self._props = kwargs
        self._default = default
        self._field_value = default
        self._name: Union[str, None] = None
        self._parent_model = None

        # Check if the annotation is provided if the default value is None
        if annotation is None and default is None:
            error_msg = "Annotation must be provided if value is None"
            raise ValueError(error_msg)

        # Set the annotation to the type of the default value if it is not provided
        self._annotation = annotation if annotation is not None else type(default)

    @property
    def name(self) -> str:
        """
        The name of the field.

        Raises:
            ValueError: If the name is accessed before it has been set, or if it is set
                again after it has been set.

        """
        if self._name is None:
            error_msg = "Name has not been set"
            raise ValueError(error_msg)
        return self._name

    @name.setter
    def name(self, name: str) -> None:
        if self._name is not None:
            error_msg = "Name has already been set"
            raise ValueError(error_msg)
        self._name = name

    @property
    def field_attrs(self) -> Tuple[type, Any]:
        """
        The field attributes.

        A tuple containing the value and type annotation of the field, along with other
        properties.

        """
        return (self._annotation, self.field_info)

    @property
    def field_info(self) -> Any:  # noqa: ANN401
        """
        Field information.

        A tuple containing the Pydantic Field object with the value and properties.
        """
        # Create a Pydantic Field object with the value and properties
        self._field_info = PydanticField(self._default, **self._props)  # type: ignore[arg-type,call-overload,unused-ignore]
        return self._field_info

    @property
    def value(self) -> Union[str, float]:
        """The value of the object."""
        return self.get()

    @value.setter
    def value(self, value: Union[str, float]) -> None:
        self.set(value)

    def get(self) -> Union[str, float]:
        """
        Get the value of the field.

        Raises:
            ValueError: If the value is accessed before it has been set, or if it is set
                again after it has been set.

        """
        if self._field_value is None:
            error_msg = "Value has not been set"
            raise ValueError(error_msg)
        return self._field_value

    def set(self, value: Any) -> None:  # noqa: ANN401
        """
        Set the value of the field.

        Args:
            value: The new value to be set.

        Raises:
            Exception: If the parent model validation fails.

        """
        old_value = self._field_value
        self._field_value = value
        if self._parent_model is None:
            error_msg = "Parent model has not been set"
            raise ValueError(error_msg)
        try:
            # Trigger the parent model validation
            _ = self._parent_model.value
        except:
            # If the validation fails, revert the value
            self._field_value = old_value
            # Raise the error
            raise

field_attrs: Tuple[type, Any] property

The field attributes.

A tuple containing the value and type annotation of the field, along with other properties.

field_info: Any property

Field information.

A tuple containing the Pydantic Field object with the value and properties.

name: str property writable

The name of the field.

Raises:

Type Description
ValueError

If the name is accessed before it has been set, or if it is set again after it has been set.

value: Union[str, float] property writable

The value of the object.

__init__(default=None, annotation=None, **kwargs)

Initialize a Field object.

Parameters:

Name Type Description Default
default Union[str, float, None]

The default value for the field, by default ...

None
annotation Union[type, None]

The type annotation for the field, by default None

None
kwargs dict[str, Any]

Additional properties for the field.

{}
Source code in numerous/experimental/model.py
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
def __init__(
    self,
    default: Union[str, float, None] = None,
    annotation: Union[type, None] = None,
    **kwargs: dict[str, Any],
) -> None:
    """
    Initialize a Field object.

    Args:
        default: The default value for the field, by default ...
        annotation: The type annotation for the field, by default None
        kwargs: Additional properties for the field.

    """
    self._default = default
    self._props = kwargs
    self._default = default
    self._field_value = default
    self._name: Union[str, None] = None
    self._parent_model = None

    # Check if the annotation is provided if the default value is None
    if annotation is None and default is None:
        error_msg = "Annotation must be provided if value is None"
        raise ValueError(error_msg)

    # Set the annotation to the type of the default value if it is not provided
    self._annotation = annotation if annotation is not None else type(default)

get()

Get the value of the field.

Raises:

Type Description
ValueError

If the value is accessed before it has been set, or if it is set again after it has been set.

Source code in numerous/experimental/model.py
218
219
220
221
222
223
224
225
226
227
228
229
230
def get(self) -> Union[str, float]:
    """
    Get the value of the field.

    Raises:
        ValueError: If the value is accessed before it has been set, or if it is set
            again after it has been set.

    """
    if self._field_value is None:
        error_msg = "Value has not been set"
        raise ValueError(error_msg)
    return self._field_value

set(value)

Set the value of the field.

Parameters:

Name Type Description Default
value Any

The new value to be set.

required

Raises:

Type Description
Exception

If the parent model validation fails.

Source code in numerous/experimental/model.py
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
def set(self, value: Any) -> None:  # noqa: ANN401
    """
    Set the value of the field.

    Args:
        value: The new value to be set.

    Raises:
        Exception: If the parent model validation fails.

    """
    old_value = self._field_value
    self._field_value = value
    if self._parent_model is None:
        error_msg = "Parent model has not been set"
        raise ValueError(error_msg)
    try:
        # Trigger the parent model validation
        _ = self._parent_model.value
    except:
        # If the validation fails, revert the value
        self._field_value = old_value
        # Raise the error
        raise