multidict.py revision 13663:9b64aeabf9a5
1# Copyright (c) 2005 The Regents of The University of Michigan
2# All rights reserved.
3#
4# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions are
6# met: redistributions of source code must retain the above copyright
7# notice, this list of conditions and the following disclaimer;
8# redistributions in binary form must reproduce the above copyright
9# notice, this list of conditions and the following disclaimer in the
10# documentation and/or other materials provided with the distribution;
11# neither the name of the copyright holders nor the names of its
12# contributors may be used to endorse or promote products derived from
13# this software without specific prior written permission.
14#
15# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26#
27# Authors: Nathan Binkert
28
29from __future__ import print_function
30
31__all__ = [ 'multidict' ]
32
33class multidict(object):
34    def __init__(self, parent = {}, **kwargs):
35        self.local = dict(**kwargs)
36        self.parent = parent
37        self.deleted = {}
38
39    def __str__(self):
40        return str(dict(self.items()))
41
42    def __repr__(self):
43        return `dict(self.items())`
44
45    def __contains__(self, key):
46        return self.local.has_key(key) or self.parent.has_key(key)
47
48    def __delitem__(self, key):
49        try:
50            del self.local[key]
51        except KeyError as e:
52            if key in self.parent:
53                self.deleted[key] = True
54            else:
55                raise KeyError(e)
56
57    def __setitem__(self, key, value):
58        self.deleted.pop(key, False)
59        self.local[key] = value
60
61    def __getitem__(self, key):
62        try:
63            return self.local[key]
64        except KeyError as e:
65            if not self.deleted.get(key, False) and key in self.parent:
66                return self.parent[key]
67            else:
68                raise KeyError(e)
69
70    def __len__(self):
71        return len(self.local) + len(self.parent)
72
73    def next(self):
74        for key,value in self.local.items():
75            yield key,value
76
77        if self.parent:
78            for key,value in self.parent.next():
79                if key not in self.local and key not in self.deleted:
80                    yield key,value
81
82    def has_key(self, key):
83        return key in self
84
85    def iteritems(self):
86        for item in self.next():
87            yield item
88
89    def items(self):
90        return [ item for item in self.next() ]
91
92    def iterkeys(self):
93        for key,value in self.next():
94            yield key
95
96    def keys(self):
97        return [ key for key,value in self.next() ]
98
99    def itervalues(self):
100        for key,value in self.next():
101            yield value
102
103    def values(self):
104        return [ value for key,value in self.next() ]
105
106    def get(self, key, default=None):
107        try:
108            return self[key]
109        except KeyError as e:
110            return default
111
112    def setdefault(self, key, default):
113        try:
114            return self[key]
115        except KeyError:
116            self.deleted.pop(key, False)
117            self.local[key] = default
118            return default
119
120    def _dump(self):
121        print('multidict dump')
122        node = self
123        while isinstance(node, multidict):
124            print('    ', node.local)
125            node = node.parent
126
127    def _dumpkey(self, key):
128        values = []
129        node = self
130        while isinstance(node, multidict):
131            if key in node.local:
132                values.append(node.local[key])
133            node = node.parent
134        print(key, values)
135
136if __name__ == '__main__':
137    test1 = multidict()
138    test2 = multidict(test1)
139    test3 = multidict(test2)
140    test4 = multidict(test3)
141
142    test1['a'] = 'test1_a'
143    test1['b'] = 'test1_b'
144    test1['c'] = 'test1_c'
145    test1['d'] = 'test1_d'
146    test1['e'] = 'test1_e'
147
148    test2['a'] = 'test2_a'
149    del test2['b']
150    test2['c'] = 'test2_c'
151    del test1['a']
152
153    test2.setdefault('f', multidict)
154
155    print('test1>', test1.items())
156    print('test2>', test2.items())
157    #print(test1['a'])
158    print(test1['b'])
159    print(test1['c'])
160    print(test1['d'])
161    print(test1['e'])
162
163    print(test2['a'])
164    #print(test2['b'])
165    print(test2['c'])
166    print(test2['d'])
167    print(test2['e'])
168
169    for key in test2.iterkeys():
170        print(key)
171
172    test2.get('g', 'foo')
173    #test2.get('b')
174    test2.get('b', 'bar')
175    test2.setdefault('b', 'blah')
176    print(test1)
177    print(test2)
178    print(`test2`)
179
180    print(len(test2))
181
182    test3['a'] = [ 0, 1, 2, 3 ]
183
184    print(test4)
185