2 Tools to mess with dicts.
6 from bisect import bisect_left, insort_left
8 from allmydata.util.assertutil import _assert, precondition
10 def move(k, d1, d2, strict=False):
12 Move item with key k from d1 to d2.
14 if strict and not d1.has_key(k):
22 Remove all items from d1 whose key occurs in d2.
36 class DictOfSets(dict):
37 def add(self, key, value):
41 self[key] = set([value])
43 def update(self, otherdictofsets):
44 for key, values in otherdictofsets.iteritems():
46 self[key].update(values)
48 self[key] = set(values)
50 def discard(self, key, value):
53 self[key].discard(value)
58 def __init__(self, initialdata={}):
60 self.update(initialdata)
62 def del_if_present(self, key):
66 def items_sorted_by_value(self):
68 @return a sequence of (key, value,) pairs sorted according to value
70 l = [(x[1], x[0],) for x in self.d.iteritems()]
72 return [(x[1], x[0],) for x in l]
74 def items_sorted_by_key(self):
76 @return a sequence of (key, value,) pairs sorted according to key
82 def __repr__(self, *args, **kwargs):
83 return self.d.__repr__(*args, **kwargs)
85 def __str__(self, *args, **kwargs):
86 return self.d.__str__(*args, **kwargs)
88 def __contains__(self, *args, **kwargs):
89 return self.d.__contains__(*args, **kwargs)
91 def __len__(self, *args, **kwargs):
92 return self.d.__len__(*args, **kwargs)
94 def __cmp__(self, other):
96 return self.d.__cmp__(other)
98 # maybe we should look for a .d member in other. I know this is insanely kludgey, but the Right Way To Do It is for dict.__cmp__ to use structural typing ("duck typing")
100 return self.d.__cmp__(other.d)
104 def __eq__(self, *args, **kwargs):
105 return self.d.__eq__(*args, **kwargs)
107 def __ne__(self, *args, **kwargs):
108 return self.d.__ne__(*args, **kwargs)
110 def __gt__(self, *args, **kwargs):
111 return self.d.__gt__(*args, **kwargs)
113 def __ge__(self, *args, **kwargs):
114 return self.d.__ge__(*args, **kwargs)
116 def __le__(self, *args, **kwargs):
117 return self.d.__le__(*args, **kwargs)
119 def __lt__(self, *args, **kwargs):
120 return self.d.__lt__(*args, **kwargs)
122 def __getitem__(self, *args, **kwargs):
123 return self.d.__getitem__(*args, **kwargs)
125 def __setitem__(self, *args, **kwargs):
126 return self.d.__setitem__(*args, **kwargs)
128 def __delitem__(self, *args, **kwargs):
129 return self.d.__delitem__(*args, **kwargs)
131 def __iter__(self, *args, **kwargs):
132 return self.d.__iter__(*args, **kwargs)
134 def clear(self, *args, **kwargs):
135 return self.d.clear(*args, **kwargs)
137 def copy(self, *args, **kwargs):
138 return self.__class__(self.d.copy(*args, **kwargs))
140 def fromkeys(self, *args, **kwargs):
141 return self.__class__(self.d.fromkeys(*args, **kwargs))
143 def get(self, key, default=None):
144 return self.d.get(key, default)
146 def has_key(self, *args, **kwargs):
147 return self.d.has_key(*args, **kwargs)
149 def items(self, *args, **kwargs):
150 return self.d.items(*args, **kwargs)
152 def iteritems(self, *args, **kwargs):
153 return self.d.iteritems(*args, **kwargs)
155 def iterkeys(self, *args, **kwargs):
156 return self.d.iterkeys(*args, **kwargs)
158 def itervalues(self, *args, **kwargs):
159 return self.d.itervalues(*args, **kwargs)
161 def keys(self, *args, **kwargs):
162 return self.d.keys(*args, **kwargs)
164 def pop(self, *args, **kwargs):
165 return self.d.pop(*args, **kwargs)
167 def popitem(self, *args, **kwargs):
168 return self.d.popitem(*args, **kwargs)
170 def setdefault(self, *args, **kwargs):
171 return self.d.setdefault(*args, **kwargs)
173 def update(self, *args, **kwargs):
174 self.d.update(*args, **kwargs)
176 def values(self, *args, **kwargs):
177 return self.d.values(*args, **kwargs)
180 def __init__(self, initialdict={}):
181 self.d = copy.deepcopy(initialdict)
183 def add_num(self, key, val, default=0):
185 If the key doesn't appear in self then it is created with value default
188 self.d[key] = self.d.get(key, default) + val
190 def subtract_num(self, key, val, default=0):
191 self.d[key] = self.d.get(key, default) - val
195 @return: the sum of all values
197 return reduce(operator.__add__, self.d.values())
199 def inc(self, key, default=0):
201 Increment the value associated with key in dict. If there is no such
202 key, then one will be created with initial value 0 (before inc() --
203 therefore value 1 after inc).
205 self.add_num(key, 1, default)
207 def dec(self, key, default=0):
209 Decrement the value associated with key in dict. If there is no such
210 key, then one will be created with initial value 0 (before dec() --
211 therefore value -1 after dec).
213 self.subtract_num(key, 1, default)
215 def items_sorted_by_value(self):
217 @return a sequence of (key, value,) pairs sorted according to value
219 l = [(x[1], x[0],) for x in self.d.iteritems()]
221 return [(x[1], x[0],) for x in l]
223 def item_with_largest_value(self):
224 it = self.d.iteritems()
225 (winner, winnerval,) = it.next()
232 except StopIteration:
234 return (winner, winnerval,)
236 def items_sorted_by_key(self):
238 @return a sequence of (key, value,) pairs sorted according to key
244 def __repr__(self, *args, **kwargs):
245 return self.d.__repr__(*args, **kwargs)
247 def __str__(self, *args, **kwargs):
248 return self.d.__str__(*args, **kwargs)
250 def __contains__(self, *args, **kwargs):
251 return self.d.__contains__(*args, **kwargs)
253 def __len__(self, *args, **kwargs):
254 return self.d.__len__(*args, **kwargs)
256 def __cmp__(self, other):
258 return self.d.__cmp__(other)
259 except TypeError, le:
260 # maybe we should look for a .d member in other. I know this is insanely kludgey, but the Right Way To Do It is for dict.__cmp__ to use structural typing ("duck typing")
262 return self.d.__cmp__(other.d)
266 def __eq__(self, *args, **kwargs):
267 return self.d.__eq__(*args, **kwargs)
269 def __ne__(self, *args, **kwargs):
270 return self.d.__ne__(*args, **kwargs)
272 def __gt__(self, *args, **kwargs):
273 return self.d.__gt__(*args, **kwargs)
275 def __ge__(self, *args, **kwargs):
276 return self.d.__ge__(*args, **kwargs)
278 def __le__(self, *args, **kwargs):
279 return self.d.__le__(*args, **kwargs)
281 def __lt__(self, *args, **kwargs):
282 return self.d.__lt__(*args, **kwargs)
284 def __getitem__(self, *args, **kwargs):
285 return self.d.__getitem__(*args, **kwargs)
287 def __setitem__(self, *args, **kwargs):
288 return self.d.__setitem__(*args, **kwargs)
290 def __delitem__(self, *args, **kwargs):
291 return self.d.__delitem__(*args, **kwargs)
293 def __iter__(self, *args, **kwargs):
294 return self.d.__iter__(*args, **kwargs)
296 def clear(self, *args, **kwargs):
297 return self.d.clear(*args, **kwargs)
299 def copy(self, *args, **kwargs):
300 return self.__class__(self.d.copy(*args, **kwargs))
302 def fromkeys(self, *args, **kwargs):
303 return self.__class__(self.d.fromkeys(*args, **kwargs))
305 def get(self, key, default=0):
306 return self.d.get(key, default)
308 def has_key(self, *args, **kwargs):
309 return self.d.has_key(*args, **kwargs)
311 def items(self, *args, **kwargs):
312 return self.d.items(*args, **kwargs)
314 def iteritems(self, *args, **kwargs):
315 return self.d.iteritems(*args, **kwargs)
317 def iterkeys(self, *args, **kwargs):
318 return self.d.iterkeys(*args, **kwargs)
320 def itervalues(self, *args, **kwargs):
321 return self.d.itervalues(*args, **kwargs)
323 def keys(self, *args, **kwargs):
324 return self.d.keys(*args, **kwargs)
326 def pop(self, *args, **kwargs):
327 return self.d.pop(*args, **kwargs)
329 def popitem(self, *args, **kwargs):
330 return self.d.popitem(*args, **kwargs)
332 def setdefault(self, *args, **kwargs):
333 return self.d.setdefault(*args, **kwargs)
335 def update(self, *args, **kwargs):
336 return self.d.update(*args, **kwargs)
338 def values(self, *args, **kwargs):
339 return self.d.values(*args, **kwargs)
341 def del_if_present(d, k):
345 class ValueOrderedDict:
347 Note: this implementation assumes that the values do not mutate and change
348 their sort order. That is, it stores the values in a sorted list and
349 as items are added and removed from the dict, it makes updates to the list
350 which will keep the list sorted. But if a value that is currently sitting
351 in the list changes its sort order, then the internal consistency of this
354 If that happens, and if assertion checking is turned on, then you will get
355 an assertion failure the very next time you try to do anything with this
356 ValueOrderedDict. However, those internal consistency checks are very slow
357 and almost certainly unacceptable to leave turned on in production code.
360 def __init__(self, c):
366 precondition(self.i <= len(self.c.l), "The iterated ValueOrderedDict doesn't have this many elements. Most likely this is because someone altered the contents of the ValueOrderedDict while the iteration was in progress.", self.i, self.c)
367 precondition((self.i == len(self.c.l)) or self.c.d.has_key(self.c.l[self.i][1]), "The iterated ValueOrderedDict doesn't have this key. Most likely this is because someone altered the contents of the ValueOrderedDict while the iteration was in progress.", self.i, (self.i < len(self.c.l)) and self.c.l[self.i], self.c)
368 if self.i == len(self.c.l):
370 le = self.c.l[self.i]
372 return (le[1], le[0],)
375 return ValueOrderedDict.ItemIterator(self)
378 return zip(map(operator.__getitem__, self.l, [1]*len(self.l)), map(operator.__getitem__, self.l, [0]*len(self.l)))
381 return map(operator.__getitem__, self.l, [0]*len(self.l))
384 return map(operator.__getitem__, self.l, [1]*len(self.l))
387 def __init__(self, c):
393 precondition(self.i <= len(self.c.l), "The iterated ValueOrderedDict doesn't have this many elements. Most likely this is because someone altered the contents of the ValueOrderedDict while the iteration was in progress.", self.i, self.c)
394 precondition((self.i == len(self.c.l)) or self.c.d.has_key(self.c.l[self.i][1]), "The iterated ValueOrderedDict doesn't have this key. Most likely this is because someone altered the contents of the ValueOrderedDict while the iteration was in progress.", self.i, (self.i < len(self.c.l)) and self.c.l[self.i], self.c)
395 if self.i == len(self.c.l):
397 le = self.c.l[self.i]
402 return ValueOrderedDict.KeyIterator(self)
405 def __init__(self, c):
411 precondition(self.i <= len(self.c.l), "The iterated ValueOrderedDict doesn't have this many elements. Most likely this is because someone altered the contents of the ValueOrderedDict while the iteration was in progress.", self.i, self.c)
412 precondition((self.i == len(self.c.l)) or self.c.d.has_key(self.c.l[self.i][1]), "The iterated ValueOrderedDict doesn't have this key. Most likely this is because someone altered the contents of the ValueOrderedDict while the iteration was in progress.", self.i, (self.i < len(self.c.l)) and self.c.l[self.i], self.c)
413 if self.i == len(self.c.l):
415 le = self.c.l[self.i]
419 def itervalues(self):
420 return ValueOrderedDict.ValueIterator(self)
422 def __init__(self, initialdata={}):
423 self.d = {} # k: key, v: val
424 self.l = [] # sorted list of tuples of (val, key,)
425 self.update(initialdata)
426 assert self._assert_invariants()
431 def __repr_n__(self, n=None):
434 iter = self.iteritems()
436 s.append(str(x[0])); s.append(": "); s.append(str(x[1]))
438 while (n is None) or (i < n):
440 s.append(", "); s.append(str(x[0])); s.append(": "); s.append(str(x[1]))
441 except StopIteration:
447 return "<%s %s>" % (self.__class__.__name__, self.__repr_n__(),)
450 return "<%s %s>" % (self.__class__.__name__, self.__repr_n__(16),)
452 def __eq__(self, other):
453 for (k, v,) in other.iteritems():
454 if not self.d.has_key(k) or self.d[k] != v:
458 def __ne__(self, other):
459 return not self.__eq__(other)
461 def _assert_invariants(self):
462 iter = self.l.__iter__()
467 # self.l is required to be sorted
468 _assert(x >= oldx, x, oldx)
469 # every element of self.l is required to appear in self.d
470 _assert(self.d.has_key(x[1]), x)
472 except StopIteration:
474 for (k, v,) in self.d.iteritems():
475 i = bisect_left(self.l, (v, k,))
476 while (self.l[i][0] is not v) or (self.l[i][1] is not k):
478 _assert(i < len(self.l), i, len(self.l), k, v, self.l)
479 _assert(self.l[i][0] is v, i, v, l=self.l, d=self.d)
480 _assert(self.l[i][1] is k, i, k, l=self.l, d=self.d)
483 def insert(self, key, val=None):
484 assert self._assert_invariants()
485 result = self.__setitem__(key, val)
486 assert self._assert_invariants()
489 def setdefault(self, key, default=None):
490 assert self._assert_invariants()
491 if not self.has_key(key):
493 assert self._assert_invariants()
496 def __setitem__(self, key, val=None):
497 assert self._assert_invariants()
498 if self.d.has_key(key):
502 i = bisect_left(self.l, (oldval, key,))
503 while (self.l[i][0] is not oldval) or (self.l[i][1] is not key):
506 insort_left(self.l, (val, key,))
507 elif oldval is not val:
509 i = bisect_left(self.l, (oldval, key,))
510 while (self.l[i][0] is not oldval) or (self.l[i][1] is not key):
512 self.l[i] = (val, key,)
514 insort_left(self.l, (val, key,))
517 assert self._assert_invariants()
520 def remove(self, key, default=None, strictkey=True):
521 assert self._assert_invariants()
522 result = self.__delitem__(key, default, strictkey)
523 assert self._assert_invariants()
526 def __getitem__(self, key, default=None, strictkey=True):
527 if not self.d.has_key(key):
534 def __delitem__(self, key, default=None, strictkey=True):
536 @param strictkey: True if you want a KeyError in the case that
537 key is not there, False if you want a reference to default
538 in the case that key is not there
539 @param default: the object to return if key is not there; This
540 is ignored if strictkey.
542 @return: the object removed or default if there is not item by
543 that key and strictkey is False
545 assert self._assert_invariants()
546 if self.d.has_key(key):
547 val = self.d.pop(key)
548 i = bisect_left(self.l, (val, key,))
549 while (self.l[i][0] is not val) or (self.l[i][1] is not key):
552 assert self._assert_invariants()
555 assert self._assert_invariants()
558 assert self._assert_invariants()
562 assert self._assert_invariants()
565 assert self._assert_invariants()
567 def update(self, otherdict):
571 assert self._assert_invariants()
572 for (k, v,) in otherdict.iteritems():
574 assert self._assert_invariants()
577 def has_key(self, key):
578 assert self._assert_invariants()
579 return self.d.has_key(key)
583 raise KeyError, 'popitem(): dictionary is empty'
586 return (le[1], le[0],)
588 def pop(self, k, default=None, strictkey=False):
589 if not self.d.has_key(k):
595 i = bisect_left(self.l, (v, k,))
596 while (self.l[i][0] is not v) or (self.l[i][1] is not k):
601 def pop_from_list(self, i=0):
606 class AuxValueDict(dict):
607 """I behave like a regular dict, but each key is associated with two
608 values: the main value, and an auxilliary one. Setting the main value
609 (with the usual d[key]=value) clears the auxvalue. You can set both main
610 and auxvalue at the same time, and can retrieve the values separately.
612 The main use case is a dictionary that represents unpacked child values
613 for a directory node, where a common pattern is to modify one or more
614 children and then pass the dict back to a packing function. The original
615 packed representation can be cached in the auxvalue, and the packing
616 function can use it directly on all unmodified children. On large
617 directories with a complex packing function, this can save considerable
620 def __init__(self, *args, **kwargs):
621 super(AuxValueDict, self).__init__(*args, **kwargs)
624 def __setitem__(self, key, value):
625 super(AuxValueDict, self).__setitem__(key, value)
626 self.auxilliary[key] = None # clear the auxvalue
628 def __delitem__(self, key):
629 super(AuxValueDict, self).__delitem__(key)
630 self.auxilliary.pop(key)
632 def get_aux(self, key, default=None):
633 """Retrieve the auxilliary value. There is no way to distinguish
634 between an auxvalue of 'None' and a key that does not have an
635 auxvalue, and get_aux() will not raise KeyError when called with a
637 return self.auxilliary.get(key, default)
639 def set_with_aux(self, key, value, auxilliary):
640 """Set both the main value and the auxilliary value. There is no way
641 to distinguish between an auxvalue of 'None' and a key that does not
643 super(AuxValueDict, self).__setitem__(key, value)
644 self.auxilliary[key] = auxilliary