Source code for florin.closure

"""Closure decorator for delayed processing.

Functions
---------
florinate
    Decorator to wrap arbitrary functions and enable delayed evaluation.

"""

from collections import Sequence
import functools

from florin.context import FlorinContext


[docs]def florinate(func): """Decorator to wrap arbitrary functions and enable delayed evaluation. Parameters ---------- func : callable The function/Python callable to wrap. Returns ------- wrapper : callable The wrapped ``func`` which stores any arguments passed to ``func`` and may be called on new data at a future time. Notes ----- ``florinate`` is essentially a rebranding of functools.partial to allow passing the deferred arguments at the front of the call instead of the tail. This conforms with the signatures of many computer vision API functions, which tend to accept image data as the first argument. Examples -------- ``florinate`` may be appplied as a decorator to standard function definitions to then make subsequent calls return the deferred function. >>> @florinate ... def add(x, y): ... return x + y >>> plus_one = add(1) >>> plus_one(5) 6 Functions may also be florinated on the fly by using it as a standard function: >>> def concat(str1, str2): ... return ' '.join([str1, str2]) >>> worlder = florinate(concat)('World') >>> worlder('Hello') 'Hello World' """ @functools.wraps(func) def wrapper(*wrapper_args, **wrapper_kwargs): """Function wrapper that saves args and keyword arguments.""" @functools.wraps(func) def delayed(*args, **kwargs): """Wrapper for deferred function calls with persistent arguments""" kwargs.update(wrapper_kwargs) if isinstance(args[0], Sequence) and isinstance(args[0][-1], FlorinContext): innerargs = tuple(args[0][:-1]) + wrapper_args return func(*innerargs, **kwargs), args[0][-1] else: innerargs = args + wrapper_args return func(*innerargs, **kwargs) return delayed return wrapper