Source code for pypey.func

"""
Functions and constants for a concise use of higher-level functions
"""
from functools import partial
from typing import Any, Callable as Fn, TypeVar, Iterable, Type, Tuple

__all__ = ['Fn', 'H', 'I', 'K', 'T', 'V', 'X', 'Y', 'px', 'ident', 'pipe', 'require', 'require_val', 'throw']

H = TypeVar('H', Any, Any)
I = TypeVar('I', bound=Iterable)
K = TypeVar('K')
T = TypeVar('T')
V = TypeVar('V')
X = TypeVar('X')
Y = TypeVar('Y')

#: Concise alias of ``functools.partial``
px: Fn[..., Fn] = partial


[docs]def ident(item: T) -> T: """ Identity function, returns the argument passed to it. :param item: any argument :return: the argument passed in """ return item
[docs]def pipe(*functions: Fn) -> Fn: """ Chains given functions. :: >>> from pypey import pipe >>> from math import sqrt >>> [pipe(len, sqrt)(w) for w in ('a', 'fun','day')] [1.0, 1.7320508075688772, 1.7320508075688772] For functions taking multiple arguments, the return of the previous function in the chain will be unpacked only if it's a ``tuple``: :: >>> from pypey import pipe >>> pipe(divmod, lambda quotient, remainder: quotient + remainder)(10, 3) 4 If a function returns an ``Iterable`` that it's not a tuple but unpacking in the next function is still needed, built-in ``tuple`` can be inserted in between to achieve the desired effect: :: >>> from pypey import pipe >>> pipe(range, tuple, lambda _1, _2_, _3: sum([_1, _3]))(3) 2 Conversely, if a function returns a ``tuple`` but unpacking is not required in the next function, built-in ``list`` can be used to achieve the desired effect: :: >>> from pypey import pipe >>> pipe(divmod, list, sum)(10, 3) 4 Note that ``list`` is the only exception to the rule that ``tuple`` returns will be unpacked. :param functions: a variable number of functions :return: a combined function """ if len(functions) == 1: return functions[0] return px(_pipe_functions, functions=functions)
[docs]def require(cond: bool, message: str, exception: Type[Exception] = TypeError): """ Guard clause, useful for implementing exception-raising checks concisely, especially useful in lambdas. >>> from pypey import require, pype >>> pype([1,2,'3']).do(lambda n: require(isinstance(n, int), 'not an int'), now=True) Traceback (most recent call last): ... TypeError: not an int :param cond: if ``False`` the given exception will be thrown, otherwise this function is a no-op :param message: exception message :param exception: exception to throw if ``cond`` is ``False``, defaults to ``TypeError`` :return: nothing """ if not cond: raise exception(message)
[docs]def require_val(cond: bool, message: str): """ Throws ``ValueError`` exception if ``cond`` is ``False``, equivalent to :func:`require` with ``exception=ValueError``. >>> from pypey import require_val, pype >>> pype([1,2,-3]).do(lambda n: require_val(n>0, 'not a positive number'), now=True) Traceback (most recent call last): ... ValueError: not a positive number :param cond: if ``False`` the a ValueError will be thrown, otherwise this function is a no-op :param message: the exception message :return: nothing """ require(cond, message, ValueError)
[docs]def throw(exception: Type[Exception], message: str): """ Throws given exception with given message, equivalent to built-in ``raise``. This function is useful for raising exceptions inside lambdas as ``raise`` is syntactically invalid in them. >>> from pypey import throw, pype >>> pype([1,2,3]).do(lambda n: throw(ValueError, 'test'), now=True) Traceback (most recent call last): ... ValueError: test :param exception: the exception to throw :param message: the exception message :return: nothing """ raise exception(message)
def _pipe_functions(*arg: Any, functions: Tuple[Fn[..., Any], Any]) -> Any: # created as global function to avoid issues with multiprocessing result = arg for idx, fn in enumerate(functions): result = fn(*result) if idx == 0 or (idx > 0 and fn != list and isinstance(result, tuple)) else fn(result) return result