multidict.py revision 13709:dd6b7ac5801f
112841Sgabeblack@google.com# Copyright (c) 2005 The Regents of The University of Michigan
212841Sgabeblack@google.com# All rights reserved.
312841Sgabeblack@google.com#
412841Sgabeblack@google.com# Redistribution and use in source and binary forms, with or without
512841Sgabeblack@google.com# modification, are permitted provided that the following conditions are
612841Sgabeblack@google.com# met: redistributions of source code must retain the above copyright
712841Sgabeblack@google.com# notice, this list of conditions and the following disclaimer;
812841Sgabeblack@google.com# redistributions in binary form must reproduce the above copyright
912841Sgabeblack@google.com# notice, this list of conditions and the following disclaimer in the
1012841Sgabeblack@google.com# documentation and/or other materials provided with the distribution;
1112841Sgabeblack@google.com# neither the name of the copyright holders nor the names of its
1212841Sgabeblack@google.com# contributors may be used to endorse or promote products derived from
1312841Sgabeblack@google.com# this software without specific prior written permission.
1412841Sgabeblack@google.com#
1512841Sgabeblack@google.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1612841Sgabeblack@google.com# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1712841Sgabeblack@google.com# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1812841Sgabeblack@google.com# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1912841Sgabeblack@google.com# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2012841Sgabeblack@google.com# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2112841Sgabeblack@google.com# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2212841Sgabeblack@google.com# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2312841Sgabeblack@google.com# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2412841Sgabeblack@google.com# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2512841Sgabeblack@google.com# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2612841Sgabeblack@google.com#
2712841Sgabeblack@google.com# Authors: Nathan Binkert
2812841Sgabeblack@google.com
2912841Sgabeblack@google.comfrom __future__ import print_function
3012841Sgabeblack@google.com
3112841Sgabeblack@google.com__all__ = [ 'multidict' ]
3212841Sgabeblack@google.com
3312841Sgabeblack@google.comclass multidict(object):
3412841Sgabeblack@google.com    def __init__(self, parent = {}, **kwargs):
3512841Sgabeblack@google.com        self.local = dict(**kwargs)
3612841Sgabeblack@google.com        self.parent = parent
3712841Sgabeblack@google.com        self.deleted = {}
3812841Sgabeblack@google.com
3912841Sgabeblack@google.com    def __str__(self):
4012841Sgabeblack@google.com        return str(dict(self.items()))
4112841Sgabeblack@google.com
4212841Sgabeblack@google.com    def __repr__(self):
4312841Sgabeblack@google.com        return repr(dict(list(self.items())))
4412841Sgabeblack@google.com
4512841Sgabeblack@google.com    def __contains__(self, key):
4612841Sgabeblack@google.com        return key in self.local or key in self.parent
4712841Sgabeblack@google.com
4812841Sgabeblack@google.com    def __delitem__(self, key):
4912841Sgabeblack@google.com        try:
5012841Sgabeblack@google.com            del self.local[key]
5112841Sgabeblack@google.com        except KeyError as e:
5212841Sgabeblack@google.com            if key in self.parent:
5312841Sgabeblack@google.com                self.deleted[key] = True
5412841Sgabeblack@google.com            else:
5512841Sgabeblack@google.com                raise KeyError(e)
5612841Sgabeblack@google.com
5712841Sgabeblack@google.com    def __setitem__(self, key, value):
5812841Sgabeblack@google.com        self.deleted.pop(key, False)
5912841Sgabeblack@google.com        self.local[key] = value
6012841Sgabeblack@google.com
6112841Sgabeblack@google.com    def __getitem__(self, key):
6212841Sgabeblack@google.com        try:
6312841Sgabeblack@google.com            return self.local[key]
6412841Sgabeblack@google.com        except KeyError as e:
6512841Sgabeblack@google.com            if not self.deleted.get(key, False) and key in self.parent:
6612841Sgabeblack@google.com                return self.parent[key]
6712841Sgabeblack@google.com            else:
6812841Sgabeblack@google.com                raise KeyError(e)
6912841Sgabeblack@google.com
7012841Sgabeblack@google.com    def __len__(self):
7112841Sgabeblack@google.com        return len(self.local) + len(self.parent)
7212841Sgabeblack@google.com
7312841Sgabeblack@google.com    def next(self):
7412841Sgabeblack@google.com        for key,value in self.local.items():
7512841Sgabeblack@google.com            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 items(self):
86        for item in self.next():
87            yield item
88
89    def keys(self):
90        for key,value in self.next():
91            yield key
92
93    def values(self):
94        for key,value in self.next():
95            yield value
96
97    def get(self, key, default=None):
98        try:
99            return self[key]
100        except KeyError as e:
101            return default
102
103    def setdefault(self, key, default):
104        try:
105            return self[key]
106        except KeyError:
107            self.deleted.pop(key, False)
108            self.local[key] = default
109            return default
110
111    def _dump(self):
112        print('multidict dump')
113        node = self
114        while isinstance(node, multidict):
115            print('    ', node.local)
116            node = node.parent
117
118    def _dumpkey(self, key):
119        values = []
120        node = self
121        while isinstance(node, multidict):
122            if key in node.local:
123                values.append(node.local[key])
124            node = node.parent
125        print(key, values)
126
127if __name__ == '__main__':
128    test1 = multidict()
129    test2 = multidict(test1)
130    test3 = multidict(test2)
131    test4 = multidict(test3)
132
133    test1['a'] = 'test1_a'
134    test1['b'] = 'test1_b'
135    test1['c'] = 'test1_c'
136    test1['d'] = 'test1_d'
137    test1['e'] = 'test1_e'
138
139    test2['a'] = 'test2_a'
140    del test2['b']
141    test2['c'] = 'test2_c'
142    del test1['a']
143
144    test2.setdefault('f', multidict)
145
146    print('test1>', list(test1.items()))
147    print('test2>', list(test2.items()))
148    #print(test1['a'])
149    print(test1['b'])
150    print(test1['c'])
151    print(test1['d'])
152    print(test1['e'])
153
154    print(test2['a'])
155    #print(test2['b'])
156    print(test2['c'])
157    print(test2['d'])
158    print(test2['e'])
159
160    for key in test2.keys():
161        print(key)
162
163    test2.get('g', 'foo')
164    #test2.get('b')
165    test2.get('b', 'bar')
166    test2.setdefault('b', 'blah')
167    print(test1)
168    print(test2)
169    print(repr(test2))
170
171    print(len(test2))
172
173    test3['a'] = [ 0, 1, 2, 3 ]
174
175    print(test4)
176