|
@ -1,11 +1,15 @@ |
|
|
|
|
|
"""Some utility functions""" |
|
|
|
|
|
|
|
|
from collections import UserDict |
|
|
from collections import UserDict |
|
|
|
|
|
|
|
|
class DictOfDict(UserDict): |
|
|
class DictOfDict(UserDict): |
|
|
"""Dictionary, with a smart :meth:`update` method. |
|
|
"""Dictionary, with a recursive :meth:`update` method. |
|
|
|
|
|
|
|
|
By "smart", we mean: if `self.update(other)` is called, and for some key |
|
|
By "recursive", we mean: if `self.update(other)` is called, and for some |
|
|
both `self[key]` and `other[key]` are dictionary, then `self[key]` is not |
|
|
key both `self[key]` and `other[key]` are dictionary, then `self[key]` is |
|
|
replaced by `other[key]`, but instead is updated. |
|
|
not replaced by `other[key]`, but instead is updated. This is done |
|
|
|
|
|
recursively (that is, `self[foo][bar][baz]` is updated with |
|
|
|
|
|
`other[foo][bar][baz]`, if the corresponding objects are dictionaries). |
|
|
|
|
|
|
|
|
>>> ordinal = DictOfDict({ |
|
|
>>> ordinal = DictOfDict({ |
|
|
... "francais": { |
|
|
... "francais": { |
|
@ -42,10 +46,15 @@ class DictOfDict(UserDict): |
|
|
""" |
|
|
""" |
|
|
|
|
|
|
|
|
def update(self, other): |
|
|
def update(self, other): |
|
|
for key in other: |
|
|
# pylint: disable=arguments-differ |
|
|
if key not in self: |
|
|
self._update(self, other) |
|
|
self[key] = other[key] |
|
|
|
|
|
elif isinstance(self[key], dict) and isinstance(other[key], dict): |
|
|
def _update(self, left, right): |
|
|
self[key].update(other[key]) |
|
|
"""Equivalent to `left.update(right)`, with recursive update.""" |
|
|
|
|
|
for key in right: |
|
|
|
|
|
if key not in left: |
|
|
|
|
|
left[key] = right[key] |
|
|
|
|
|
elif isinstance(left[key], dict) and isinstance(right[key], dict): |
|
|
|
|
|
self._update(left[key], right[key]) |
|
|
else: |
|
|
else: |
|
|
self[key] = other[key] |
|
|
left[key] = right[key] |
|
|