monkey_wrench.generic._types module

monkey_wrench.generic._types.ListSetTuple = list[~ElementType] | set[~ElementType] | tuple[~ElementType, ...]

Generic type alias for the union of homogeneous lists, sets, and tuples, i.e. classic iterables..

Warning

Strings and dictionaries have been intentionally left out, although they are also iterables!

class monkey_wrench.generic._types.Model[source]

Bases: BaseModel

A Pydantic model to be used as a base for all other models, e.g. specifications of a task.

Note

Models that inherit from this model have the following properties

1- They do not allow any extra keyword arguments to be passed to the constructor if the corresponding field is not explicitly defined.

2- The fields are faux-immutable (frozen).

3- They allow for arbitrary types to be validated, e.g. when using pydantic.validate_call decorator.

Example

class Dataset(Model):
    name: str

# The following will lead to an exception.
# `number` has not been explicitly defined as a model field.
dataset = Dataset(name="dataset-name", number=1)

dataset = Dataset(name="dataset-name")
# The following will lead to an exception.
# All fields (i.e. `name` in this case) are immutable.
dataset.name = "dataset-name_changed"
new_with(**kwargs: dict[str, Any]) Self[source]

Create an instance of the same model but with new values for the fields as determined by kwargs.

Warning

The new instance will be validated against all field and model validators before being returned. This is true even for the fields which have not been updated via kwargs. As a result, if validators for fields have side effects, it is important to ensure that the side effects do not unintentionally get repeated!d! Look at the example below for such an unintentional side effect!

Example

>>> from typing_extensions import Annotated
>>> from pydantic import AfterValidator
>>>
>>> class Dataset(Model):
...     set_number: int
...     count: int
...     name: Annotated[str, AfterValidator(lambda x: x + ".extension")]
>>>
>>> dataset = Dataset(name="dataset-original", count=10, set_number=1)
>>> dataset
Dataset(set_number=1, count=10, name='dataset-original.extension')
>>>
>>> dataset_new = dataset.new_with(set_number=2)
>>> dataset_new
Dataset(set_number=2, count=10, name='dataset-original.extension.extension')
>>> # `.extension` gets duplicated as the validator for `name` runs twice.
>>> # `name` has not been explicitly passed to the `with_new()` method!
>>> # `count` has not been affected since its validator `int` is pure!