about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/pydash/functions.py
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/pydash/functions.py
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-master.tar.gz
two version of R2R are here HEAD master
Diffstat (limited to '.venv/lib/python3.12/site-packages/pydash/functions.py')
-rw-r--r--.venv/lib/python3.12/site-packages/pydash/functions.py1461
1 files changed, 1461 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/pydash/functions.py b/.venv/lib/python3.12/site-packages/pydash/functions.py
new file mode 100644
index 00000000..30a8a607
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pydash/functions.py
@@ -0,0 +1,1461 @@
+"""
+Functions that wrap other functions.
+
+.. versionadded:: 1.0.0
+"""
+
+from __future__ import annotations
+
+from functools import cached_property
+from inspect import getfullargspec
+import itertools
+import time
+import typing as t
+
+from typing_extensions import Concatenate, Literal, ParamSpec, Protocol
+
+import pydash as pyd
+from pydash.helpers import getargcount
+
+
+__all__ = (
+    "after",
+    "ary",
+    "before",
+    "conjoin",
+    "curry",
+    "curry_right",
+    "debounce",
+    "delay",
+    "disjoin",
+    "flip",
+    "flow",
+    "flow_right",
+    "iterated",
+    "juxtapose",
+    "negate",
+    "once",
+    "over_args",
+    "partial",
+    "partial_right",
+    "rearg",
+    "spread",
+    "throttle",
+    "unary",
+    "wrap",
+)
+
+T = t.TypeVar("T")
+T1 = t.TypeVar("T1")
+T2 = t.TypeVar("T2")
+T3 = t.TypeVar("T3")
+T4 = t.TypeVar("T4")
+T5 = t.TypeVar("T5")
+P = ParamSpec("P")
+
+
+class _WithArgCount(Protocol):
+    func: t.Callable[..., t.Any]
+
+    @cached_property
+    def _argcount(self) -> t.Optional[int]:
+        return getargcount(self.func, None)
+
+
+class After(_WithArgCount, t.Generic[P, T]):
+    """Wrap a function in an after context."""
+
+    def __init__(self, func: t.Callable[P, T], n: t.SupportsInt) -> None:
+        try:
+            n = int(n)
+            assert n >= 0
+        except (ValueError, TypeError, AssertionError):
+            n = 0
+
+        self.n = n
+        self.func = func
+
+    def __call__(self, *args: P.args, **kwargs: P.kwargs) -> t.Union[T, None]:
+        """Return results of :attr:`func` after :attr:`n` calls."""
+        self.n -= 1
+
+        if self.n <= 0:
+            return self.func(*args, **kwargs)
+
+        return None
+
+
+class Ary(_WithArgCount, t.Generic[T]):
+    """Wrap a function in an ary context."""
+
+    def __init__(self, func: t.Callable[..., T], n: t.Union[t.SupportsInt, None]) -> None:
+        try:
+            # Type error would be caught
+            n = int(n)  # type: ignore
+            assert n >= 0
+        except (ValueError, TypeError, AssertionError):
+            n = None
+
+        self.n = n
+        self.func = func
+
+    def __call__(self, *args: t.Any, **kwargs: t.Any) -> T:
+        """
+        Return results of :attr:`func` with arguments capped to :attr:`n`.
+
+        Only positional arguments are capped. Any number of keyword arguments are allowed.
+        """
+        cut_args = args[: self.n] if self.n is not None else args
+
+        return self.func(*cut_args, **kwargs)  # type: ignore
+
+
+class Before(After[P, T], t.Generic[P, T]):
+    """Wrap a function in a before context."""
+
+    def __call__(self, *args: P.args, **kwargs: P.kwargs) -> t.Union[T, None]:
+        self.n -= 1
+
+        if self.n > 0:
+            return self.func(*args, **kwargs)
+
+        return None
+
+
+class Flow(t.Generic[P, T]):
+    """Wrap a function in a flow context."""
+
+    @t.overload
+    def __init__(
+        self,
+        func1: t.Callable[P, T2],
+        func2: t.Callable[[T2], T3],
+        func3: t.Callable[[T3], T4],
+        func4: t.Callable[[T4], T5],
+        func5: t.Callable[[T5], T],
+        *,
+        from_right: bool = True,
+    ) -> None: ...
+
+    @t.overload
+    def __init__(
+        self,
+        func1: t.Callable[P, T2],
+        func2: t.Callable[[T2], T3],
+        func3: t.Callable[[T3], T4],
+        func4: t.Callable[[T4], T],
+        *,
+        from_right: bool = True,
+    ) -> None: ...
+
+    @t.overload
+    def __init__(
+        self,
+        func1: t.Callable[P, T2],
+        func2: t.Callable[[T2], T3],
+        func3: t.Callable[[T3], T],
+        *,
+        from_right: bool = True,
+    ) -> None: ...
+
+    @t.overload
+    def __init__(
+        self, func1: t.Callable[P, T2], func2: t.Callable[[T2], T], *, from_right: bool = True
+    ) -> None: ...
+
+    @t.overload
+    def __init__(self, func1: t.Callable[P, T], *, from_right: bool = True) -> None: ...
+
+    def __init__(self, *funcs, from_right: bool = True) -> None:  # type: ignore
+        self.funcs = funcs
+        self._from_index = -1 if from_right else 0
+
+    def __call__(self, *args: P.args, **kwargs: P.kwargs) -> T:
+        """Return results of composing :attr:`funcs`."""
+        funcs = list(self.funcs)
+
+        result = None
+
+        while funcs:
+            result = funcs.pop(self._from_index)(*args, **kwargs)
+            # Incompatible type in assignements but needed here
+            # type safety is ensured from the `__init__` signature
+            args = (result,)  # type: ignore
+            kwargs = {}  # type: ignore
+
+        # type safety is ensured from the `__init__` signature
+        return result  # type: ignore
+
+    @cached_property
+    def _argcount(self) -> t.Optional[int]:
+        return getargcount(self.funcs[self._from_index], None)
+
+
+class Conjoin(t.Generic[T]):
+    """Wrap a set of functions in a conjoin context."""
+
+    def __init__(self, *funcs: t.Callable[[T], t.Any]) -> None:
+        self.funcs = funcs
+
+    def __call__(self, obj: t.Iterable[T]) -> bool:
+        """Return result of conjoin `obj` with :attr:`funcs` predicates."""
+
+        def iteratee(item: T) -> bool:
+            return pyd.every(self.funcs, lambda func: func(item))
+
+        return pyd.every(obj, iteratee)
+
+
+class Curry(t.Generic[T1, T]):
+    """Wrap a function in a curry context."""
+
+    def __init__(self, func, arity, args=None, kwargs=None) -> None:
+        self.func = func
+        self.arity = len(getfullargspec(func).args) if arity is None else arity
+        self.args = () if args is None else args
+        self.kwargs = {} if kwargs is None else kwargs
+
+    def __call__(self, *args, **kwargs):
+        """Store `args` and `kwargs` and call :attr:`func` if we've reached or exceeded the function
+        arity."""
+        args = self.compose_args(args)
+        kwargs.update(self.kwargs)
+
+        if (len(args) + len(kwargs)) >= self.arity:
+            args_arity = self.arity - len(kwargs)
+            args = args[: (args_arity if args_arity > 0 else 0)]
+            curried = self.func(*args, **kwargs)
+        else:
+            # NOTE: Use self.__class__ so that subclasses will use their own
+            # class to generate next iteration of call.
+            curried = self.__class__(self.func, self.arity, args, kwargs)
+
+        return curried
+
+    def compose_args(self, new_args):
+        """Combine `self.args` with `new_args` and return."""
+        return tuple(list(self.args) + list(new_args))
+
+    @cached_property
+    def _argcount(self) -> t.Optional[int]:
+        argcount = self.arity - len(self.args) - len(self.kwargs)
+        return argcount if argcount >= 0 else None
+
+
+class CurryOne(Curry[T1, T]):
+    def __call__(self, arg_one: T1) -> T:
+        return super().__call__(arg_one)  # pragma: no cover
+
+
+class CurryTwo(Curry[T1, CurryOne[T2, T]]):
+    @t.overload
+    def __call__(self, arg_one: T1) -> CurryOne[T2, T]: ...
+
+    @t.overload
+    def __call__(self, arg_one: T1, arg_two: T2) -> T: ...
+
+    def __call__(self, *args, **kwargs):
+        return super().__call__(*args, **kwargs)  # pragma: no cover
+
+
+class CurryThree(Curry[T1, CurryTwo[T2, T3, T]]):
+    @t.overload
+    def __call__(self, arg_one: T1) -> CurryTwo[T2, T3, T]: ...
+
+    @t.overload
+    def __call__(self, arg_one: T1, arg_two: T2) -> CurryOne[T3, T]: ...
+
+    @t.overload
+    def __call__(self, arg_one: T1, arg_two: T2, arg_three: T3) -> T: ...
+
+    def __call__(self, *args, **kwargs):
+        return super().__call__(*args, **kwargs)  # pragma: no cover
+
+
+class CurryFour(Curry[T1, CurryThree[T2, T3, T4, T]]):
+    @t.overload
+    def __call__(self, arg_one: T1) -> CurryThree[T2, T3, T4, T]: ...
+
+    @t.overload
+    def __call__(self, arg_one: T1, arg_two: T2) -> CurryTwo[T3, T4, T]: ...
+
+    @t.overload
+    def __call__(self, arg_one: T1, arg_two: T2, arg_three: T3) -> CurryOne[T4, T]: ...
+
+    @t.overload
+    def __call__(self, arg_one: T1, arg_two: T2, arg_three: T3, arg_four: T4) -> T: ...
+
+    def __call__(self, *args, **kwargs):
+        return super().__call__(*args, **kwargs)  # pragma: no cover
+
+
+class CurryFive(Curry[T1, CurryFour[T2, T3, T4, T5, T]]):
+    @t.overload
+    def __call__(self, arg_one: T1) -> CurryFour[T2, T3, T4, T5, T]: ...
+
+    @t.overload
+    def __call__(self, arg_one: T1, arg_two: T2) -> CurryThree[T3, T4, T5, T]: ...
+
+    @t.overload
+    def __call__(self, arg_one: T1, arg_two: T2, arg_three: T3) -> CurryTwo[T4, T5, T]: ...
+
+    @t.overload
+    def __call__(
+        self, arg_one: T1, arg_two: T2, arg_three: T3, arg_four: T4
+    ) -> CurryOne[T5, T]: ...
+
+    @t.overload
+    def __call__(
+        self, arg_one: T1, arg_two: T2, arg_three: T3, arg_four: T4, arg_five: T5
+    ) -> T: ...
+
+    def __call__(self, *args, **kwargs):
+        return super().__call__(*args, **kwargs)  # pragma: no cover
+
+
+class CurryRight(Curry[T5, T]):
+    """Wrap a function in a curry-right context."""
+
+    def compose_args(self, new_args):
+        return tuple(list(new_args) + list(self.args))
+
+
+class CurryRightOne(CurryRight[T5, T]):
+    def __call__(self, arg_one: T5) -> T:
+        return super().__call__(arg_one)  # pragma: no cover
+
+
+class CurryRightTwo(CurryRight[T5, CurryRightOne[T4, T]]):
+    @t.overload
+    def __call__(self, arg_one: T5) -> CurryRightOne[T4, T]: ...
+
+    @t.overload
+    def __call__(self, arg_one: T5, arg_two: T4) -> T: ...
+
+    def __call__(self, *args, **kwargs):
+        return super().__call__(*args, **kwargs)  # pragma: no cover
+
+
+class CurryRightThree(CurryRight[T5, CurryRightTwo[T4, T3, T]]):
+    @t.overload
+    def __call__(self, arg_one: T5) -> CurryRightTwo[T4, T3, T]: ...
+
+    @t.overload
+    def __call__(self, arg_one: T5, arg_two: T4) -> CurryRightOne[T3, T]: ...
+
+    @t.overload
+    def __call__(self, arg_one: T5, arg_two: T4, arg_three: T3) -> T: ...
+
+    def __call__(self, *args, **kwargs):
+        return super().__call__(*args, **kwargs)  # pragma: no cover
+
+
+class CurryRightFour(CurryRight[T5, CurryRightThree[T4, T3, T2, T]]):
+    @t.overload
+    def __call__(self, arg_one: T5) -> CurryRightThree[T4, T3, T2, T]: ...
+
+    @t.overload
+    def __call__(self, arg_one: T5, arg_two: T4) -> CurryRightTwo[T3, T2, T]: ...
+
+    @t.overload
+    def __call__(self, arg_one: T5, arg_two: T4, arg_three: T3) -> CurryRightOne[T2, T]: ...
+
+    @t.overload
+    def __call__(self, arg_one: T5, arg_two: T4, arg_three: T3, arg_four: T2) -> T: ...
+
+    def __call__(self, *args, **kwargs):
+        return super().__call__(*args, **kwargs)  # pragma: no cover
+
+
+class CurryRightFive(CurryRight[T5, CurryRightFour[T4, T3, T2, T1, T]]):
+    @t.overload
+    def __call__(self, arg_one: T5) -> CurryRightFour[T4, T3, T2, T1, T]: ...
+
+    @t.overload
+    def __call__(self, arg_one: T5, arg_two: T4) -> CurryRightThree[T3, T2, T1, T]: ...
+
+    @t.overload
+    def __call__(self, arg_one: T5, arg_two: T4, arg_three: T3) -> CurryRightTwo[T2, T1, T]: ...
+
+    @t.overload
+    def __call__(
+        self, arg_one: T5, arg_two: T4, arg_three: T3, arg_four: T2
+    ) -> CurryRightOne[T1, T]: ...
+
+    @t.overload
+    def __call__(
+        self, arg_one: T5, arg_two: T4, arg_three: T3, arg_four: T2, arg_five: T1
+    ) -> T: ...
+
+    def __call__(self, *args, **kwargs):
+        return super().__call__(*args, **kwargs)  # pragma: no cover
+
+
+class Debounce(_WithArgCount, t.Generic[P, T]):
+    """Wrap a function in a debounce context."""
+
+    def __init__(
+        self, func: t.Callable[P, T], wait: int, max_wait: t.Union[int, Literal[False]] = False
+    ) -> None:
+        self.func = func
+        self.wait = wait
+        self.max_wait = max_wait
+
+        self.last_result: t.Union[T, None] = None
+
+        # Initialize last_* times to be prior to the wait periods so that func
+        # is primed to be executed on first call.
+        self.last_call = pyd.now() - self.wait
+        self.last_execution = pyd.now() - max_wait if pyd.is_number(max_wait) else None
+
+    def __call__(self, *args: P.args, **kwargs: P.kwargs) -> T:
+        """
+        Execute :attr:`func` if function hasn't been called within last :attr:`wait` milliseconds or
+        in last :attr:`max_wait` milliseconds.
+
+        Return results of last successful call.
+        """
+        present = pyd.now()
+
+        if (present - self.last_call) >= self.wait or (
+            self.max_wait and (present - self.last_execution) >= self.max_wait  # type: ignore
+        ):
+            self.last_result = self.func(*args, **kwargs)
+            self.last_execution = present
+
+        self.last_call = present
+
+        # It will be set after first call, cannot be `None` anymore
+        return self.last_result  # type: ignore
+
+
+class Disjoin(t.Generic[T]):
+    """Wrap a set of functions in a disjoin context."""
+
+    def __init__(self, *funcs: t.Callable[[T], t.Any]) -> None:
+        self.funcs = funcs
+
+    def __call__(self, obj: t.Iterable[T]) -> bool:
+        """Return result of disjoin `obj` with :attr:`funcs` predicates."""
+
+        def iteratee(item: T) -> bool:
+            return pyd.some(self.funcs, lambda func: func(item))
+
+        return pyd.some(obj, iteratee)
+
+
+class Flip(_WithArgCount):
+    """Wrap a function in a flip context."""
+
+    def __init__(self, func: t.Callable[..., t.Any]) -> None:
+        self.func = func
+
+    def __call__(self, *args, **kwargs):
+        return self.func(*reversed(args), **kwargs)
+
+
+class Iterated(t.Generic[T]):
+    """Wrap a function in an iterated context."""
+
+    def __init__(self, func: t.Callable[[T], T]) -> None:
+        self.func = func
+
+    def _iteration(self, initial: T) -> t.Iterator[T]:
+        """Iterator that composing :attr:`func` with itself."""
+        value = initial
+        while True:
+            value = self.func(value)
+            yield value
+
+    def __call__(self, initial: T, n: int) -> T:
+        """Return value of calling :attr:`func` `n` times using `initial` as seed value."""
+        value = initial
+        iteration = self._iteration(value)
+
+        for _ in range(n):
+            value = next(iteration)
+
+        return value
+
+
+class Juxtapose(t.Generic[P, T]):
+    """Wrap a function in a juxtapose context."""
+
+    def __init__(self, *funcs: t.Callable[P, T]) -> None:
+        self.funcs = funcs
+
+    def __call__(self, *objs: P.args, **kwargs: P.kwargs) -> t.List[T]:
+        return [func(*objs, **kwargs) for func in self.funcs]
+
+    @cached_property
+    def _argcount(self) -> t.Optional[int]:
+        return getargcount(self.funcs[0], None) if self.funcs else None
+
+
+class OverArgs(_WithArgCount):
+    """Wrap a function in an over_args context."""
+
+    def __init__(self, func: t.Callable[..., t.Any], *transforms: t.Callable[..., t.Any]) -> None:
+        self.func = func
+        self.transforms = pyd.flatten(transforms)
+
+    def __call__(self, *args):
+        args = (self.transforms[idx](args) for idx, args in enumerate(args))
+        return self.func(*args)
+
+
+class Negate(_WithArgCount, t.Generic[P]):
+    """Wrap a function in a negate context."""
+
+    def __init__(self, func: t.Callable[P, t.Any]) -> None:
+        self.func = func
+
+    def __call__(self, *args: P.args, **kwargs: P.kwargs) -> bool:
+        """Return negated results of calling :attr:`func`."""
+        return not self.func(*args, **kwargs)
+
+
+class Once(_WithArgCount, t.Generic[P, T]):
+    """Wrap a function in a once context."""
+
+    def __init__(self, func: t.Callable[P, T]) -> None:
+        self.func = func
+        self.result: t.Union[T, None] = None
+        self.called = False
+
+    def __call__(self, *args: P.args, **kwargs: P.kwargs) -> T:
+        """Return results from the first call of :attr:`func`."""
+        if not self.called:
+            self.result = self.func(*args, **kwargs)
+            self.called = True
+
+        # At this point the result will be set, cannot be `None` anymore
+        return self.result  # type: ignore
+
+
+class Partial(_WithArgCount, t.Generic[T]):
+    """Wrap a function in a partial context."""
+
+    def __init__(
+        self, func: t.Callable[..., T], args: t.Any, kwargs: t.Any = None, from_right: bool = False
+    ) -> None:
+        self.func = func
+        self.args = args
+        self.kwargs = kwargs or {}
+        self.from_right = from_right
+
+    def __call__(self, *args: t.Any, **kwargs: t.Any) -> T:
+        """
+        Return results from :attr:`func` with :attr:`args` + `args`.
+
+        Apply arguments from left or right depending on :attr:`from_right`.
+        """
+        if self.from_right:
+            args = itertools.chain(args, self.args)  # type: ignore
+        else:
+            args = itertools.chain(self.args, args)  # type: ignore
+
+        kwargs = {**self.kwargs, **kwargs}
+
+        return self.func(*args, **kwargs)
+
+    @cached_property
+    def _argcount(self) -> t.Optional[int]:
+        func_argcount = getargcount(self.func, None)
+        if func_argcount is None:
+            return None
+        argcount = func_argcount - len(self.args) - len(self.kwargs)
+        return argcount if argcount >= 0 else None
+
+
+class Rearg(_WithArgCount, t.Generic[P, T]):
+    """Wrap a function in a rearg context."""
+
+    def __init__(self, func: t.Callable[P, T], *indexes: int) -> None:
+        self.func = func
+
+        # Index `indexes` by the index value, so we can do a lookup mapping by walking the function
+        # arguments.
+        self.indexes = {
+            src_index: dest_index for dest_index, src_index in enumerate(pyd.flatten(indexes))
+        }
+
+    def __call__(self, *args: P.args, **kwargs: P.kwargs) -> T:
+        """Return results from :attr:`func` using rearranged arguments."""
+        reargs = {}
+        rest = []
+
+        # Walk arguments to ensure each one is added to the final argument list.
+        for src_index, arg in enumerate(args):
+            # NOTE: dest_index will range from 0 to len(indexes).
+            dest_index = self.indexes.get(src_index)
+
+            if dest_index is not None:
+                # Remap argument index.
+                reargs[dest_index] = arg
+            else:
+                # Argumnet index is not contained in `indexes` so stick in the back.
+                rest.append(arg)
+
+        args = itertools.chain((reargs[key] for key in sorted(reargs)), rest)  # type: ignore
+
+        return self.func(*args, **kwargs)
+
+
+class Spread(t.Generic[T]):
+    """Wrap a function in a spread context."""
+
+    def __init__(self, func: t.Callable[..., T]) -> None:
+        self.func = func
+
+    def __call__(self, args: t.Iterable[t.Any]) -> T:
+        """Return results from :attr:`func` using array of `args` provided."""
+        return self.func(*args)
+
+
+class Throttle(_WithArgCount, t.Generic[P, T]):
+    """Wrap a function in a throttle context."""
+
+    def __init__(self, func: t.Callable[P, T], wait: int) -> None:
+        self.func = func
+        self.wait = wait
+
+        self.last_result: t.Union[T, None] = None
+        self.last_execution = pyd.now() - self.wait
+
+    def __call__(self, *args: P.args, **kwargs: P.kwargs) -> T:
+        """
+        Execute :attr:`func` if function hasn't been called within last :attr:`wait` milliseconds.
+
+        Return results of last successful call.
+        """
+        present = pyd.now()
+
+        if (present - self.last_execution) >= self.wait:
+            self.last_result = self.func(*args, **kwargs)
+            self.last_execution = present
+
+        # The last result will be filled on first execution, so it is always `T`
+        return self.last_result  # type: ignore
+
+
+def after(func: t.Callable[P, T], n: t.SupportsInt) -> After[P, T]:
+    """
+    Creates a function that executes `func`, with the arguments of the created function, only after
+    being called `n` times.
+
+    Args:
+        func: Function to execute.
+        n: Number of times `func` must be called before it is executed.
+
+    Returns:
+        Function wrapped in an :class:`After` context.
+
+    Example:
+
+        >>> func = lambda a, b, c: (a, b, c)
+        >>> after_func = after(func, 3)
+        >>> after_func(1, 2, 3)
+        >>> after_func(1, 2, 3)
+        >>> after_func(1, 2, 3)
+        (1, 2, 3)
+        >>> after_func(4, 5, 6)
+        (4, 5, 6)
+
+    .. versionadded:: 1.0.0
+
+    .. versionchanged:: 3.0.0
+        Reordered arguments to make `func` first.
+    """
+    return After(func, n)
+
+
+def ary(func: t.Callable[..., T], n: t.Union[t.SupportsInt, None]) -> Ary[T]:
+    """
+    Creates a function that accepts up to `n` arguments ignoring any additional arguments. Only
+    positional arguments are capped. All keyword arguments are allowed through.
+
+    Args:
+        func: Function to cap arguments for.
+        n: Number of arguments to accept.
+
+    Returns:
+        Function wrapped in an :class:`Ary` context.
+
+    Example:
+
+        >>> func = lambda a, b, c=0, d=5: (a, b, c, d)
+        >>> ary_func = ary(func, 2)
+        >>> ary_func(1, 2, 3, 4, 5, 6)
+        (1, 2, 0, 5)
+        >>> ary_func(1, 2, 3, 4, 5, 6, c=10, d=20)
+        (1, 2, 10, 20)
+
+    .. versionadded:: 3.0.0
+    """
+    return Ary(func, n)
+
+
+def before(func: t.Callable[P, T], n: t.SupportsInt) -> Before[P, T]:
+    """
+    Creates a function that executes `func`, with the arguments of the created function, until it
+    has been called `n` times.
+
+    Args:
+        func: Function to execute.
+        n: Number of times `func` may be executed.
+
+    Returns:
+        Function wrapped in an :class:`Before` context.
+
+    Example:
+
+        >>> func = lambda a, b, c: (a, b, c)
+        >>> before_func = before(func, 3)
+        >>> before_func(1, 2, 3)
+        (1, 2, 3)
+        >>> before_func(1, 2, 3)
+        (1, 2, 3)
+        >>> before_func(1, 2, 3)
+        >>> before_func(1, 2, 3)
+
+    .. versionadded:: 1.1.0
+
+    .. versionchanged:: 3.0.0
+        Reordered arguments to make `func` first.
+    """
+    return Before(func, n)
+
+
+def conjoin(*funcs: t.Callable[[T], t.Any]) -> t.Callable[[t.Iterable[T]], bool]:
+    """
+    Creates a function that composes multiple predicate functions into a single predicate that tests
+    whether **all** elements of an object pass each predicate.
+
+    Args:
+        *funcs: Function(s) to conjoin.
+
+    Returns:
+        Function(s) wrapped in a :class:`Conjoin` context.
+
+    Example:
+
+        >>> conjoiner = conjoin(lambda x: isinstance(x, int), lambda x: x > 3)
+        >>> conjoiner([1, 2, 3])
+        False
+        >>> conjoiner([1.0, 2, 1])
+        False
+        >>> conjoiner([4.0, 5, 6])
+        False
+        >>> conjoiner([4, 5, 6])
+        True
+
+    .. versionadded:: 2.0.0
+    """
+    return Conjoin(*funcs)
+
+
+@t.overload
+def curry(func: t.Callable[[T1], T], arity: t.Union[int, None] = None) -> CurryOne[T1, T]: ...
+
+
+@t.overload
+def curry(
+    func: t.Callable[[T1, T2], T], arity: t.Union[int, None] = None
+) -> CurryTwo[T1, T2, T]: ...
+
+
+@t.overload
+def curry(
+    func: t.Callable[[T1, T2, T3], T], arity: t.Union[int, None] = None
+) -> CurryThree[T1, T2, T3, T]: ...
+
+
+@t.overload
+def curry(
+    func: t.Callable[[T1, T2, T3, T4], T], arity: t.Union[int, None] = None
+) -> CurryFour[T1, T2, T3, T4, T]: ...
+
+
+@t.overload
+def curry(
+    func: t.Callable[[T1, T2, T3, T4, T5], T], arity: t.Union[int, None] = None
+) -> CurryFive[T1, T2, T3, T4, T5, T]: ...
+
+
+def curry(func, arity=None):
+    """
+    Creates a function that accepts one or more arguments of `func` that when invoked either
+    executes `func` returning its result (if all `func` arguments have been provided) or returns a
+    function that accepts one or more of the remaining `func` arguments, and so on.
+
+    Args:
+        func: Function to curry.
+        arity: Number of function arguments that can be accepted by curried
+            function. Default is to use the number of arguments that are accepted by `func`.
+
+    Returns:
+        Function wrapped in a :class:`Curry` context.
+
+    Example:
+
+        >>> func = lambda a, b, c: (a, b, c)
+        >>> currier = curry(func)
+        >>> currier = currier(1)
+        >>> assert isinstance(currier, Curry)
+        >>> currier = currier(2)
+        >>> assert isinstance(currier, Curry)
+        >>> currier = currier(3)
+        >>> currier
+        (1, 2, 3)
+
+    .. versionadded:: 1.0.0
+    """
+    return Curry(func, arity)
+
+
+@t.overload
+def curry_right(
+    func: t.Callable[[T1], T], arity: t.Union[int, None] = None
+) -> CurryRightOne[T1, T]: ...
+
+
+@t.overload
+def curry_right(
+    func: t.Callable[[T1, T2], T], arity: t.Union[int, None] = None
+) -> CurryRightTwo[T2, T1, T]: ...
+
+
+@t.overload
+def curry_right(
+    func: t.Callable[[T1, T2, T3], T], arity: t.Union[int, None] = None
+) -> CurryRightThree[T3, T2, T1, T]: ...
+
+
+@t.overload
+def curry_right(
+    func: t.Callable[[T1, T2, T3, T4], T], arity: t.Union[int, None] = None
+) -> CurryRightFour[T4, T3, T2, T1, T]: ...
+
+
+@t.overload
+def curry_right(
+    func: t.Callable[[T1, T2, T3, T4, T5], T],
+) -> CurryRightFive[T5, T4, T3, T2, T1, T]: ...
+
+
+def curry_right(func, arity=None):
+    """
+    This method is like :func:`curry` except that arguments are applied to `func` in the manner of
+    :func:`partial_right` instead of :func:`partial`.
+
+    Args:
+        func: Function to curry.
+        arity: Number of function arguments that can be accepted by curried
+            function. Default is to use the number of arguments that are accepted by `func`.
+
+    Returns:
+        Function wrapped in a :class:`CurryRight` context.
+
+    Example:
+
+        >>> func = lambda a, b, c: (a, b, c)
+        >>> currier = curry_right(func)
+        >>> currier = currier(1)
+        >>> assert isinstance(currier, CurryRight)
+        >>> currier = currier(2)
+        >>> assert isinstance(currier, CurryRight)
+        >>> currier = currier(3)
+        >>> currier
+        (3, 2, 1)
+
+    .. versionadded:: 1.1.0
+    """
+    return CurryRight(func, arity)
+
+
+def debounce(
+    func: t.Callable[P, T], wait: int, max_wait: t.Union[int, Literal[False]] = False
+) -> Debounce[P, T]:
+    """
+    Creates a function that will delay the execution of `func` until after `wait` milliseconds have
+    elapsed since the last time it was invoked. Subsequent calls to the debounced function will
+    return the result of the last `func` call.
+
+    Args:
+        func: Function to execute.
+        wait: Milliseconds to wait before executing `func`.
+        max_wait (optional): Maximum time to wait before executing `func`.
+
+    Returns:
+        Function wrapped in a :class:`Debounce` context.
+
+    .. versionadded:: 1.0.0
+    """
+    return Debounce(func, wait, max_wait=max_wait)
+
+
+def delay(func: t.Callable[P, T], wait: int, *args: "P.args", **kwargs: "P.kwargs") -> T:
+    """
+    Executes the `func` function after `wait` milliseconds. Additional arguments will be provided to
+    `func` when it is invoked.
+
+    Args:
+        func: Function to execute.
+        wait: Milliseconds to wait before executing `func`.
+        *args: Arguments to pass to `func`.
+        **kwargs: Keyword arguments to pass to `func`.
+
+    Returns:
+        Return from `func`.
+
+    .. versionadded:: 1.0.0
+    """
+    time.sleep(wait / 1000.0)
+    return func(*args, **kwargs)
+
+
+def disjoin(*funcs: t.Callable[[T], t.Any]) -> Disjoin[T]:
+    """
+    Creates a function that composes multiple predicate functions into a single predicate that tests
+    whether **any** elements of an object pass each predicate.
+
+    Args:
+        *funcs: Function(s) to disjoin.
+
+    Returns:
+        Function(s) wrapped in a :class:`Disjoin` context.
+
+    Example:
+
+        >>> disjoiner = disjoin(lambda x: isinstance(x, float),\
+                                lambda x: isinstance(x, int))
+        >>> disjoiner([1, '2', '3'])
+        True
+        >>> disjoiner([1.0, '2', '3'])
+        True
+        >>> disjoiner(['1', '2', '3'])
+        False
+
+    .. versionadded:: 2.0.0
+    """
+    return Disjoin(*funcs)
+
+
+@t.overload
+def flip(func: t.Callable[[T1, T2, T3, T4, T5], T]) -> t.Callable[[T5, T4, T3, T2, T1], T]: ...
+
+
+@t.overload
+def flip(func: t.Callable[[T1, T2, T3, T4], T]) -> t.Callable[[T4, T3, T2, T1], T]: ...
+
+
+@t.overload
+def flip(func: t.Callable[[T1, T2, T3], T]) -> t.Callable[[T3, T2, T1], T]: ...
+
+
+@t.overload
+def flip(func: t.Callable[[T1, T2], T]) -> t.Callable[[T2, T1], T]: ...
+
+
+@t.overload
+def flip(func: t.Callable[[T1], T]) -> t.Callable[[T1], T]: ...
+
+
+def flip(func: t.Callable[..., t.Any]) -> t.Callable[..., t.Any]:
+    """
+    Creates a function that invokes the method with arguments reversed.
+
+    Args:
+        func: Function to flip arguments for.
+
+    Returns:
+        Function wrapped in a :class:`Flip` context.
+
+    Example:
+
+        >>> flipped = flip(lambda *args: args)
+        >>> flipped(1, 2, 3, 4)
+        (4, 3, 2, 1)
+        >>> flipped = flip(lambda *args: [i * 2 for i in args])
+        >>> flipped(1, 2, 3, 4)
+        [8, 6, 4, 2]
+
+    .. versionadded:: 4.0.0
+    """
+    return Flip(func)
+
+
+@t.overload
+def flow(
+    func1: t.Callable[P, T2],
+    func2: t.Callable[[T2], T3],
+    func3: t.Callable[[T3], T4],
+    func4: t.Callable[[T4], T5],
+    func5: t.Callable[[T5], T],
+) -> Flow[P, T]: ...
+
+
+@t.overload
+def flow(
+    func1: t.Callable[P, T2],
+    func2: t.Callable[[T2], T3],
+    func3: t.Callable[[T3], T4],
+    func4: t.Callable[[T4], T],
+) -> Flow[P, T]: ...
+
+
+@t.overload
+def flow(
+    func1: t.Callable[P, T2],
+    func2: t.Callable[[T2], T3],
+    func3: t.Callable[[T3], T],
+) -> Flow[P, T]: ...
+
+
+@t.overload
+def flow(func1: t.Callable[P, T2], func2: t.Callable[[T2], T]) -> Flow[P, T]: ...
+
+
+@t.overload
+def flow(func1: t.Callable[P, T]) -> Flow[P, T]: ...
+
+
+def flow(*funcs):
+    """
+    Creates a function that is the composition of the provided functions, where each successive
+    invocation is supplied the return value of the previous. For example, composing the functions
+    ``f()``, ``g()``, and ``h()`` produces ``h(g(f()))``.
+
+    Args:
+        *funcs: Function(s) to compose.
+
+    Returns:
+        Function(s) wrapped in a :class:`Flow` context.
+
+    Example:
+
+        >>> mult_5 = lambda x: x * 5
+        >>> div_10 = lambda x: x / 10.0
+        >>> pow_2 = lambda x: x**2
+        >>> ops = flow(sum, mult_5, div_10, pow_2)
+        >>> ops([1, 2, 3, 4])
+        25.0
+
+    .. versionadded:: 2.0.0
+
+    .. versionchanged:: 2.3.1
+        Added :func:`pipe` as alias.
+
+    .. versionchanged:: 4.0.0
+        Removed alias ``pipe``.
+    """
+    return Flow(*funcs, from_right=False)
+
+
+@t.overload
+def flow_right(
+    func5: t.Callable[[T4], T],
+    func4: t.Callable[[T3], T4],
+    func3: t.Callable[[T2], T3],
+    func2: t.Callable[[T1], T2],
+    func1: t.Callable[P, T1],
+) -> Flow[P, T]: ...
+
+
+@t.overload
+def flow_right(
+    func4: t.Callable[[T3], T],
+    func3: t.Callable[[T2], T3],
+    func2: t.Callable[[T1], T2],
+    func1: t.Callable[P, T1],
+) -> Flow[P, T]: ...
+
+
+@t.overload
+def flow_right(
+    func3: t.Callable[[T2], T],
+    func2: t.Callable[[T1], T2],
+    func1: t.Callable[P, T1],
+) -> Flow[P, T]: ...
+
+
+@t.overload
+def flow_right(func2: t.Callable[[T1], T], func1: t.Callable[P, T1]) -> Flow[P, T]: ...
+
+
+@t.overload
+def flow_right(func1: t.Callable[P, T]) -> Flow[P, T]: ...
+
+
+def flow_right(*funcs):
+    """
+    This function is like :func:`flow` except that it creates a function that invokes the provided
+    functions from right to left. For example, composing the functions ``f()``, ``g()``, and ``h()``
+    produces ``f(g(h()))``.
+
+    Args:
+        *funcs: Function(s) to compose.
+
+    Returns:
+        Function(s) wrapped in a :class:`Flow` context.
+
+    Example:
+
+        >>> mult_5 = lambda x: x * 5
+        >>> div_10 = lambda x: x / 10.0
+        >>> pow_2 = lambda x: x**2
+        >>> ops = flow_right(mult_5, div_10, pow_2, sum)
+        >>> ops([1, 2, 3, 4])
+        50.0
+
+    .. versionadded:: 1.0.0
+
+    .. versionchanged:: 2.0.0
+        Added :func:`flow_right` and made :func:`compose` an alias.
+
+    .. versionchanged:: 2.3.1
+        Added :func:`pipe_right` as alias.
+
+    .. versionchanged:: 4.0.0
+        Removed aliases ``pipe_right`` and ``compose``.
+    """
+    return Flow(*funcs, from_right=True)
+
+
+def iterated(func: t.Callable[[T], T]) -> Iterated[T]:
+    """
+    Creates a function that is composed with itself. Each call to the iterated function uses the
+    previous function call's result as input. Returned :class:`Iterated` instance can be called with
+    ``(initial, n)`` where `initial` is the initial value to seed `func` with and `n` is the number
+    of times to call `func`.
+
+    Args:
+        func: Function to iterate.
+
+    Returns:
+        Function wrapped in a :class:`Iterated` context.
+
+    Example:
+
+        >>> doubler = iterated(lambda x: x * 2)
+        >>> doubler(4, 5)
+        128
+        >>> doubler(3, 9)
+        1536
+
+    .. versionadded:: 2.0.0
+    """
+    return Iterated(func)
+
+
+def juxtapose(*funcs: t.Callable[P, T]) -> Juxtapose[P, T]:
+    """
+    Creates a function whose return value is a list of the results of calling each `funcs` with the
+    supplied arguments.
+
+    Args:
+        *funcs: Function(s) to juxtapose.
+
+    Returns:
+        Function wrapped in a :class:`Juxtapose` context.
+
+    Example:
+
+        >>> double = lambda x: x * 2
+        >>> triple = lambda x: x * 3
+        >>> quadruple = lambda x: x * 4
+        >>> juxtapose(double, triple, quadruple)(5)
+        [10, 15, 20]
+
+
+    .. versionadded:: 2.0.0
+    """
+    return Juxtapose(*funcs)
+
+
+def negate(func: t.Callable[P, t.Any]) -> Negate[P]:
+    """
+    Creates a function that negates the result of the predicate `func`. The `func` function is
+    executed with the arguments of the created function.
+
+    Args:
+        func: Function to negate execute.
+
+    Returns:
+        Function wrapped in a :class:`Negate` context.
+
+    Example:
+
+        >>> not_is_number = negate(lambda x: isinstance(x, (int, float)))
+        >>> not_is_number(1)
+        False
+        >>> not_is_number("1")
+        True
+
+    .. versionadded:: 1.1.0
+    """
+    return Negate(func)
+
+
+def once(func: t.Callable[P, T]) -> Once[P, T]:
+    """
+    Creates a function that is restricted to execute `func` once. Repeat calls to the function will
+    return the value of the first call.
+
+    Args:
+        func: Function to execute.
+
+    Returns:
+        Function wrapped in a :class:`Once` context.
+
+    Example:
+
+        >>> oncer = once(lambda *args: args[0])
+        >>> oncer(5)
+        5
+        >>> oncer(6)
+        5
+
+    .. versionadded:: 1.0.0
+    """
+    return Once(func)
+
+
+@t.overload
+def over_args(
+    func: t.Callable[[T1, T2, T3, T4, T5], T],
+    transform_one: t.Callable[[T1], T1],
+    transform_two: t.Callable[[T2], T2],
+    transform_three: t.Callable[[T3], T3],
+    transform_four: t.Callable[[T4], T4],
+    transform_five: t.Callable[[T5], T5],
+) -> t.Callable[[T1, T2, T3, T4, T5], T]: ...
+
+
+@t.overload
+def over_args(
+    func: t.Callable[[T1, T2, T3, T4], T],
+    transform_one: t.Callable[[T1], T1],
+    transform_two: t.Callable[[T2], T2],
+    transform_three: t.Callable[[T3], T3],
+    transform_four: t.Callable[[T4], T4],
+) -> t.Callable[[T1, T2, T3, T4], T]: ...
+
+
+@t.overload
+def over_args(
+    func: t.Callable[[T1, T2, T3], T],
+    transform_one: t.Callable[[T1], T1],
+    transform_two: t.Callable[[T2], T2],
+    transform_three: t.Callable[[T3], T3],
+) -> t.Callable[[T1, T2, T3], T]: ...
+
+
+@t.overload
+def over_args(
+    func: t.Callable[[T1, T2], T],
+    transform_one: t.Callable[[T1], T1],
+    transform_two: t.Callable[[T2], T2],
+) -> t.Callable[[T1, T2], T]: ...
+
+
+@t.overload
+def over_args(
+    func: t.Callable[[T1], T],
+    transform_one: t.Callable[[T1], T1],
+) -> t.Callable[[T1], T]: ...
+
+
+def over_args(func, *transforms):
+    """
+    Creates a function that runs each argument through a corresponding transform function.
+
+    Args:
+        func: Function to wrap.
+        *transforms: Functions to transform arguments, specified as individual functions
+            or lists of functions.
+
+    Returns:
+        Function wrapped in a :class:`OverArgs` context.
+
+    Example:
+
+        >>> squared = lambda x: x**2
+        >>> double = lambda x: x * 2
+        >>> modder = over_args(lambda x, y: [x, y], squared, double)
+        >>> modder(5, 10)
+        [25, 20]
+
+    .. versionadded:: 3.3.0
+
+    .. versionchanged:: 4.0.0
+        Renamed from ``mod_args`` to ``over_args``.
+    """
+    return OverArgs(func, *transforms)
+
+
+def partial(func: t.Callable[..., T], *args: t.Any, **kwargs: t.Any) -> Partial[T]:
+    """
+    Creates a function that, when called, invokes `func` with any additional partial arguments
+    prepended to those provided to the new function.
+
+    Args:
+        func: Function to execute.
+        *args: Partial arguments to prepend to function call.
+        **kwargs: Partial keyword arguments to bind to function call.
+
+    Returns:
+        Function wrapped in a :class:`Partial` context.
+
+    Example:
+
+        >>> dropper = partial(lambda array, n: array[n:], [1, 2, 3, 4])
+        >>> dropper(2)
+        [3, 4]
+        >>> dropper(1)
+        [2, 3, 4]
+        >>> myrest = partial(lambda array, n: array[n:], n=1)
+        >>> myrest([1, 2, 3, 4])
+        [2, 3, 4]
+
+    .. versionadded:: 1.0.0
+    """
+    return Partial(func, args, kwargs)
+
+
+def partial_right(func: t.Callable[..., T], *args: t.Any, **kwargs: t.Any) -> Partial[T]:
+    """
+    This method is like :func:`partial` except that partial arguments are appended to those provided
+    to the new function.
+
+    Args:
+        func: Function to execute.
+        *args: Partial arguments to append to function call.
+        **kwargs: Partial keyword arguments to bind to function call.
+
+    Returns:
+        Function wrapped in a :class:`Partial` context.
+
+    Example:
+
+        >>> myrest = partial_right(lambda array, n: array[n:], 1)
+        >>> myrest([1, 2, 3, 4])
+        [2, 3, 4]
+
+    .. versionadded:: 1.0.0
+    """
+    return Partial(func, args, kwargs, from_right=True)
+
+
+def rearg(func: t.Callable[P, T], *indexes: int) -> Rearg[P, T]:
+    """
+    Creates a function that invokes `func` with arguments arranged according to the specified
+    indexes where the argument value at the first index is provided as the first argument, the
+    argument value at the second index is provided as the second argument, and so on.
+
+    Args:
+        func: Function to rearrange arguments for.
+        *indexes: The arranged argument indexes.
+
+    Returns:
+        Function wrapped in a :class:`Rearg` context.
+
+    Example:
+
+        >>> jumble = rearg(lambda *args: args, 1, 2, 3)
+        >>> jumble(1, 2, 3)
+        (2, 3, 1)
+        >>> jumble("a", "b", "c", "d", "e")
+        ('b', 'c', 'd', 'a', 'e')
+
+    .. versionadded:: 3.0.0
+    """
+    return Rearg(func, *indexes)
+
+
+def spread(func: t.Callable[..., T]) -> Spread[T]:
+    """
+    Creates a function that invokes `func` with the array of arguments provided to the created
+    function.
+
+    Args:
+        func: Function to spread.
+
+    Returns:
+        Function wrapped in a :class:`Spread` context.
+
+    Example:
+
+        >>> greet = spread(lambda *people: "Hello " + ", ".join(people) + "!")
+        >>> greet(["Mike", "Don", "Leo"])
+        'Hello Mike, Don, Leo!'
+
+    .. versionadded:: 3.1.0
+    """
+    return Spread(func)
+
+
+def throttle(func: t.Callable[P, T], wait: int) -> Throttle[P, T]:
+    """
+    Creates a function that, when executed, will only call the `func` function at most once per
+    every `wait` milliseconds. Subsequent calls to the throttled function will return the result of
+    the last `func` call.
+
+    Args:
+        func: Function to throttle.
+        wait: Milliseconds to wait before calling `func` again.
+
+    Returns:
+        Results of last `func` call.
+
+    .. versionadded:: 1.0.0
+    """
+    return Throttle(func, wait)
+
+
+def unary(func: t.Callable[..., T]) -> Ary[T]:
+    """
+    Creates a function that accepts up to one argument, ignoring any additional arguments.
+
+    Args:
+        func: Function to cap arguments for.
+
+    Returns:
+        Function wrapped in an :class:`Ary` context.
+
+    Example:
+
+        >>> func = lambda a, b=1, c=0, d=5: (a, b, c, d)
+        >>> unary_func = unary(func)
+        >>> unary_func(1, 2, 3, 4, 5, 6)
+        (1, 1, 0, 5)
+        >>> unary_func(1, 2, 3, 4, 5, 6, b=0, c=10, d=20)
+        (1, 0, 10, 20)
+
+    .. versionadded:: 4.0.0
+    """
+    return Ary(func, 1)
+
+
+def wrap(value: T1, func: t.Callable[Concatenate[T1, P], T]) -> Partial[T]:
+    """
+    Creates a function that provides value to the wrapper function as its first argument. Additional
+    arguments provided to the function are appended to those provided to the wrapper function.
+
+    Args:
+        value: Value provided as first argument to function call.
+        func: Function to execute.
+
+    Returns:
+        Function wrapped in a :class:`Partial` context.
+
+    Example:
+
+        >>> wrapper = wrap("hello", lambda *args: args)
+        >>> wrapper(1, 2)
+        ('hello', 1, 2)
+
+    .. versionadded:: 1.0.0
+    """
+    return Partial(func, (value,))