#!/usr/bin/env python2 # -*- coding: utf-8 -*- # type: ignore # Compiled with Coconut version 1.4.3 [Ernest Scribbler] """Built-in Coconut utilities.""" # Coconut Header: ------------------------------------------------------------- from __future__ import print_function, absolute_import, unicode_literals, division import sys as _coconut_sys from __builtin__ import chr, filter, hex, input, int, map, object, oct, open, print, range, str, zip, filter, reversed, enumerate, raw_input, xrange py_chr, py_hex, py_input, py_int, py_map, py_object, py_oct, py_open, py_print, py_range, py_str, py_zip, py_filter, py_reversed, py_enumerate, py_raw_input, py_xrange, py_repr = chr, hex, input, int, map, object, oct, open, print, range, str, zip, filter, reversed, enumerate, raw_input, xrange, repr _coconut_NotImplemented, _coconut_raw_input, _coconut_xrange, _coconut_int, _coconut_long, _coconut_print, _coconut_str, _coconut_unicode, _coconut_repr = NotImplemented, raw_input, xrange, int, long, print, str, unicode, repr from future_builtins import * chr, str = unichr, unicode from io import open class object(object): __slots__ = () def __ne__(self, other): eq = self == other if eq is _coconut_NotImplemented: return eq return not eq class int(_coconut_int): __slots__ = () if hasattr(_coconut_int, "__doc__"): __doc__ = _coconut_int.__doc__ class __metaclass__(type): def __instancecheck__(cls, inst): return _coconut.isinstance(inst, (_coconut_int, _coconut_long)) def __subclasscheck__(cls, subcls): return _coconut.issubclass(subcls, (_coconut_int, _coconut_long)) class range(object): __slots__ = ("_xrange",) if hasattr(_coconut_xrange, "__doc__"): __doc__ = _coconut_xrange.__doc__ def __init__(self, *args): self._xrange = _coconut_xrange(*args) def __iter__(self): return _coconut.iter(self._xrange) def __reversed__(self): return _coconut.reversed(self._xrange) def __len__(self): return _coconut.len(self._xrange) def __contains__(self, elem): return elem in self._xrange def __getitem__(self, index): if _coconut.isinstance(index, _coconut.slice): args = _coconut.slice(*self._args) start, stop, step, ind_step = (args.start if args.start is not None else 0), args.stop, (args.step if args.step is not None else 1), (index.step if index.step is not None else 1) return self.__class__((start if ind_step >= 0 else stop - step) if index.start is None else start + step * index.start if index.start >= 0 else stop + step * index.start, (stop if ind_step >= 0 else start - step) if index.stop is None else start + step * index.stop if index.stop >= 0 else stop + step * index.stop, step if index.step is None else step * index.step) else: return self._xrange[index] def count(self, elem): """Count the number of times elem appears in the range.""" return _coconut_int(elem in self._xrange) def index(self, elem): """Find the index of elem in the range.""" if elem not in self._xrange: raise _coconut.ValueError(_coconut.repr(elem) + " is not in range") start, _, step = self._xrange.__reduce_ex__(2)[1] return (elem - start) // step def __repr__(self): return _coconut.repr(self._xrange)[1:] @property def _args(self): return self._xrange.__reduce__()[1] def __reduce_ex__(self, protocol): return (self.__class__, self._xrange.__reduce_ex__(protocol)[1]) def __reduce__(self): return self.__reduce_ex__(_coconut.pickle.DEFAULT_PROTOCOL) def __hash__(self): return _coconut.hash(self._args) def __copy__(self): return self.__class__(*self._args) def __eq__(self, other): return _coconut.isinstance(other, self.__class__) and self._args == other._args from collections import Sequence as _coconut_Sequence _coconut_Sequence.register(range) from functools import wraps as _coconut_wraps @_coconut_wraps(_coconut_print) def print(*args, **kwargs): file = kwargs.get("file", _coconut_sys.stdout) flush = kwargs.get("flush", False) if "flush" in kwargs: del kwargs["flush"] if _coconut.hasattr(file, "encoding") and file.encoding is not None: _coconut_print(*(_coconut_unicode(x).encode(file.encoding) for x in args), **kwargs) else: _coconut_print(*(_coconut_unicode(x).encode() for x in args), **kwargs) if flush: file.flush() @_coconut_wraps(_coconut_raw_input) def input(*args, **kwargs): if _coconut.hasattr(_coconut_sys.stdout, "encoding") and _coconut_sys.stdout.encoding is not None: return _coconut_raw_input(*args, **kwargs).decode(_coconut_sys.stdout.encoding) return _coconut_raw_input(*args, **kwargs).decode() @_coconut_wraps(_coconut_repr) def repr(obj): if isinstance(obj, _coconut_unicode): return _coconut_unicode(_coconut_repr(obj)[1:]) if isinstance(obj, _coconut_str): return "b" + _coconut_unicode(_coconut_repr(obj)) return _coconut_unicode(_coconut_repr(obj)) ascii = repr def raw_input(*args): """Coconut uses Python 3 "input" instead of Python 2 "raw_input".""" raise _coconut.NameError('Coconut uses Python 3 "input" instead of Python 2 "raw_input"') def xrange(*args): """Coconut uses Python 3 "range" instead of Python 2 "xrange".""" raise _coconut.NameError('Coconut uses Python 3 "range" instead of Python 2 "xrange"') class _coconut(object): import collections, copy, functools, types, itertools, operator, threading, weakref, os, warnings try: from backports.functools_lru_cache import lru_cache functools.lru_cache = lru_cache except ImportError: pass try: import trollius as asyncio except ImportError: class you_need_to_install_trollius: pass asyncio = you_need_to_install_trollius() import cPickle as pickle OrderedDict = collections.OrderedDict abc = collections class typing(object): @staticmethod def NamedTuple(name, fields): return _coconut.collections.namedtuple(name, [x for x, t in fields]) Ellipsis, Exception, AttributeError, ImportError, IndexError, KeyError, NameError, TypeError, ValueError, StopIteration, classmethod, dict, enumerate, filter, float, frozenset, getattr, hasattr, hash, id, int, isinstance, issubclass, iter, len, list, locals, map, min, max, next, object, property, range, reversed, set, slice, str, sum, super, tuple, type, zip, repr, bytearray = Ellipsis, Exception, AttributeError, ImportError, IndexError, KeyError, NameError, TypeError, ValueError, StopIteration, classmethod, dict, enumerate, filter, float, frozenset, getattr, hasattr, hash, id, int, isinstance, issubclass, iter, len, list, locals, map, min, max, next, object, property, range, reversed, set, slice, str, sum, super, tuple, type, zip, staticmethod(repr), bytearray _coconut_sentinel = _coconut.object() class MatchError(Exception): """Pattern-matching error. Has attributes .pattern and .value.""" __slots__ = ("pattern", "value") def _coconut_igetitem(iterable, index): if isinstance(iterable, (_coconut_reversed, _coconut_map, _coconut.zip, _coconut_enumerate, _coconut_count, _coconut.abc.Sequence)): return iterable[index] if not _coconut.isinstance(index, _coconut.slice): if index < 0: return _coconut.collections.deque(iterable, maxlen=-index)[0] return _coconut.next(_coconut.itertools.islice(iterable, index, index + 1)) if index.start is not None and index.start < 0 and (index.stop is None or index.stop < 0) and index.step is None: queue = _coconut.collections.deque(iterable, maxlen=-index.start) if index.stop is not None: queue = _coconut.list(queue)[:index.stop - index.start] return queue if (index.start is not None and index.start < 0) or (index.stop is not None and index.stop < 0) or (index.step is not None and index.step < 0): return _coconut.list(iterable)[index] return _coconut.itertools.islice(iterable, index.start, index.stop, index.step) class _coconut_base_compose(object): __slots__ = ("func", "funcstars") def __init__(self, func, *funcstars): self.func = func self.funcstars = [] for f, stars in funcstars: if _coconut.isinstance(f, _coconut_base_compose): self.funcstars.append((f.func, stars)) self.funcstars += f.funcstars else: self.funcstars.append((f, stars)) def __call__(self, *args, **kwargs): arg = self.func(*args, **kwargs) for f, stars in self.funcstars: if stars == 0: arg = f(arg) elif stars == 1: arg = f(*arg) elif stars == 2: arg = f(**arg) else: raise _coconut.ValueError("invalid arguments to " + _coconut.repr(self)) return arg def __repr__(self): return _coconut.repr(self.func) + " " + " ".join(("..*> " if star == 1 else "..**>" if star == 2 else "..> ") + _coconut.repr(f) for f, star in self.funcstars) def __reduce__(self): return (self.__class__, (self.func,) + _coconut.tuple(self.funcstars)) def __get__(self, obj, objtype=None): return _coconut.functools.partial(self, obj) def _coconut_forward_compose(func, *funcs): return _coconut_base_compose(func, *((f, 0) for f in funcs)) def _coconut_back_compose(*funcs): return _coconut_forward_compose(*_coconut.reversed(funcs)) def _coconut_forward_star_compose(func, *funcs): return _coconut_base_compose(func, *((f, 1) for f in funcs)) def _coconut_back_star_compose(*funcs): return _coconut_forward_star_compose(*_coconut.reversed(funcs)) def _coconut_forward_dubstar_compose(func, *funcs): return _coconut_base_compose(func, *((f, 2) for f in funcs)) def _coconut_back_dubstar_compose(*funcs): return _coconut_forward_dubstar_compose(*_coconut.reversed(funcs)) def _coconut_pipe(x, f): return f(x) def _coconut_star_pipe(xs, f): return f(*xs) def _coconut_dubstar_pipe(kws, f): return f(**kws) def _coconut_back_pipe(f, x): return f(x) def _coconut_back_star_pipe(f, xs): return f(*xs) def _coconut_back_dubstar_pipe(f, kws): return f(**kws) def _coconut_assert(cond, msg=None): assert cond, msg if msg is not None else "(assert) got falsey value " + _coconut.repr(cond) def _coconut_bool_and(a, b): return a and b def _coconut_bool_or(a, b): return a or b def _coconut_none_coalesce(a, b): return a if a is not None else b def _coconut_minus(a, *rest): if not rest: return -a for b in rest: a = a - b return a @_coconut.functools.wraps(_coconut.itertools.tee) def tee(iterable, n=2): if n >= 0 and _coconut.isinstance(iterable, (_coconut.tuple, _coconut.frozenset)): return (iterable,) * n if n > 0 and (_coconut.hasattr(iterable, "__copy__") or _coconut.isinstance(iterable, _coconut.abc.Sequence)): return (iterable,) + _coconut.tuple(_coconut.copy.copy(iterable) for _ in _coconut.range(n - 1)) return _coconut.itertools.tee(iterable, n) class reiterable(object): """Allows an iterator to be iterated over multiple times.""" __slots__ = ("iter",) def __init__(self, iterable): self.iter = iterable def _get_new_iter(self): self.iter, new_iter = _coconut_tee(self.iter) return new_iter def __iter__(self): return _coconut.iter(self._get_new_iter()) def __getitem__(self, index): return _coconut_igetitem(self._get_new_iter(), index) def __reversed__(self): return _coconut_reversed(self._get_new_iter()) def __len__(self): return _coconut.len(self.iter) def __repr__(self): return "reiterable(%r)" % (self.iter,) def __reduce__(self): return (self.__class__, (self.iter,)) def __copy__(self): return self.__class__(self._get_new_iter()) def __fmap__(self, func): return _coconut_map(func, self) class scan(object): """Reduce func over iterable, yielding intermediate results, optionally starting from initializer.""" __slots__ = ("func", "iter", "initializer") def __init__(self, function, iterable, initializer=_coconut_sentinel): self.func = function self.iter = iterable self.initializer = initializer def __iter__(self): acc = self.initializer if acc is not _coconut_sentinel: yield acc for item in self.iter: if acc is _coconut_sentinel: acc = item else: acc = self.func(acc, item) yield acc def __len__(self): return _coconut.len(self.iter) def __repr__(self): return "scan(%r, %r)" % (self.func, self.iter) def __reduce__(self): return (self.__class__, (self.func, self.iter)) def __copy__(self): return self.__class__(self.func, _coconut.copy.copy(self.iter)) def __fmap__(self, func): return _coconut_map(func, self) class reversed(object): __slots__ = ("iter",) if hasattr(_coconut.map, "__doc__"): __doc__ = _coconut.reversed.__doc__ def __new__(cls, iterable): if _coconut.isinstance(iterable, _coconut.range): return iterable[::-1] if not _coconut.hasattr(iterable, "__reversed__") or _coconut.isinstance(iterable, (_coconut.list, _coconut.tuple)): return _coconut.object.__new__(cls) return _coconut.reversed(iterable) def __init__(self, iterable): self.iter = iterable def __iter__(self): return _coconut.iter(_coconut.reversed(self.iter)) def __getitem__(self, index): if _coconut.isinstance(index, _coconut.slice): return _coconut_igetitem(self.iter, _coconut.slice(-(index.start + 1) if index.start is not None else None, -(index.stop + 1) if index.stop else None, -(index.step if index.step is not None else 1))) return _coconut_igetitem(self.iter, -(index + 1)) def __reversed__(self): return self.iter def __len__(self): return _coconut.len(self.iter) def __repr__(self): return "reversed(%r)" % (self.iter,) def __hash__(self): return -_coconut.hash(self.iter) def __reduce__(self): return (self.__class__, (self.iter,)) def __copy__(self): return self.__class__(_coconut.copy.copy(self.iter)) def __eq__(self, other): return isinstance(other, self.__class__) and self.iter == other.iter def __contains__(self, elem): return elem in self.iter def count(self, elem): """Count the number of times elem appears in the reversed iterator.""" return self.iter.count(elem) def index(self, elem): """Find the index of elem in the reversed iterator.""" return _coconut.len(self.iter) - self.iter.index(elem) - 1 def __fmap__(self, func): return self.__class__(_coconut_map(func, self.iter)) class map(_coconut.map): __slots__ = ("func", "iters") if hasattr(_coconut.map, "__doc__"): __doc__ = _coconut.map.__doc__ def __new__(cls, function, *iterables): new_map = _coconut.map.__new__(cls, function, *iterables) new_map.func = function new_map.iters = iterables return new_map def __getitem__(self, index): if _coconut.isinstance(index, _coconut.slice): return self.__class__(self.func, *(_coconut_igetitem(i, index) for i in self.iters)) return self.func(*(_coconut_igetitem(i, index) for i in self.iters)) def __reversed__(self): return self.__class__(self.func, *(_coconut_reversed(i) for i in self.iters)) def __len__(self): return _coconut.min(_coconut.len(i) for i in self.iters) def __repr__(self): return "map(%r, %s)" % (self.func, ", ".join((_coconut.repr(i) for i in self.iters))) def __reduce__(self): return (self.__class__, (self.func,) + self.iters) def __reduce_ex__(self, _): return self.__reduce__() def __copy__(self): return self.__class__(self.func, *_coconut.map(_coconut.copy.copy, self.iters)) def __fmap__(self, func): return self.__class__(_coconut_forward_compose(self.func, func), *self.iters) class parallel_map(map): """Multi-process implementation of map using concurrent.futures. Requires arguments to be pickleable.""" __slots__ = () def __iter__(self): from concurrent.futures import ProcessPoolExecutor with ProcessPoolExecutor() as executor: return _coconut.iter(_coconut.list(executor.map(self.func, *self.iters))) def __repr__(self): return "parallel_" + _coconut_map.__repr__(self) class concurrent_map(map): """Multi-thread implementation of map using concurrent.futures.""" __slots__ = () def __iter__(self): from concurrent.futures import ThreadPoolExecutor from multiprocessing import cpu_count # cpu_count() * 5 is the default Python 3.5 thread count with ThreadPoolExecutor(cpu_count() * 5) as executor: return _coconut.iter(_coconut.list(executor.map(self.func, *self.iters))) def __repr__(self): return "concurrent_" + _coconut_map.__repr__(self) class filter(_coconut.filter): __slots__ = ("func", "iter") if hasattr(_coconut.filter, "__doc__"): __doc__ = _coconut.filter.__doc__ def __new__(cls, function, iterable): new_filter = _coconut.filter.__new__(cls, function, iterable) new_filter.func = function new_filter.iter = iterable return new_filter def __reversed__(self): return self.__class__(self.func, _coconut_reversed(self.iter)) def __repr__(self): return "filter(%r, %r)" % (self.func, self.iter) def __reduce__(self): return (self.__class__, (self.func, self.iter)) def __reduce_ex__(self, _): return self.__reduce__() def __copy__(self): return self.__class__(self.func, _coconut.copy.copy(self.iter)) def __fmap__(self, func): return _coconut_map(func, self) class zip(_coconut.zip): __slots__ = ("iters",) if hasattr(_coconut.zip, "__doc__"): __doc__ = _coconut.zip.__doc__ def __new__(cls, *iterables): new_zip = _coconut.zip.__new__(cls, *iterables) new_zip.iters = iterables return new_zip def __getitem__(self, index): if _coconut.isinstance(index, _coconut.slice): return self.__class__(*(_coconut_igetitem(i, index) for i in self.iters)) return _coconut.tuple(_coconut_igetitem(i, index) for i in self.iters) def __reversed__(self): return self.__class__(*(_coconut_reversed(i) for i in self.iters)) def __len__(self): return _coconut.min(_coconut.len(i) for i in self.iters) def __repr__(self): return "zip(%s)" % (", ".join((_coconut.repr(i) for i in self.iters)),) def __reduce__(self): return (self.__class__, self.iters) def __reduce_ex__(self, _): return self.__reduce__() def __copy__(self): return self.__class__(*_coconut.map(_coconut.copy.copy, self.iters)) def __fmap__(self, func): return _coconut_map(func, self) class enumerate(_coconut.enumerate): __slots__ = ("iter", "start") if hasattr(_coconut.enumerate, "__doc__"): __doc__ = _coconut.enumerate.__doc__ def __new__(cls, iterable, start=0): new_enumerate = _coconut.enumerate.__new__(cls, iterable, start) new_enumerate.iter = iterable new_enumerate.start = start return new_enumerate def __getitem__(self, index): if _coconut.isinstance(index, _coconut.slice): return self.__class__(_coconut_igetitem(self.iter, index), self.start + (0 if index.start is None else index.start if index.start >= 0 else len(self.iter) + index.start)) return (self.start + index, _coconut_igetitem(self.iter, index)) def __len__(self): return _coconut.len(self.iter) def __repr__(self): return "enumerate(%r, %r)" % (self.iter, self.start) def __reduce__(self): return (self.__class__, (self.iter, self.start)) def __reduce_ex__(self, _): return self.__reduce__() def __copy__(self): return self.__class__(_coconut.copy.copy(self.iter), self.start) def __fmap__(self, func): return _coconut_map(func, self) class count(object): """count(start, step) returns an infinite iterator starting at start and increasing by step. If step is set to 0, count will infinitely repeat its first argument.""" __slots__ = ("start", "step") def __init__(self, start=0, step=1): self.start = start self.step = step def __iter__(self): while True: yield self.start if self.step: self.start += self.step def __contains__(self, elem): if not self.step: return elem == self.start if elem < self.start: return False return (elem - self.start) % self.step == 0 def __getitem__(self, index): if _coconut.isinstance(index, _coconut.slice) and (index.start is None or index.start >= 0) and (index.stop is None or index.stop >= 0): new_start, new_step = self.start, self.step if self.step and index.start is not None: new_start += self.step * index.start if self.step and index.step is not None: new_step *= index.step if index.stop is None: return self.__class__(new_start, new_step) if self.step and _coconut.isinstance(self.start, _coconut.int) and _coconut.isinstance(self.step, _coconut.int): return _coconut.range(new_start, self.start + self.step * index.stop, new_step) return _coconut_map(self.__getitem__, _coconut.range(index.start if index.start is not None else 0, index.stop, index.step if index.step is not None else 1)) if index < 0: raise _coconut.IndexError("count indices must be positive") return self.start + self.step * index if self.step else self.start def count(self, elem): """Count the number of times elem appears in the count.""" if not self.step: return _coconut.float("inf") if elem == self.start else 0 return int(elem in self) def index(self, elem): """Find the index of elem in the count.""" if elem not in self: raise _coconut.ValueError(_coconut.repr(elem) + " not in " + _coconut.repr(self)) return (elem - self.start) // self.step if self.step else 0 def __reversed__(self): if not self.step: return self raise _coconut.TypeError(repr(self) + " object is not reversible") def __repr__(self): return "count(%r, %r)" % (self.start, self.step) def __hash__(self): return _coconut.hash((self.start, self.step)) def __reduce__(self): return (self.__class__, (self.start, self.step)) def __copy__(self): return self.__class__(self.start, self.step) def __eq__(self, other): return isinstance(other, self.__class__) and self.start == other.start and self.step == other.step def __fmap__(self, func): return _coconut_map(func, self) class groupsof(object): """groupsof(n, iterable) splits iterable into groups of size n. If the length of the iterable is not divisible by n, the last group may be of size < n.""" __slots__ = ("group_size", "iter") def __init__(self, n, iterable): self.iter = iterable try: self.group_size = _coconut.int(n) except _coconut.ValueError: raise _coconut.TypeError("group size must be an int; not %r" % (n,)) if self.group_size <= 0: raise _coconut.ValueError("group size must be > 0; not %r" % (self.group_size,)) def __iter__(self): iterator = _coconut.iter(self.iter) loop = True while loop: group = [] for _ in _coconut.range(self.group_size): try: group.append(_coconut.next(iterator)) except _coconut.StopIteration: loop = False break if group: yield _coconut.tuple(group) def __len__(self): return _coconut.len(self.iter) def __repr__(self): return "groupsof(%r)" % (self.iter,) def __reduce__(self): return (self.__class__, (self.group_size, self.iter)) def __copy__(self): return self.__class__(self.group_size, _coconut.copy.copy(self.iter)) def __fmap__(self, func): return _coconut_map(func, self) class recursive_iterator(object): """Decorator that optimizes a function for iterator recursion.""" __slots__ = ("func", "tee_store", "backup_tee_store") def __init__(self, func): self.func = func self.tee_store = {} self.backup_tee_store = [] def __call__(self, *args, **kwargs): key = (args, _coconut.frozenset(kwargs)) use_backup = False try: hash(key) except _coconut.Exception: try: key = _coconut.pickle.dumps(key, -1) except _coconut.Exception: use_backup = True if use_backup: for i, (k, v) in _coconut.enumerate(self.backup_tee_store): if k == key: to_tee, store_pos = v, i break else: # no break to_tee = self.func(*args, **kwargs) store_pos = None to_store, to_return = _coconut_tee(to_tee) if store_pos is None: self.backup_tee_store.append([key, to_store]) else: self.backup_tee_store[store_pos][1] = to_store else: self.tee_store[key], to_return = _coconut_tee(self.tee_store.get(key) or self.func(*args, **kwargs)) return to_return def __repr__(self): return "@recursive_iterator(" + _coconut.repr(self.func) + ")" def __reduce__(self): return (self.__class__, (self.func,)) def __get__(self, obj, objtype=None): return _coconut.functools.partial(self, obj) class _coconut_FunctionMatchErrorContext(object): __slots__ = ('exc_class', 'taken') threadlocal_var = _coconut.threading.local() def __init__(self, exc_class): self.exc_class = exc_class self.taken = False def __enter__(self): try: self.threadlocal_var.contexts.append(self) except _coconut.AttributeError: self.threadlocal_var.contexts = [self] def __exit__(self, type, value, traceback): self.threadlocal_var.contexts.pop() @classmethod def get(cls): try: ctx = cls.threadlocal_var.contexts[-1] except (_coconut.AttributeError, _coconut.IndexError): return _coconut_MatchError if not ctx.taken: ctx.taken = True return ctx.exc_class return _coconut_MatchError _coconut_get_function_match_error = _coconut_FunctionMatchErrorContext.get class _coconut_base_pattern_func(object): __slots__ = ("FunctionMatchError", "__doc__", "patterns") _coconut_is_match = True def __init__(self, *funcs): self.FunctionMatchError = _coconut.type(_coconut_str("MatchError"), (_coconut_MatchError,), {}) self.__doc__ = None self.patterns = [] for func in funcs: self.add(func) def add(self, func): self.__doc__ = _coconut.getattr(func, "__doc__", None) or self.__doc__ if _coconut.isinstance(func, _coconut_base_pattern_func): self.patterns += func.patterns else: self.patterns.append(func) def __call__(self, *args, **kwargs): for func in self.patterns[:-1]: try: with _coconut_FunctionMatchErrorContext(self.FunctionMatchError): return func(*args, **kwargs) except self.FunctionMatchError: pass return self.patterns[-1](*args, **kwargs) def _coconut_tco_func(self, *args, **kwargs): for func in self.patterns[:-1]: try: with _coconut_FunctionMatchErrorContext(self.FunctionMatchError): return func(*args, **kwargs) except self.FunctionMatchError: pass return _coconut_tail_call(self.patterns[-1], *args, **kwargs) def __repr__(self): return "addpattern(" + _coconut.repr(self.patterns[0]) + ")(*" + _coconut.repr(self.patterns[1:]) + ")" def __reduce__(self): return (self.__class__, _coconut.tuple(self.patterns)) def __get__(self, obj, objtype=None): if obj is None: return self return _coconut.functools.partial(self, obj) def _coconut_mark_as_match(base_func): base_func._coconut_is_match = True return base_func def addpattern(base_func, **kwargs): """Decorator to add a new case to a pattern-matching function, where the new case is checked last.""" allow_any_func = kwargs.pop("allow_any_func", False) if not allow_any_func and not _coconut.getattr(base_func, "_coconut_is_match", False): _coconut.warnings.warn("Possible misuse of addpattern with non-pattern-matching function " + _coconut.repr(base_func) + " (pass allow_any_func=True to dismiss)", stacklevel=2) if kwargs: raise _coconut.TypeError("addpattern() got unexpected keyword arguments " + _coconut.repr(kwargs)) return _coconut.functools.partial(_coconut_base_pattern_func, base_func) _coconut_addpattern = addpattern class _coconut_partial(object): __slots__ = ("func", "_argdict", "_arglen", "_stargs", "keywords") if hasattr(_coconut.functools.partial, "__doc__"): __doc__ = _coconut.functools.partial.__doc__ def __init__(self, func, argdict, arglen, *args, **kwargs): self.func = func self._argdict = argdict self._arglen = arglen self._stargs = args self.keywords = kwargs def __reduce__(self): return (self.__class__, (self.func, self._argdict, self._arglen) + self._stargs, self.keywords) def __setstate__(self, keywords): self.keywords = keywords @property def args(self): return _coconut.tuple(self._argdict.get(i) for i in _coconut.range(self._arglen)) + self._stargs def __call__(self, *args, **kwargs): callargs = [] argind = 0 for i in _coconut.range(self._arglen): if i in self._argdict: callargs.append(self._argdict[i]) elif argind >= _coconut.len(args): raise _coconut.TypeError("expected at least " + _coconut.str(self._arglen - _coconut.len(self._argdict)) + " argument(s) to " + _coconut.repr(self)) else: callargs.append(args[argind]) argind += 1 callargs += self._stargs callargs += args[argind:] kwargs.update(self.keywords) return self.func(*callargs, **kwargs) def __repr__(self): args = [] for i in _coconut.range(self._arglen): if i in self._argdict: args.append(_coconut.repr(self._argdict[i])) else: args.append("?") for arg in self._stargs: args.append(_coconut.repr(arg)) return _coconut.repr(self.func) + "$(" + ", ".join(args) + ")" def consume(iterable, keep_last=0): """consume(iterable, keep_last) fully exhausts iterable and return the last keep_last elements.""" return _coconut.collections.deque(iterable, maxlen=keep_last) class starmap(_coconut.itertools.starmap): __slots__ = ("func", "iter") if hasattr(_coconut.itertools.starmap, "__doc__"): __doc__ = _coconut.itertools.starmap.__doc__ def __new__(cls, function, iterable): new_map = _coconut.itertools.starmap.__new__(cls, function, iterable) new_map.func = function new_map.iter = iterable return new_map def __getitem__(self, index): if _coconut.isinstance(index, _coconut.slice): return self.__class__(self.func, _coconut_igetitem(self.iter, index)) return self.func(*_coconut_igetitem(self.iter, index)) def __reversed__(self): return self.__class__(self.func, *_coconut_reversed(self.iter)) def __len__(self): return _coconut.len(self.iter) def __repr__(self): return "starmap(%r, %r)" % (self.func, self.iter) def __reduce__(self): return (self.__class__, (self.func, self.iter)) def __reduce_ex__(self, _): return self.__reduce__() def __copy__(self): return self.__class__(self.func, _coconut.copy.copy(self.iter)) def __fmap__(self, func): return self.__class__(_coconut_forward_compose(self.func, func), self.iter) def makedata(data_type, *args): """Construct an object of the given data_type containing the given arguments.""" if _coconut.hasattr(data_type, "_make") and _coconut.issubclass(data_type, _coconut.tuple): return data_type._make(args) if _coconut.issubclass(data_type, (_coconut.map, _coconut.range, _coconut.abc.Iterator)): return args if _coconut.issubclass(data_type, _coconut.str): return "".join(args) return data_type(args) def fmap(func, obj): """fmap(func, obj) creates a copy of obj with func applied to its contents. Override by defining obj.__fmap__(func).""" if _coconut.hasattr(obj, "__fmap__"): return obj.__fmap__(func) if obj.__class__.__module__ == "numpy": from numpy import vectorize return vectorize(func)(obj) return _coconut_makedata(obj.__class__, *(_coconut_starmap(func, obj.items()) if _coconut.isinstance(obj, _coconut.abc.Mapping) else _coconut_map(func, obj))) def memoize(maxsize=None, *args, **kwargs): """Decorator that memoizes a function, preventing it from being recomputed if it is called multiple times with the same arguments.""" return _coconut.functools.lru_cache(maxsize, *args, **kwargs) _coconut_MatchError, _coconut_count, _coconut_enumerate, _coconut_makedata, _coconut_map, _coconut_reversed, _coconut_starmap, _coconut_tee, _coconut_zip, TYPE_CHECKING, reduce, takewhile, dropwhile = MatchError, count, enumerate, makedata, map, reversed, starmap, tee, zip, False, _coconut.functools.reduce, _coconut.itertools.takewhile, _coconut.itertools.dropwhile