summaryrefslogtreecommitdiff
path: root/odoo/tools/misc.py
diff options
context:
space:
mode:
authorRaphael Collet <rco@odoo.com>2018-01-18 12:15:15 +0100
committerRaphael Collet <rco@odoo.com>2018-01-23 16:41:45 +0100
commitf1d60d2e528284c4d4401d40e362f1b45ac32211 (patch)
tree572031ea4a6997928ada1f5a519fae590798e405 /odoo/tools/misc.py
parent74801feb0cfd26d09e767878c18dfffaa220ab51 (diff)
[IMP] api: make the implementation of field protection more robust
Diffstat (limited to 'odoo/tools/misc.py')
-rw-r--r--odoo/tools/misc.py46
1 files changed, 44 insertions, 2 deletions
diff --git a/odoo/tools/misc.py b/odoo/tools/misc.py
index ac3a56b3825..a9b66117f03 100644
--- a/odoo/tools/misc.py
+++ b/odoo/tools/misc.py
@@ -25,8 +25,7 @@ import types
import unicodedata
import werkzeug.utils
import zipfile
-
-from collections import defaultdict, Iterable, Mapping, MutableSet, OrderedDict
+from collections import defaultdict, Iterable, Mapping, MutableMapping, MutableSet, OrderedDict
from itertools import islice, groupby, repeat
from lxml import etree
@@ -998,6 +997,49 @@ class Collector(Mapping):
def __len__(self):
return len(self._map)
+
+@pycompat.implements_to_string
+class StackMap(MutableMapping):
+ """ A stack of mappings behaving as a single mapping, and used to implement
+ nested scopes. The lookups search the stack from top to bottom, and
+ returns the first value found. Mutable operations modify the topmost
+ mapping only.
+ """
+ __slots__ = ['_maps']
+
+ def __init__(self, m=None):
+ self._maps = [] if m is None else [m]
+
+ def __getitem__(self, key):
+ for mapping in reversed(self._maps):
+ try:
+ return mapping[key]
+ except KeyError:
+ pass
+ raise KeyError(key)
+
+ def __setitem__(self, key, val):
+ self._maps[-1][key] = val
+
+ def __delitem__(self, key):
+ del self._maps[-1][key]
+
+ def __iter__(self):
+ return iter({key for mapping in self._maps for key in mapping})
+
+ def __len__(self):
+ return sum(1 for key in self)
+
+ def __str__(self):
+ return u"<StackMap %s>" % self._maps
+
+ def pushmap(self, m=None):
+ self._maps.append({} if m is None else m)
+
+ def popmap(self):
+ return self._maps.pop()
+
+
class OrderedSet(MutableSet):
""" A set collection that remembers the elements first insertion order. """
__slots__ = ['_map']