Source code for schrodinger.application.matsci.qexsd.qespresso.utils.mapping
#
# Copyright (c), 2015-2016, Quantum Espresso Foundation and SISSA (Scuola
# Internazionale Superiore di Studi Avanzati). All rights reserved.
# This file is distributed under the terms of the MIT License. See the
# file 'LICENSE' in the root directory of the present distribution, or
# http://opensource.org/licenses/MIT.
# Authors: Davide Brunato
#
"""
Useful classes for building mapping structures.
"""
from collections import MutableMapping
[docs]class BiunivocalMap(MutableMapping):
    """
    A dictionary that implements a bijective correspondence, namely with constraints
    of uniqueness both on keys that on values.
    """
[docs]    def __init__(self, *args, **kwargs):
        self.__map = {}
        self.__inverse = {}
        self.update(*args, **kwargs) 
    def __getitem__(self, key):
        if key in self.__map:
            return self.__map[key]
        if hasattr(self.__class__, '__missing__'):
            return getattr(self.__class__, '__missing__')(self, key)
        raise KeyError(key)
    def __setitem__(self, key, item):
        try:
            if self.__inverse[item] != key:
                raise ValueError(
                    "Value '{0}' is already mapped by another key!".format(
                        item))
        except KeyError:
            if key in self.__map:
                del self.__inverse[self.__map[key]]
            self.__map[key] = item
            self.__inverse[item] = key
        else:
            del self.__inverse[self.__map[key]]
            self.__map[key] = item
            self.__inverse[item] = key
    def __delitem__(self, key):
        del self.__inverse[self.__map[key]]
        del self.__map[key]
    def __iter__(self):
        return iter(self.__map)
[docs]    def __len__(self):
        return len(self.__map) 
[docs]    def __contains__(self, key):
        return key in self.__map 
    def __repr__(self):
        return repr(self.__map)
[docs]    def copy(self):
        if self.__class__ is BiunivocalMap:
            return BiunivocalMap(self.__map.copy())
        import copy
        __map = self.__map
        try:
            self.__map = {}
            c = copy.copy(self)
        finally:
            self.__map = __map
        c.update(self)
        return c 
[docs]    @classmethod
    def fromkeys(cls, iterable, value=None):
        d = cls()
        for key in iterable:
            d[key] = value
        return d 
[docs]    def getkey(self, value, default=None):
        """
        If value is in dictionary's values, return the key correspondent
        to the value, else return None.
        :param value: Value to map
        :param default: Default to return if the value is not in the map values
        """
        try:
            return self.__inverse[value]
        except KeyError:
            return default 
[docs]    def inverse(self):
        """Return a copy of the inverse dictionary."""
        return self.__inverse.copy()