Source code for monkey_wrench.generic._common

from typing import Any, Callable, TypeVar

from pydantic import validate_call

from monkey_wrench.generic._types import ListSetTuple

T = TypeVar("T")
U = TypeVar("U")
R = TypeVar("R")


[docs] def assert_(item: T, message: str, exception: type[Exception] = ValueError, silent: bool = True) -> T: """Assert the truth value of the item, and return the item or raise ``exception``. Args: 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``. """ if item or silent: return item raise exception(message)
[docs] @validate_call def apply_to_single_or_collection( function: Callable[[T], R], single_or_collection: dict[Any, T] | ListSetTuple[T] | T ) -> dict[Any, R] | ListSetTuple[R] | R: """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. Args: 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!' """ match single_or_collection: case dict(): return {k: function(v) for k, v in single_or_collection.items()} case list(): return [function(i) for i in single_or_collection] case set(): return {function(i) for i in single_or_collection} case tuple(): return tuple(function(i) for i in single_or_collection) case _: return function(single_or_collection)
[docs] @validate_call def collection_element_type(collection: dict[Any, T] | ListSetTuple[T]) -> type[T] | None: """Return the type of collection elements, e.g. for ``set[T]`` it returns ``T``. Args: 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")) """ if len(collection) == 0: return None elements = tuple(collection.values() if isinstance(collection, dict) else collection) any_element_type = type(elements[0]) if all([isinstance(e, any_element_type) for e in elements]): return any_element_type raise TypeError("Cannot return a single element type when collection elements are of different types.")
[docs] @validate_call def type_(single_or_collection: dict[Any, T] | ListSetTuple[T] | T) -> type[T] | None: """Return the type of the given item, or any element from the collection using :func:`element_type_from_collection`. Examples: >>> type_([3, 2, 1]) <class 'int'> >>> type_(3) <class 'int'> """ match single_or_collection: case dict() | list() | set() | tuple(): return collection_element_type(single_or_collection) case _: return type(single_or_collection)