• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import collections
2import itertools
3
4
5# from jaraco.collections 3.5.1
6class DictStack(list, collections.abc.Mapping):
7    """
8    A stack of dictionaries that behaves as a view on those dictionaries,
9    giving preference to the last.
10
11    >>> stack = DictStack([dict(a=1, c=2), dict(b=2, a=2)])
12    >>> stack['a']
13    2
14    >>> stack['b']
15    2
16    >>> stack['c']
17    2
18    >>> len(stack)
19    3
20    >>> stack.push(dict(a=3))
21    >>> stack['a']
22    3
23    >>> set(stack.keys()) == set(['a', 'b', 'c'])
24    True
25    >>> set(stack.items()) == set([('a', 3), ('b', 2), ('c', 2)])
26    True
27    >>> dict(**stack) == dict(stack) == dict(a=3, c=2, b=2)
28    True
29    >>> d = stack.pop()
30    >>> stack['a']
31    2
32    >>> d = stack.pop()
33    >>> stack['a']
34    1
35    >>> stack.get('b', None)
36    >>> 'c' in stack
37    True
38    """
39
40    def __iter__(self):
41        dicts = list.__iter__(self)
42        return iter(set(itertools.chain.from_iterable(c.keys() for c in dicts)))
43
44    def __getitem__(self, key):
45        for scope in reversed(tuple(list.__iter__(self))):
46            if key in scope:
47                return scope[key]
48        raise KeyError(key)
49
50    push = list.append
51
52    def __contains__(self, other):
53        return collections.abc.Mapping.__contains__(self, other)
54
55    def __len__(self):
56        return len(list(iter(self)))
57