monkey_wrench.generic package

The package providing some generic utilities and types, used in other sub-packages of Monkey Wrench.

class monkey_wrench.generic.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!
class monkey_wrench.generic.StringTransformation(*, trim: bool = True, transform_function: Annotated[Callable[[...], TransformedType], BeforeValidator(func=validate_function_path, json_schema_input_type=PydanticUndefined)] | Callable[[...], TransformedType] | None = None)[source]

Bases: Model, Generic

Pydantic model for transformations on strings, e.g. before writing to or after reading from a file.

_transform_item(item: OriginalType) OriginalType | TransformedType[source]

Transform a single item.

_trim_item(item: OriginalType) str[source]

Trim a single item. The item can be of any type and will be coerced into a string first.

transform_items(items: list[OriginalType] | set[OriginalType] | tuple[OriginalType, ...] | OriginalType) list[TransformedType] | set[TransformedType] | tuple[TransformedType, ...] | list[OriginalType] | set[OriginalType] | tuple[OriginalType, ...] | OriginalType | TransformedType[source]

Transform a single or multiple items (of any type).

trim_items(items: list[OriginalType] | set[OriginalType] | tuple[OriginalType, ...] | OriginalType) list[str] | set[str] | tuple[str, ...] | str[source]

Trim a single or multiple items. The items can be of any type and will be first coerced into strings.

trim: bool

A boolean indicating whether to remove trailing/leading whitespaces, tabs, and newlines from string items.

Defaults to True.

transform_function: Annotated[Callable[[...], TransformedType], BeforeValidator(func=validate_function_path, json_schema_input_type=PydanticUndefined)] | Callable[[...], TransformedType] | None

If given, each item will be transformed according to the function.

Defaults to None, which means no transformation is performed and items will be treated as they are.

monkey_wrench.generic.apply_to_single_or_collection(function: Callable[[T], R], single_or_collection: dict[Any, T] | list[T] | set[T] | tuple[T, ...] | T) dict[Any, R] | list[R] | set[R] | tuple[R, ...] | R[source]

Apply the given function to a single item or all elements of a collection (dict/list/set/tuple).

Note

In the case of a dictionary, function will be applied to the values.

Warning

A string, although being a collection, is treated as a single item.

Parameters:
  • function – The function to be applied.

  • single_or_collection – Either a single item or a collection (dict/list/set/tuple).

Returns:

Either a single output, or a collection as output resulting from applying the given function.

Examples

>>> apply_to_single_or_collection(lambda x: x**2, [1, 2, 3])
[1, 4, 9]
>>> apply_to_single_or_collection(lambda x: x**2, (1, 2, 3))
(1, 4, 9)
>>> apply_to_single_or_collection(lambda x: x**2, {"a": 1, "b": 2, "c":3})
{'a': 1, 'b': 4, 'c': 9}
>>> apply_to_single_or_collection(lambda x: x**2, set())
set()
>>> apply_to_single_or_collection(lambda x: x**2, 3)
9
>>> apply_to_single_or_collection(lambda x: x*2, "book!")
'book!book!'
monkey_wrench.generic.assert_(item: ~monkey_wrench.generic._common.T, message: str, exception: type[Exception] = <class 'ValueError'>, silent: bool = True) T[source]

Assert the truth value of the item, and return the item or raise exception.

Parameters:
  • item – The item to assert. It does not have to be a boolean. For example, given an empty list, assert [] fails as an empty list evaluates to False.

  • message – The exception message, which will be shown when the exception is raised.

  • exception – The exception to raise if both the item and silent evaluate to False. Defaults to ValueError.

  • silent – A boolean indicating whether to return the item silently or raise an exception in the case of assertion failure. Defaults to True, which means the item will be silently returned.

Returns:

Return the item if it evaluates to True. If the item evaluates to False, return it only if silent is True.

Raises:

exception – If the item evaluates to False and silent is False.

monkey_wrench.generic.collection_element_type(collection: dict[Any, T] | list[T] | set[T] | tuple[T, ...]) type[T] | None[source]

Return the type of collection elements, e.g. for set[T] it returns T.

Parameters:

collection – The collection to get the type of any element from.

Returns:

The type of any element from the collection (dict/list/set/tuple). In the case of an empty collection, None is returned.

Raises:

TypeError – If the collection elements are of different types.

Examples

>>> collection_element_type([3, 2, 1])
<class 'int'>
>>> collection_element_type(set()) is None
True
>>> # The following will lead to an exception, since the collection elements are not of the same type.
>>> # element_type_from_collection((3.0, 2.0, "1"))
monkey_wrench.generic.type_(single_or_collection: dict[Any, T] | list[T] | set[T] | tuple[T, ...] | T) type[T] | None[source]

Return the type of the given item, or any element from the collection using element_type_from_collection().

Examples

>>> type_([3, 2, 1])
<class 'int'>
>>> type_(3)
<class 'int'>

Subpackages

Submodules