diff options
Diffstat (limited to 'module/lib')
| -rw-r--r-- | module/lib/new_collections.py | 375 | 
1 files changed, 375 insertions, 0 deletions
| diff --git a/module/lib/new_collections.py b/module/lib/new_collections.py new file mode 100644 index 000000000..12d05b4b9 --- /dev/null +++ b/module/lib/new_collections.py @@ -0,0 +1,375 @@ +## {{{ http://code.activestate.com/recipes/576693/ (r9) +# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy. +# Passes Python2.7's test suite and incorporates all the latest updates. + +try: +    from thread import get_ident as _get_ident +except ImportError: +    from dummy_thread import get_ident as _get_ident + +try: +    from _abcoll import KeysView, ValuesView, ItemsView +except ImportError: +    pass + + +class OrderedDict(dict): +    'Dictionary that remembers insertion order' +    # An inherited dict maps keys to values. +    # The inherited dict provides __getitem__, __len__, __contains__, and get. +    # The remaining methods are order-aware. +    # Big-O running times for all methods are the same as for regular dictionaries. + +    # The internal self.__map dictionary maps keys to links in a doubly linked list. +    # The circular doubly linked list starts and ends with a sentinel element. +    # The sentinel element never gets deleted (this simplifies the algorithm). +    # Each link is stored as a list of length three:  [PREV, NEXT, KEY]. + +    def __init__(self, *args, **kwds): +        '''Initialize an ordered dictionary.  Signature is the same as for +        regular dictionaries, but keyword arguments are not recommended +        because their insertion order is arbitrary. + +        ''' +        if len(args) > 1: +            raise TypeError('expected at most 1 arguments, got %d' % len(args)) +        try: +            self.__root +        except AttributeError: +            self.__root = root = []                     # sentinel node +            root[:] = [root, root, None] +            self.__map = {} +        self.__update(*args, **kwds) + +    def __setitem__(self, key, value, dict_setitem=dict.__setitem__): +        'od.__setitem__(i, y) <==> od[i]=y' +        # Setting a new item creates a new link which goes at the end of the linked +        # list, and the inherited dictionary is updated with the new key/value pair. +        if key not in self: +            root = self.__root +            last = root[0] +            last[1] = root[0] = self.__map[key] = [last, root, key] +        dict_setitem(self, key, value) + +    def __delitem__(self, key, dict_delitem=dict.__delitem__): +        'od.__delitem__(y) <==> del od[y]' +        # Deleting an existing item uses self.__map to find the link which is +        # then removed by updating the links in the predecessor and successor nodes. +        dict_delitem(self, key) +        link_prev, link_next, key = self.__map.pop(key) +        link_prev[1] = link_next +        link_next[0] = link_prev + +    def __iter__(self): +        'od.__iter__() <==> iter(od)' +        root = self.__root +        curr = root[1] +        while curr is not root: +            yield curr[2] +            curr = curr[1] + +    def __reversed__(self): +        'od.__reversed__() <==> reversed(od)' +        root = self.__root +        curr = root[0] +        while curr is not root: +            yield curr[2] +            curr = curr[0] + +    def clear(self): +        'od.clear() -> None.  Remove all items from od.' +        try: +            for node in self.__map.itervalues(): +                del node[:] +            root = self.__root +            root[:] = [root, root, None] +            self.__map.clear() +        except AttributeError: +            pass +        dict.clear(self) + +    def popitem(self, last=True): +        '''od.popitem() -> (k, v), return and remove a (key, value) pair. +        Pairs are returned in LIFO order if last is true or FIFO order if false. + +        ''' +        if not self: +            raise KeyError('dictionary is empty') +        root = self.__root +        if last: +            link = root[0] +            link_prev = link[0] +            link_prev[1] = root +            root[0] = link_prev +        else: +            link = root[1] +            link_next = link[1] +            root[1] = link_next +            link_next[0] = root +        key = link[2] +        del self.__map[key] +        value = dict.pop(self, key) +        return key, value + +    # -- the following methods do not depend on the internal structure -- + +    def keys(self): +        'od.keys() -> list of keys in od' +        return list(self) + +    def values(self): +        'od.values() -> list of values in od' +        return [self[key] for key in self] + +    def items(self): +        'od.items() -> list of (key, value) pairs in od' +        return [(key, self[key]) for key in self] + +    def iterkeys(self): +        'od.iterkeys() -> an iterator over the keys in od' +        return iter(self) + +    def itervalues(self): +        'od.itervalues -> an iterator over the values in od' +        for k in self: +            yield self[k] + +    def iteritems(self): +        'od.iteritems -> an iterator over the (key, value) items in od' +        for k in self: +            yield (k, self[k]) + +    def update(*args, **kwds): +        '''od.update(E, **F) -> None.  Update od from dict/iterable E and F. + +        If E is a dict instance, does:           for k in E: od[k] = E[k] +        If E has a .keys() method, does:         for k in E.keys(): od[k] = E[k] +        Or if E is an iterable of items, does:   for k, v in E: od[k] = v +        In either case, this is followed by:     for k, v in F.items(): od[k] = v + +        ''' +        if len(args) > 2: +            raise TypeError('update() takes at most 2 positional ' +                            'arguments (%d given)' % (len(args),)) +        elif not args: +            raise TypeError('update() takes at least 1 argument (0 given)') +        self = args[0] +        # Make progressively weaker assumptions about "other" +        other = () +        if len(args) == 2: +            other = args[1] +        if isinstance(other, dict): +            for key in other: +                self[key] = other[key] +        elif hasattr(other, 'keys'): +            for key in other.keys(): +                self[key] = other[key] +        else: +            for key, value in other: +                self[key] = value +        for key, value in kwds.items(): +            self[key] = value + +    __update = update  # let subclasses override update without breaking __init__ + +    __marker = object() + +    def pop(self, key, default=__marker): +        '''od.pop(k[,d]) -> v, remove specified key and return the corresponding value. +        If key is not found, d is returned if given, otherwise KeyError is raised. + +        ''' +        if key in self: +            result = self[key] +            del self[key] +            return result +        if default is self.__marker: +            raise KeyError(key) +        return default + +    def setdefault(self, key, default=None): +        'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od' +        if key in self: +            return self[key] +        self[key] = default +        return default + +    def __repr__(self, _repr_running={}): +        'od.__repr__() <==> repr(od)' +        call_key = id(self), _get_ident() +        if call_key in _repr_running: +            return '...' +        _repr_running[call_key] = 1 +        try: +            if not self: +                return '%s()' % (self.__class__.__name__,) +            return '%s(%r)' % (self.__class__.__name__, self.items()) +        finally: +            del _repr_running[call_key] + +    def __reduce__(self): +        'Return state information for pickling' +        items = [[k, self[k]] for k in self] +        inst_dict = vars(self).copy() +        for k in vars(OrderedDict()): +            inst_dict.pop(k, None) +        if inst_dict: +            return (self.__class__, (items,), inst_dict) +        return self.__class__, (items,) + +    def copy(self): +        'od.copy() -> a shallow copy of od' +        return self.__class__(self) + +    @classmethod +    def fromkeys(cls, iterable, value=None): +        '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S +        and values equal to v (which defaults to None). + +        ''' +        d = cls() +        for key in iterable: +            d[key] = value +        return d + +    def __eq__(self, other): +        '''od.__eq__(y) <==> od==y.  Comparison to another OD is order-sensitive +        while comparison to a regular mapping is order-insensitive. + +        ''' +        if isinstance(other, OrderedDict): +            return len(self)==len(other) and self.items() == other.items() +        return dict.__eq__(self, other) + +    def __ne__(self, other): +        return not self == other + +    # -- the following methods are only used in Python 2.7 -- + +    def viewkeys(self): +        "od.viewkeys() -> a set-like object providing a view on od's keys" +        return KeysView(self) + +    def viewvalues(self): +        "od.viewvalues() -> an object providing a view on od's values" +        return ValuesView(self) + +    def viewitems(self): +        "od.viewitems() -> a set-like object providing a view on od's items" +        return ItemsView(self) +## end of http://code.activestate.com/recipes/576693/ }}} + +## {{{ http://code.activestate.com/recipes/500261/ (r15) +from operator import itemgetter as _itemgetter +from keyword import iskeyword as _iskeyword +import sys as _sys + +def namedtuple(typename, field_names, verbose=False, rename=False): +    """Returns a new subclass of tuple with named fields. + +    >>> Point = namedtuple('Point', 'x y') +    >>> Point.__doc__                   # docstring for the new class +    'Point(x, y)' +    >>> p = Point(11, y=22)             # instantiate with positional args or keywords +    >>> p[0] + p[1]                     # indexable like a plain tuple +    33 +    >>> x, y = p                        # unpack like a regular tuple +    >>> x, y +    (11, 22) +    >>> p.x + p.y                       # fields also accessable by name +    33 +    >>> d = p._asdict()                 # convert to a dictionary +    >>> d['x'] +    11 +    >>> Point(**d)                      # convert from a dictionary +    Point(x=11, y=22) +    >>> p._replace(x=100)               # _replace() is like str.replace() but targets named fields +    Point(x=100, y=22) + +    """ + +    # Parse and validate the field names.  Validation serves two purposes, +    # generating informative error messages and preventing template injection attacks. +    if isinstance(field_names, basestring): +        field_names = field_names.replace(',', ' ').split() # names separated by whitespace and/or commas +    field_names = tuple(map(str, field_names)) +    if rename: +        names = list(field_names) +        seen = set() +        for i, name in enumerate(names): +            if (not min(c.isalnum() or c=='_' for c in name) or _iskeyword(name) +                or not name or name[0].isdigit() or name.startswith('_') +                or name in seen): +                    names[i] = '_%d' % i +            seen.add(name) +        field_names = tuple(names) +    for name in (typename,) + field_names: +        if not min(c.isalnum() or c=='_' for c in name): +            raise ValueError('Type names and field names can only contain alphanumeric characters and underscores: %r' % name) +        if _iskeyword(name): +            raise ValueError('Type names and field names cannot be a keyword: %r' % name) +        if name[0].isdigit(): +            raise ValueError('Type names and field names cannot start with a number: %r' % name) +    seen_names = set() +    for name in field_names: +        if name.startswith('_') and not rename: +            raise ValueError('Field names cannot start with an underscore: %r' % name) +        if name in seen_names: +            raise ValueError('Encountered duplicate field name: %r' % name) +        seen_names.add(name) + +    # Create and fill-in the class template +    numfields = len(field_names) +    argtxt = repr(field_names).replace("'", "")[1:-1]   # tuple repr without parens or quotes +    reprtxt = ', '.join('%s=%%r' % name for name in field_names) +    template = '''class %(typename)s(tuple): +        '%(typename)s(%(argtxt)s)' \n +        __slots__ = () \n +        _fields = %(field_names)r \n +        def __new__(_cls, %(argtxt)s): +            return _tuple.__new__(_cls, (%(argtxt)s)) \n +        @classmethod +        def _make(cls, iterable, new=tuple.__new__, len=len): +            'Make a new %(typename)s object from a sequence or iterable' +            result = new(cls, iterable) +            if len(result) != %(numfields)d: +                raise TypeError('Expected %(numfields)d arguments, got %%d' %% len(result)) +            return result \n +        def __repr__(self): +            return '%(typename)s(%(reprtxt)s)' %% self \n +        def _asdict(self): +            'Return a new dict which maps field names to their values' +            return dict(zip(self._fields, self)) \n +        def _replace(_self, **kwds): +            'Return a new %(typename)s object replacing specified fields with new values' +            result = _self._make(map(kwds.pop, %(field_names)r, _self)) +            if kwds: +                raise ValueError('Got unexpected field names: %%r' %% kwds.keys()) +            return result \n +        def __getnewargs__(self): +            return tuple(self) \n\n''' % locals() +    for i, name in enumerate(field_names): +        template += '        %s = _property(_itemgetter(%d))\n' % (name, i) +    if verbose: +        print template + +    # Execute the template string in a temporary namespace +    namespace = dict(_itemgetter=_itemgetter, __name__='namedtuple_%s' % typename, +                     _property=property, _tuple=tuple) +    try: +        exec template in namespace +    except SyntaxError, e: +        raise SyntaxError(e.message + ':\n' + template) +    result = namespace[typename] + +    # For pickling to work, the __module__ variable needs to be set to the frame +    # where the named tuple is created.  Bypass this step in enviroments where +    # sys._getframe is not defined (Jython for example) or sys._getframe is not +    # defined for arguments greater than 0 (IronPython). +    try: +        result.__module__ = _sys._getframe(1).f_globals.get('__name__', '__main__') +    except (AttributeError, ValueError): +        pass + +    return result +## end of http://code.activestate.com/recipes/500261/ }}} | 
