1"""Misc dict tools."""
2
3from __future__ import print_function, absolute_import, division
4from fontTools.misc.py23 import *
5
6__all__ = ['hashdict']
7
8# https://stackoverflow.com/questions/1151658/python-hashable-dicts
9class hashdict(dict):
10    """
11    hashable dict implementation, suitable for use as a key into
12    other dicts.
13
14        >>> h1 = hashdict({"apples": 1, "bananas":2})
15        >>> h2 = hashdict({"bananas": 3, "mangoes": 5})
16        >>> h1+h2
17        hashdict(apples=1, bananas=3, mangoes=5)
18        >>> d1 = {}
19        >>> d1[h1] = "salad"
20        >>> d1[h1]
21        'salad'
22        >>> d1[h2]
23        Traceback (most recent call last):
24        ...
25        KeyError: hashdict(bananas=3, mangoes=5)
26
27    based on answers from
28       http://stackoverflow.com/questions/1151658/python-hashable-dicts
29
30    """
31    def __key(self):
32        return tuple(sorted(self.items()))
33    def __repr__(self):
34        return "{0}({1})".format(self.__class__.__name__,
35            ", ".join("{0}={1}".format(
36                    str(i[0]),repr(i[1])) for i in self.__key()))
37
38    def __hash__(self):
39        return hash(self.__key())
40    def __setitem__(self, key, value):
41        raise TypeError("{0} does not support item assignment"
42                         .format(self.__class__.__name__))
43    def __delitem__(self, key):
44        raise TypeError("{0} does not support item assignment"
45                         .format(self.__class__.__name__))
46    def clear(self):
47        raise TypeError("{0} does not support item assignment"
48                         .format(self.__class__.__name__))
49    def pop(self, *args, **kwargs):
50        raise TypeError("{0} does not support item assignment"
51                         .format(self.__class__.__name__))
52    def popitem(self, *args, **kwargs):
53        raise TypeError("{0} does not support item assignment"
54                         .format(self.__class__.__name__))
55    def setdefault(self, *args, **kwargs):
56        raise TypeError("{0} does not support item assignment"
57                         .format(self.__class__.__name__))
58    def update(self, *args, **kwargs):
59        raise TypeError("{0} does not support item assignment"
60                         .format(self.__class__.__name__))
61    # update is not ok because it mutates the object
62    # __add__ is ok because it creates a new object
63    # while the new object is under construction, it's ok to mutate it
64    def __add__(self, right):
65        result = hashdict(self)
66        dict.update(result, right)
67        return result
68
69