import six class ProxyDictPostWrite(dict): """ Dictionary wrapper that updates an arguments instance on any item set in the dictionary """ def __init__(self, update_obj, update_func, *args, **kwargs): super(ProxyDictPostWrite, self).__init__(*args, **kwargs) self._update_obj = update_obj self._update_func = None for k, i in self.items(): if isinstance(i, dict): super(ProxyDictPostWrite, self).update({k: ProxyDictPostWrite(update_obj, self._set_callback, **i)}) self._update_func = update_func def __setitem__(self, key, value): super(ProxyDictPostWrite, self).__setitem__(key, value) self._set_callback() def _set_callback(self, *_): if self._update_func: self._update_func(self._update_obj, self) def _to_dict(self): a_dict = {} for k, i in self.items(): if isinstance(i, ProxyDictPostWrite): a_dict[k] = i._to_dict() else: a_dict[k] = i return a_dict def update(self, E=None, **F): return super(ProxyDictPostWrite, self).update( ProxyDictPostWrite(self._update_obj, self._set_callback, **E) if E is not None else ProxyDictPostWrite(self._update_obj, self._set_callback, **F)) class ProxyDictPreWrite(dict): """ Dictionary wrapper that prevents modifications to the dictionary """ def __init__(self, update_obj, update_func, *args, **kwargs): super(ProxyDictPreWrite, self).__init__(*args, **kwargs) self._update_func = None for k, i in self.items(): if isinstance(i, dict): self.update({k: ProxyDictPreWrite(k, self._nested_callback, **i)}) self._update_obj = update_obj self._update_func = update_func def __setitem__(self, key, value): key_value = self._set_callback((key, value,)) if key_value: super(ProxyDictPreWrite, self).__setitem__(*key_value) def _set_callback(self, key_value, *_): if self._update_func is not None: if callable(self._update_func): res = self._update_func(self._update_obj, key_value) else: res = self._update_func if not res: return None return res return key_value def _nested_callback(self, prefix, key_value): return self._set_callback((prefix+'.'+key_value[0], key_value[1],)) def flatten_dictionary(a_dict, prefix=''): flat_dict = {} sep = '/' basic_types = (float, int, bool, six.string_types, ) for k, v in a_dict.items(): k = str(k) if isinstance(v, (float, int, bool, six.string_types)): flat_dict[prefix+k] = v elif isinstance(v, (list, tuple)) and all([isinstance(i, basic_types) for i in v]): flat_dict[prefix+k] = v elif isinstance(v, dict): flat_dict.update(flatten_dictionary(v, prefix=prefix+k+sep)) else: # this is a mixture of list and dict, or any other object, # leave it as is, we have nothing to do with it. flat_dict[prefix+k] = v return flat_dict def nested_from_flat_dictionary(a_dict, flat_dict, prefix=''): basic_types = (float, int, bool, six.string_types, ) sep = '/' for k, v in a_dict.items(): k = str(k) if isinstance(v, (float, int, bool, six.string_types)): a_dict[k] = flat_dict.get(prefix+k, v) elif isinstance(v, (list, tuple)) and all([isinstance(i, basic_types) for i in v]): a_dict[k] = flat_dict.get(prefix+k, v) elif isinstance(v, dict): a_dict[k] = nested_from_flat_dictionary(v, flat_dict, prefix=prefix+k+sep) or v else: # this is a mixture of list and dict, or any other object, # leave it as is, we have nothing to do with it. a_dict[k] = flat_dict.get(prefix+k, v) return a_dict