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
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)
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
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])
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_)
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)
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])
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:])
def last(list_): """Returns last element of a list.""" ensure_sequence(list_) return list_[-1]
def head(list_): """Returns head of a list, i.e. it's first element.""" ensure_sequence(list_) return list_[0]
def fifth(arg): """Returns the fifth element of a tuple (or other sequence).""" ensure_sequence(arg) return arg[4]
def third(arg): """Returns the third element of a tuple (or other sequence).""" ensure_sequence(arg) return arg[2]
def second(arg): """Returns the second element of a tuple (or other sequence).""" ensure_sequence(arg) return arg[1]