1 # Copyright (c) 2005 The Regents of The University of Michigan
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.
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.
27 __all__
= [ 'multidict' ]
29 class multidict(object):
30 __nodefault
= object()
31 def __init__(self
, parent
= {}, **kwargs
):
32 self
.dict = dict(**kwargs
)
37 return str(dict(self
.items()))
40 return `
dict(self
.items())`
42 def __contains__(self
, key
):
43 return self
.dict.has_key(key
) or self
.parent
.has_key(key
)
45 def __delitem__(self
, key
):
49 if key
in self
.parent
:
50 self
.deleted
[key
] = True
54 def __setitem__(self
, key
, value
):
55 self
.deleted
.pop(key
, False)
56 self
.dict[key
] = value
58 def __getitem__(self
, key
):
62 if not self
.deleted
.get(key
, False) and key
in self
.parent
:
63 return self
.parent
[key
]
68 return len(self
.dict) + len(self
.parent
)
71 for key
,value
in self
.dict.items():
75 for key
,value
in self
.parent
.next():
76 if key
not in self
.dict and key
not in self
.deleted
:
79 def has_key(self
, key
):
83 for item
in self
.next():
87 return [ item
for item
in self
.next() ]
90 for key
,value
in self
.next():
94 return [ key
for key
,value
in self
.next() ]
97 for key
,value
in self
.next():
101 return [ value
for key
,value
in self
.next() ]
103 def get(self
, key
, default
=__nodefault
):
107 if default
!= self
.__nodefault
:
112 def setdefault(self
, key
, default
):
116 self
.deleted
.pop(key
, False)
117 self
.dict[key
] = default
121 print 'multidict dump'
123 while isinstance(node
, multidict
):
127 def _dumpkey(self
, key
):
130 while isinstance(node
, multidict
):
132 values
.append(node
.dict[key
])
136 if __name__
== '__main__':
138 test2
= multidict(test1
)
139 test3
= multidict(test2
)
140 test4
= multidict(test3
)
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'
148 test2
['a'] = 'test2_a'
150 test2
['c'] = 'test2_c'
153 test2
.setdefault('f', multidict
)
155 print 'test1>', test1
.items()
156 print 'test2>', test2
.items()
169 for key
in test2
.iterkeys():
172 test2
.get('g', 'foo')
174 test2
.get('b', 'bar')
175 test2
.setdefault('b', 'blah')
182 test3
['a'] = [ 0, 1, 2, 3 ]