def compose(first, second): name = lambda: '{0} ?| {1}'.format(get_name(first), get_name(second)) def composite(*args, **kwargs): result = first(*args, **kwargs) return None if result is None else second(result) return set_name(name, composite)
def compose(first, second): name = '{0} | {1}'.format(get_name(first), get_name(second)) def composite(*args, **kwargs): with pipe_exception_handler('pipe | ' + name): return second(first(*args, **kwargs)) return set_name(name, composite)
def compose(first, second): name = lambda: '{0} | {1}'.format(get_name(first), get_name(second)) def composite(*args, **kwargs): return second(first(*args, **kwargs)) return set_name(name, composite)
def compose(first, second): name = '{0} ?| {1}'.format(get_name(first), get_name(second)) def composite(*args, **kwargs): with pipe_exception_handler('maybe ?| ' + name): result = first(*args, **kwargs) return None if result is None else second(result) return set_name(name, composite)
def unless(exception_class_or_tuple, func, *args, **kwargs): """ When `exception_class_or_tuple` occurs while executing `func`, it will be caught and ``None`` will be returned. >>> f = where(X > 10) | list | unless(IndexError, X[0]) >>> f([5, 8, 12, 4]) 12 >>> f([1, 2, 3]) None """ @pipe_util @auto_string_formatter @data_structure_builder def construct_unless(function): # a wrapper so we can re-use the decorators def _unless(*args, **kwargs): try: return function(*args, **kwargs) except exception_class_or_tuple: pass return _unless name = lambda: 'unless(%s, %s)' % (exception_class_or_tuple, ', '.join( filter(None, (get_name(func), repr_args(*args, **kwargs))))) return set_name(name, construct_unless(func, *args, **kwargs))
def unless(exception_class_or_tuple, func, *args, **kwargs): """ When `exception_class_or_tuple` occurs while executing `func`, it will be caught and ``None`` will be returned. >>> f = where(X > 10) | list | unless(IndexError, X[0]) >>> f([5, 8, 12, 4]) 12 >>> f([1, 2, 3]) None """ @pipe_util @auto_string_formatter @data_structure_builder def construct_unless(function): # a wrapper so we can re-use the decorators def _unless(*args, **kwargs): try: return function(*args, **kwargs) except exception_class_or_tuple: pass return _unless name = 'unless(%s, %s)' % (exception_class_or_tuple, ', '.join( filter(None, (get_name(func), repr_args(*args, **kwargs))))) return set_name(name, construct_unless(func, *args, **kwargs))
def pipe_util_wrapper(function, *args, **kwargs): if isinstance(function, XObject): function = ~function function_name = get_name(function) if args or kwargs: function = xcurry(function, *args, **kwargs) name = '%s(%s)' % (func.__name__, ', '.join( filter(None, (function_name, repr_args(*args, **kwargs))))) return pipe | set_name(name, func(function))
def xpartial(func, *xargs, **xkwargs): """ Like :func:`functools.partial`, but can take an :class:`XObject` placeholder that will be replaced with the first positional argument when the partially applied function is called. Useful when the function's positional arguments' order doesn't fit your situation, e.g.: >>> reverse_range = xpartial(range, X, 0, -1) >>> reverse_range(5) [5, 4, 3, 2, 1] It can also be used to transform the positional argument to a keyword argument, which can come in handy inside a *pipe*:: xpartial(objects.get, id=X) Also the XObjects are evaluated, which can be used for some sort of destructuring of the argument:: xpartial(somefunc, name=X.name, number=X.contacts['number']) Lastly, unlike :func:`functools.partial`, this creates a regular function which will bind to classes (like the ``curry`` function from ``django.utils.functional``). """ any_x = any( isinstance(a, XObject) for a in xargs + tuple(xkwargs.values())) use = lambda x, value: (~x)(value) if isinstance(x, XObject) else x @wraps(func, assigned=filter(partial(hasattr, func), WRAPPER_ASSIGNMENTS)) def xpartially_applied(*func_args, **func_kwargs): if any_x: if not func_args: raise ValueError( 'Function "%s" partially applied with an ' 'X placeholder but called with no positional arguments.' % get_name(func)) first = func_args[0] rest = func_args[1:] args = tuple(use(x, first) for x in xargs) + rest kwargs = dict((k, use(x, first)) for k, x in dict_items(xkwargs)) kwargs.update(func_kwargs) else: args = xargs + func_args kwargs = dict(xkwargs, **func_kwargs) return func(*args, **kwargs) name = lambda: '%s(%s)' % (get_name(func), repr_args(*xargs, **xkwargs)) return set_name(name, xpartially_applied)
def xcurried(*func_args, **func_kwargs): if any_x: if not func_args: raise ValueError('Function "%s" curried with an X placeholder ' 'but called with no positional arguments.' % get_name(func)) first = func_args[0] rest = func_args[1:] args = tuple(use(x, first) for x in xargs) + rest kwargs = dict((k, use(x, first)) for k, x in xkwargs.iteritems()) kwargs.update(func_kwargs) else: args = xargs + func_args kwargs = dict(xkwargs, **func_kwargs) return func(*args, **kwargs)
def pipe_util_wrapper(function, *args, **kwargs): if isinstance(function, XObject): function = ~function original_function = function if args or kwargs: function = xpartial(function, *args, **kwargs) name = lambda: '%s(%s)' % (get_name(func), ', '.join( filter(None, (get_name(original_function), repr_args(*args, **kwargs))))) f = func(function) result = pipe | set_name(name, f) # if the util defines an 'attrs' mapping, copy it as attributes # to the result attrs = getattr(f, 'attrs', {}) for k, v in dict_items(attrs): setattr(result, k, v) return result
def xpartial(func, *xargs, **xkwargs): """ Like :func:`functools.partial`, but can take an :class:`XObject` placeholder that will be replaced with the first positional argument when the partially applied function is called. Useful when the function's positional arguments' order doesn't fit your situation, e.g.: >>> reverse_range = xpartial(range, X, 0, -1) >>> reverse_range(5) [5, 4, 3, 2, 1] It can also be used to transform the positional argument to a keyword argument, which can come in handy inside a *pipe*:: xpartial(objects.get, id=X) Also the XObjects are evaluated, which can be used for some sort of destructuring of the argument:: xpartial(somefunc, name=X.name, number=X.contacts['number']) Lastly, unlike :func:`functools.partial`, this creates a regular function which will bind to classes (like the ``curry`` function from ``django.utils.functional``). """ any_x = any(isinstance(a, XObject) for a in xargs + tuple(xkwargs.values())) use = lambda x, value: (~x)(value) if isinstance(x, XObject) else x @wraps(func) def xpartially_applied(*func_args, **func_kwargs): if any_x: if not func_args: raise ValueError('Function "%s" partially applied with an ' 'X placeholder but called with no positional arguments.' % get_name(func)) first = func_args[0] rest = func_args[1:] args = tuple(use(x, first) for x in xargs) + rest kwargs = dict((k, use(x, first)) for k, x in dict_items(xkwargs)) kwargs.update(func_kwargs) else: args = xargs + func_args kwargs = dict(xkwargs, **func_kwargs) return func(*args, **kwargs) name = lambda: '%s(%s)' % (get_name(func), repr_args(*xargs, **xkwargs)) return set_name(name, xpartially_applied)
def __str__(self): return get_name(self.func)
def __repr__(self): return get_name(self)
def __init__(self, func=None): self._func = func set_name(lambda: get_name(func) if func else 'X', self)
def __init__(self, func=None): self._func = func self.__name__ = get_name(func) if func else 'X'