web/hdabo/utils.py
author ymh <ymh.work@gmail.com>
Fri, 08 Jul 2011 13:31:34 +0200
changeset 74 85f7f99c044c
parent 72 ba8ebabbaece
child 111 ceb381f5b0c7
permissions -rw-r--r--
improve normalization
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
24
8f84b9bbd22d add wikipedia link edition
ymh <ymh.work@gmail.com>
parents: 11
diff changeset
     1
# -*- coding: utf-8 -*-
11
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
     2
import collections
56
e70cbbc093cc improve tag letter list
ymh <ymh.work@gmail.com>
parents: 49
diff changeset
     3
import unicodedata
11
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
     4
0
896db0083b76 first commit
ymh <ymh.work@gmail.com>
parents:
diff changeset
     5
896db0083b76 first commit
ymh <ymh.work@gmail.com>
parents:
diff changeset
     6
###
896db0083b76 first commit
ymh <ymh.work@gmail.com>
parents:
diff changeset
     7
# allow to declare a property as a decorator
896db0083b76 first commit
ymh <ymh.work@gmail.com>
parents:
diff changeset
     8
###
896db0083b76 first commit
ymh <ymh.work@gmail.com>
parents:
diff changeset
     9
def Property(func):
11
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    10
    return property(**func())
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    11
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    12
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    13
## {{{ http://code.activestate.com/recipes/576694/ (r7)
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    14
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    15
KEY, PREV, NEXT = range(3)
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    16
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    17
class OrderedSet(collections.MutableSet):
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    18
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    19
    def __init__(self, iterable=None):
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    20
        self.end = end = [] 
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    21
        end += [None, end, end]         # sentinel node for doubly linked list
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    22
        self.map = {}                   # key --> [key, prev, next]
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    23
        if iterable is not None:
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    24
            self |= iterable
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    25
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    26
    def __len__(self):
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    27
        return len(self.map)
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    28
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    29
    def __contains__(self, key):
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    30
        return key in self.map
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    31
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    32
    def add(self, key):
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    33
        if key not in self.map:
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    34
            end = self.end
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    35
            curr = end[PREV]
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    36
            curr[NEXT] = end[PREV] = self.map[key] = [key, curr, end]
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    37
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    38
    def discard(self, key):
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    39
        if key in self.map:        
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    40
            key, prev, next = self.map.pop(key)
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    41
            prev[NEXT] = next
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    42
            next[PREV] = prev
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    43
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    44
    def __iter__(self):
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    45
        end = self.end
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    46
        curr = end[NEXT]
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    47
        while curr is not end:
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    48
            yield curr[KEY]
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    49
            curr = curr[NEXT]
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    50
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    51
    def __reversed__(self):
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    52
        end = self.end
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    53
        curr = end[PREV]
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    54
        while curr is not end:
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    55
            yield curr[KEY]
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    56
            curr = curr[PREV]
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    57
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    58
    def pop(self, last=True):
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    59
        if not self:
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    60
            raise KeyError('set is empty')
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    61
        key = next(reversed(self)) if last else next(iter(self))
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    62
        self.discard(key)
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    63
        return key
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    64
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    65
    def __repr__(self):
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    66
        if not self:
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    67
            return '%s()' % (self.__class__.__name__,)
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    68
        return '%s(%r)' % (self.__class__.__name__, list(self))
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    69
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    70
    def __eq__(self, other):
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    71
        if isinstance(other, OrderedSet):
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    72
            return len(self) == len(other) and list(self) == list(other)
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    73
        return set(self) == set(other)
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    74
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    75
    def __del__(self):
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    76
        self.clear()                    # remove circular references
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    77
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    78
            
143ab88d17f8 add ordered manytomany fields and indexing
ymh <ymh.work@gmail.com>
parents: 0
diff changeset
    79
## end of http://code.activestate.com/recipes/576694/ }}}
24
8f84b9bbd22d add wikipedia link edition
ymh <ymh.work@gmail.com>
parents: 11
diff changeset
    80
46
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
    81
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
    82
## {{{ http://code.activestate.com/recipes/576693/ (r9)
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
    83
# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy.
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
    84
# Passes Python2.7's test suite and incorporates all the latest updates.
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
    85
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
    86
try:
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
    87
    from thread import get_ident as _get_ident
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
    88
except ImportError:
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
    89
    from dummy_thread import get_ident as _get_ident
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
    90
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
    91
try:
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
    92
    from _abcoll import KeysView, ValuesView, ItemsView
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
    93
except ImportError:
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
    94
    pass
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
    95
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
    96
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
    97
class OrderedDict(dict):
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
    98
    'Dictionary that remembers insertion order'
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
    99
    # An inherited dict maps keys to values.
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   100
    # The inherited dict provides __getitem__, __len__, __contains__, and get.
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   101
    # The remaining methods are order-aware.
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   102
    # Big-O running times for all methods are the same as for regular dictionaries.
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   103
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   104
    # The internal self.__map dictionary maps keys to links in a doubly linked list.
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   105
    # The circular doubly linked list starts and ends with a sentinel element.
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   106
    # The sentinel element never gets deleted (this simplifies the algorithm).
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   107
    # Each link is stored as a list of length three:  [PREV, NEXT, KEY].
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   108
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   109
    def __init__(self, *args, **kwds):
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   110
        '''Initialize an ordered dictionary.  Signature is the same as for
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   111
        regular dictionaries, but keyword arguments are not recommended
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   112
        because their insertion order is arbitrary.
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   113
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   114
        '''
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   115
        if len(args) > 1:
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   116
            raise TypeError('expected at most 1 arguments, got %d' % len(args))
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   117
        try:
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   118
            self.__root
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   119
        except AttributeError:
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   120
            self.__root = root = []                     # sentinel node
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   121
            root[:] = [root, root, None]
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   122
            self.__map = {}
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   123
        self.__update(*args, **kwds)
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   124
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   125
    def __setitem__(self, key, value, dict_setitem=dict.__setitem__):
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   126
        'od.__setitem__(i, y) <==> od[i]=y'
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   127
        # Setting a new item creates a new link which goes at the end of the linked
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   128
        # list, and the inherited dictionary is updated with the new key/value pair.
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   129
        if key not in self:
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   130
            root = self.__root
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   131
            last = root[0]
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   132
            last[1] = root[0] = self.__map[key] = [last, root, key]
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   133
        dict_setitem(self, key, value)
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   134
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   135
    def __delitem__(self, key, dict_delitem=dict.__delitem__):
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   136
        'od.__delitem__(y) <==> del od[y]'
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   137
        # Deleting an existing item uses self.__map to find the link which is
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   138
        # then removed by updating the links in the predecessor and successor nodes.
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   139
        dict_delitem(self, key)
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   140
        link_prev, link_next, key = self.__map.pop(key)
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   141
        link_prev[1] = link_next
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   142
        link_next[0] = link_prev
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   143
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   144
    def __iter__(self):
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   145
        'od.__iter__() <==> iter(od)'
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   146
        root = self.__root
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   147
        curr = root[1]
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   148
        while curr is not root:
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   149
            yield curr[2]
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   150
            curr = curr[1]
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   151
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   152
    def __reversed__(self):
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   153
        'od.__reversed__() <==> reversed(od)'
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   154
        root = self.__root
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   155
        curr = root[0]
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   156
        while curr is not root:
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   157
            yield curr[2]
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   158
            curr = curr[0]
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   159
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   160
    def clear(self):
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   161
        'od.clear() -> None.  Remove all items from od.'
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   162
        try:
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   163
            for node in self.__map.itervalues():
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   164
                del node[:]
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   165
            root = self.__root
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   166
            root[:] = [root, root, None]
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   167
            self.__map.clear()
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   168
        except AttributeError:
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   169
            pass
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   170
        dict.clear(self)
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   171
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   172
    def popitem(self, last=True):
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   173
        '''od.popitem() -> (k, v), return and remove a (key, value) pair.
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   174
        Pairs are returned in LIFO order if last is true or FIFO order if false.
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   175
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   176
        '''
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   177
        if not self:
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   178
            raise KeyError('dictionary is empty')
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   179
        root = self.__root
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   180
        if last:
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   181
            link = root[0]
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   182
            link_prev = link[0]
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   183
            link_prev[1] = root
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   184
            root[0] = link_prev
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   185
        else:
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   186
            link = root[1]
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   187
            link_next = link[1]
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   188
            root[1] = link_next
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   189
            link_next[0] = root
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   190
        key = link[2]
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   191
        del self.__map[key]
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   192
        value = dict.pop(self, key)
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   193
        return key, value
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   194
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   195
    # -- the following methods do not depend on the internal structure --
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   196
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   197
    def keys(self):
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   198
        'od.keys() -> list of keys in od'
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   199
        return list(self)
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   200
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   201
    def values(self):
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   202
        'od.values() -> list of values in od'
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   203
        return [self[key] for key in self]
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   204
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   205
    def items(self):
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   206
        'od.items() -> list of (key, value) pairs in od'
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   207
        return [(key, self[key]) for key in self]
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   208
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   209
    def iterkeys(self):
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   210
        'od.iterkeys() -> an iterator over the keys in od'
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   211
        return iter(self)
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   212
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   213
    def itervalues(self):
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   214
        'od.itervalues -> an iterator over the values in od'
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   215
        for k in self:
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   216
            yield self[k]
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   217
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   218
    def iteritems(self):
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   219
        'od.iteritems -> an iterator over the (key, value) items in od'
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   220
        for k in self:
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   221
            yield (k, self[k])
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   222
49
55e5f8a878ae add the version context_processor and correct css to display it correctly
ymh <ymh.work@gmail.com>
parents: 46
diff changeset
   223
    def update(*args, **kwds): #@NoSelf
46
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   224
        '''od.update(E, **F) -> None.  Update od from dict/iterable E and F.
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   225
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   226
        If E is a dict instance, does:           for k in E: od[k] = E[k]
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   227
        If E has a .keys() method, does:         for k in E.keys(): od[k] = E[k]
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   228
        Or if E is an iterable of items, does:   for k, v in E: od[k] = v
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   229
        In either case, this is followed by:     for k, v in F.items(): od[k] = v
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   230
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   231
        '''
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   232
        if len(args) > 2:
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   233
            raise TypeError('update() takes at most 2 positional '
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   234
                            'arguments (%d given)' % (len(args),))
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   235
        elif not args:
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   236
            raise TypeError('update() takes at least 1 argument (0 given)')
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   237
        self = args[0]
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   238
        # Make progressively weaker assumptions about "other"
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   239
        other = ()
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   240
        if len(args) == 2:
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   241
            other = args[1]
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   242
        if isinstance(other, dict):
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   243
            for key in other:
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   244
                self[key] = other[key]
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   245
        elif hasattr(other, 'keys'):
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   246
            for key in other.keys():
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   247
                self[key] = other[key]
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   248
        else:
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   249
            for key, value in other:
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   250
                self[key] = value
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   251
        for key, value in kwds.items():
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   252
            self[key] = value
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   253
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   254
    __update = update  # let subclasses override update without breaking __init__
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   255
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   256
    __marker = object()
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   257
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   258
    def pop(self, key, default=__marker):
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   259
        '''od.pop(k[,d]) -> v, remove specified key and return the corresponding value.
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   260
        If key is not found, d is returned if given, otherwise KeyError is raised.
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   261
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   262
        '''
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   263
        if key in self:
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   264
            result = self[key]
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   265
            del self[key]
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   266
            return result
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   267
        if default is self.__marker:
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   268
            raise KeyError(key)
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   269
        return default
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   270
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   271
    def setdefault(self, key, default=None):
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   272
        'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od'
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   273
        if key in self:
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   274
            return self[key]
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   275
        self[key] = default
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   276
        return default
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   277
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   278
    def __repr__(self, _repr_running={}):
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   279
        'od.__repr__() <==> repr(od)'
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   280
        call_key = id(self), _get_ident()
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   281
        if call_key in _repr_running:
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   282
            return '...'
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   283
        _repr_running[call_key] = 1
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   284
        try:
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   285
            if not self:
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   286
                return '%s()' % (self.__class__.__name__,)
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   287
            return '%s(%r)' % (self.__class__.__name__, self.items())
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   288
        finally:
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   289
            del _repr_running[call_key]
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   290
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   291
    def __reduce__(self):
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   292
        'Return state information for pickling'
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   293
        items = [[k, self[k]] for k in self]
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   294
        inst_dict = vars(self).copy()
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   295
        for k in vars(OrderedDict()):
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   296
            inst_dict.pop(k, None)
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   297
        if inst_dict:
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   298
            return (self.__class__, (items,), inst_dict)
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   299
        return self.__class__, (items,)
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   300
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   301
    def copy(self):
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   302
        'od.copy() -> a shallow copy of od'
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   303
        return self.__class__(self)
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   304
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   305
    @classmethod
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   306
    def fromkeys(cls, iterable, value=None):
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   307
        '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   308
        and values equal to v (which defaults to None).
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   309
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   310
        '''
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   311
        d = cls()
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   312
        for key in iterable:
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   313
            d[key] = value
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   314
        return d
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   315
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   316
    def __eq__(self, other):
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   317
        '''od.__eq__(y) <==> od==y.  Comparison to another OD is order-sensitive
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   318
        while comparison to a regular mapping is order-insensitive.
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   319
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   320
        '''
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   321
        if isinstance(other, OrderedDict):
56
e70cbbc093cc improve tag letter list
ymh <ymh.work@gmail.com>
parents: 49
diff changeset
   322
            return len(self) == len(other) and self.items() == other.items()
46
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   323
        return dict.__eq__(self, other)
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   324
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   325
    def __ne__(self, other):
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   326
        return not self == other
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   327
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   328
    # -- the following methods are only used in Python 2.7 --
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   329
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   330
    def viewkeys(self):
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   331
        "od.viewkeys() -> a set-like object providing a view on od's keys"
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   332
        return KeysView(self)
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   333
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   334
    def viewvalues(self):
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   335
        "od.viewvalues() -> an object providing a view on od's values"
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   336
        return ValuesView(self)
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   337
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   338
    def viewitems(self):
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   339
        "od.viewitems() -> a set-like object providing a view on od's items"
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   340
        return ItemsView(self)
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   341
## end of http://code.activestate.com/recipes/576693/ }}}
3ad571e54608 get categories enhancement.
cavaliet
parents: 24
diff changeset
   342
56
e70cbbc093cc improve tag letter list
ymh <ymh.work@gmail.com>
parents: 49
diff changeset
   343
def remove_accents(str):
e70cbbc093cc improve tag letter list
ymh <ymh.work@gmail.com>
parents: 49
diff changeset
   344
    nkfd_form = unicodedata.normalize('NFKD', unicode(str))
e70cbbc093cc improve tag letter list
ymh <ymh.work@gmail.com>
parents: 49
diff changeset
   345
    return u"".join([c for c in nkfd_form if not unicodedata.combining(c)])
72
ba8ebabbaece -correct css and display
ymh <ymh.work@gmail.com>
parents: 56
diff changeset
   346
ba8ebabbaece -correct css and display
ymh <ymh.work@gmail.com>
parents: 56
diff changeset
   347
def normalize(str):
74
85f7f99c044c improve normalization
ymh <ymh.work@gmail.com>
parents: 72
diff changeset
   348
    return remove_accents(str).lower().replace(u"œ",u"oe")