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 repr(dict(list(self.items()))) 44 45 def __contains__(self, key): 46 return key in self.local or key in self.parent 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 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