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): 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 = '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 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 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 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 take_first(count): """ Assumes an iterable on the input, returns an iterable with first `count` items from the input (or possibly less, if there isn't that many). >>> xrange(9000) > where(X % 100 == 0) | take_first(5) | tuple (0, 100, 200, 300, 400) """ def _take_first(iterable): return islice(iterable, count) return pipe | set_name('take_first(%s)' % count, _take_first)
def drop_first(count): """ Assumes an iterable on the input, returns an iterable with identical items except for the first `count`. >>> xrange(10) > drop_first(5) | tuple (5, 6, 7, 8, 9) """ def _drop_first(iterable): g = (x for x in xrange(1, count + 1)) return dropwhile(lambda i: unless(StopIteration, g.next)(), iterable) return pipe | set_name('drop_first(%s)' % count, _drop_first)
def StringFormatter(template): f = text_type(template).format def format(content): if isinstance(content, dict): return f(**content) if _iterable(content): return f(*content) return f(content) return set_name(lambda: "format('%s')" % template[:20], format)
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 take_first(count): """ Assumes an iterable on the input, returns an iterable with first `count` items from the input (or possibly less, if there isn't that many). >>> range(9000) > where(X % 100 == 0) | take_first(5) | tuple (0, 100, 200, 300, 400) """ def _take_first(iterable): return islice(iterable, count) return pipe | set_name('take_first(%s)' % count, _take_first)
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 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 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 bind(self, name, func): set_name(name, func) return XObject((self._func | func) if self._func else (pipe | func))
def __invert__(self): return self._func or set_name('X', lambda x: x)
def __init__(self, func=None): self._func = func set_name(lambda: get_name(func) if func else 'X', self)