# -*- coding: utf-8 -*- # Copyright (c) 2012 Santiago Lezica # # Permission is hereby granted, free of charge, to any person obtaining a copy of this # software and associated documentation files (the "Software"), to deal in the Software # without restriction, including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, and to permit # persons to whom the Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all copies or # substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR # PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE # FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. # source: https://raw.githubusercontent.com/slezica/python-frozendict/c5d16bafcca7b72ff3e8f40d3a9081e4c9233f1b/frozendict/__init__.py # version: 1.2 # date: 2018-06-29 try: from collections.abc import Mapping except ImportError: from collections import Mapping try: from collections import OrderedDict except ImportError: # python < 2.7 OrderedDict = NotImplemented iteritems = getattr(dict, 'iteritems', dict.items) # py2-3 compatibility class frozendict(Mapping): """ An immutable wrapper around dictionaries that implements the complete :py:class:`collections.Mapping` interface. It can be used as a drop-in replacement for dictionaries where immutability is desired. """ dict_cls = dict def __init__(self, *args, **kwargs): self._dict = self.dict_cls(*args, **kwargs) self._hash = None def __getitem__(self, key): return self._dict[key] def __contains__(self, key): return key in self._dict def copy(self, **add_or_replace): return self.__class__(self, **add_or_replace) def __iter__(self): return iter(self._dict) def __len__(self): return len(self._dict) def __repr__(self): return '<%s %r>' % (self.__class__.__name__, self._dict) def __hash__(self): if self._hash is None: h = 0 for key, value in iteritems(self._dict): h ^= hash((key, value)) self._hash = h return self._hash def __json__(self): # Works with auxlib's EntityEncoder. return self._dict def to_json(self): return self.__json__() class FrozenOrderedDict(frozendict): """ A frozendict subclass that maintains key order """ dict_cls = OrderedDict if OrderedDict is NotImplemented: del FrozenOrderedDict