Ejemplo n.º 1
0
def ensure_argcount(args, min_=None, max_=None):
    """Checks whether iterable of positional arguments satisfies conditions.

    :param args: Iterable of positional arguments, received via ``*args``
    :param min_: Minimum number of arguments
    :param max_: Maximum number of arguments

    :return: ``args`` if the conditions are met
    :raise TypeError: When conditions are not met
    """
    ensure_sequence(args)

    has_min = min_ is not None
    has_max = max_ is not None
    if not (has_min or has_max):
        raise ValueError(
            "minimum and/or maximum number of arguments must be provided")
    if has_min and has_max and min_ > max_:
        raise ValueError(
            "maximum number of arguments must be greater or equal to minimum")

    if has_min and len(args) < min_:
        raise TypeError(
            "expected at least %s arguments, got %s" % (min_, len(args)))
    if has_max and len(args) > max_:
        raise TypeError(
            "expected at most %s arguments, got %s" % (max_, len(args)))

    return args
Ejemplo n.º 2
0
def omit(indices, from_, strict=False):
    """Returns a subsequence from given tuple, omitting specified indices.

    :param indices: Iterable of indices to exclude
    :param strict: Whether ``indices`` are required to exist in the tuple

    :return: Tuple without elements of specified indices

    :raise IndexError: If ``strict`` is True and one of ``indices``
                       is out of range.

    .. versionadded:: 0.0.3
    """
    from taipan.collections.sets import remove_subset

    ensure_iterable(indices)
    ensure_sequence(from_)

    if strict:
        remaining_indices = set(xrange(len(from_)))
        try:
            remove_subset(remaining_indices, indices)
        except KeyError as e:
            raise IndexError(int(str(e)))
    else:
        remaining_indices = set(xrange(len(from_))) - set(indices)

    return from_.__class__(from_[index] for index in remaining_indices)
Ejemplo n.º 3
0
def _index(*args, **kwargs):
    """Implementation of list searching.

    :param of: Element to search for
    :param where: Predicate to search for
    :param in_: List to search in
    :param start: Start index for the lookup
    :param step: Counter step (i.e. in/decrement) for each iteration

    :return: Pair of ``(list, index)``,
             where ``list`` is the list we searched in
             and ``index`` is the index of the first element found, or -1
    """
    start = kwargs.pop('start', 0)
    step = kwargs.pop('step', 1)

    if len(args) == 2:
        elem, list_ = args
        ensure_sequence(list_)
        predicate = lambda item: item == elem
    else:
        ensure_keyword_args(kwargs,
                            mandatory=('in_',), optional=('of', 'where'))
        if 'of' in kwargs and 'where' in kwargs:
            raise TypeError(
                "either an item or predicate must be supplied, not both")
        if not ('of' in kwargs or 'where' in kwargs):
            raise TypeError("an item or predicate must be supplied")

        list_ = ensure_sequence(kwargs['in_'])
        if 'where' in kwargs:
            predicate = ensure_callable(kwargs['where'])
        else:
            elem = kwargs['of']
            predicate = lambda item: item == elem

    len_ = len(list_)
    start = max(0, min(len_ - 1, start))

    i = start
    while 0 <= i < len_:
        if predicate(list_[i]):
            return list_, i
        i += step
    else:
        return list_, -1
Ejemplo n.º 4
0
def intercalate(elems, list_):
    """Insert given elements between existing elements of a list.

    :param elems: List of elements to insert between elements of ``list_`
    :param list_: List to insert the elements to

    :return: A new list where items from ``elems`` are inserted
             between every two elements of ``list_``
    """
    ensure_sequence(elems)
    ensure_sequence(list_)

    if len(list_) <= 1:
        return list_

    return sum(
        (elems + list_[i:i+1] for i in xrange(1, len(list_))),
        list_[:1])
Ejemplo n.º 5
0
def select(indices, from_, strict=False):
    """Selects a subsequence of given tuple, including only specified indices.

    :param indices: Iterable of indices to include
    :param strict: Whether ``indices`` are required to exist in the tuple.

    :return: Tuple with selected elements, in the order corresponding
             to the order of ``indices``.

    :raise IndexError: If ``strict`` is True and one of ``indices``
                       is out of range.
    """
    ensure_iterable(indices)
    ensure_sequence(from_)

    if strict:
        return from_.__class__(from_[index] for index in indices)
    else:
        len_ = len(from_)
        return from_.__class__(from_[index] for index in indices
                               if 0 <= index < len_)
Ejemplo n.º 6
0
def merge(arg, *rest, **kwargs):
    """Merge a collection, with functions as items, into a single function
    that takes a collection and maps its items through corresponding functions.

    :param arg: A collection of functions, such as list, tuple, or dictionary
    :param default: Optional default function to use for items
                    within merged function's arguments that do not have
                    corresponding functions in ``arg``

    Example with two-element tuple::

        >> dict_ = {'Alice': -5, 'Bob': 4}
        >> func = merge((str.upper, abs))
        >> dict(map(func, dict_.items()))
        {'ALICE': 5, 'BOB': 4}

    Example with a dictionary::

        >> func = merge({'id': int, 'name': str.split})
        >> data = [
            {'id': '1', 'name': "John Doe"},
            {'id': '2', 'name': "Anne Arbor"},
        ]
        >> list(map(func, data))
        [{'id': 1, 'name': ['John', 'Doe']},
         {'id': 2, 'name': ['Anne', 'Arbor']}]

    :return: Merged function

    .. versionadded:: 0.0.2
    """
    ensure_keyword_args(kwargs, optional=('default', ))

    has_default = 'default' in kwargs
    if has_default:
        default = ensure_callable(kwargs['default'])

    # if more than one argument was given, they must all be functions;
    # result will be a function that takes multiple arguments (rather than
    # a single collection) and returns a tuple
    unary_result = True
    if rest:
        fs = (ensure_callable(arg), ) + tuple(imap(ensure_callable, rest))
        unary_result = False
    else:
        fs = arg

    if is_mapping(fs):
        if has_default:
            return lambda arg_: fs.__class__(
                (k, fs.get(k, default)(arg_[k])) for k in arg_)
        else:
            return lambda arg_: fs.__class__((k, fs[k](arg_[k])) for k in arg_)
    else:
        ensure_sequence(fs)
        if has_default:
            # we cannot use ``izip_longest(fs, arg_, fillvalue=default)``,
            # because we want to terminate the generator
            # only when ``arg_`` is exhausted (not when just ``fs`` is)
            func = lambda arg_: fs.__class__((fs[i]
                                              if i < len(fs) else default)(x)
                                             for i, x in enumerate(arg_))
        else:
            # we cannot use ``izip(fs, arg_)`` because it would short-circuit
            # if ``arg_`` is longer than ``fs``, rather than raising
            # the required ``IndexError``
            func = lambda arg_: fs.__class__(fs[i](x)
                                             for i, x in enumerate(arg_))
        return func if unary_result else lambda *args: func(args)
Ejemplo n.º 7
0
def init(list_):
    """Returns all the elements of a list except the last one."""
    ensure_sequence(list_)
    if not list_:
        raise ValueError("can't extract initial part of an empty list")
    return list(list_[:-1])
Ejemplo n.º 8
0
def tail(list_):
    """Returns tail of a list (all elements without the first one)."""
    ensure_sequence(list_)
    if not list_:
        raise ValueError("can't tail an empty list")
    return list(list_[1:])
Ejemplo n.º 9
0
def last(list_):
    """Returns last element of a list."""
    ensure_sequence(list_)
    return list_[-1]
Ejemplo n.º 10
0
def head(list_):
    """Returns head of a list, i.e. it's first element."""
    ensure_sequence(list_)
    return list_[0]
Ejemplo n.º 11
0
def fifth(arg):
    """Returns the fifth element of a tuple (or other sequence)."""
    ensure_sequence(arg)
    return arg[4]
Ejemplo n.º 12
0
def third(arg):
    """Returns the third element of a tuple (or other sequence)."""
    ensure_sequence(arg)
    return arg[2]
Ejemplo n.º 13
0
def second(arg):
    """Returns the second element of a tuple (or other sequence)."""
    ensure_sequence(arg)
    return arg[1]