multi_domain.py 2.71 KB
Newer Older
Martin Reinecke's avatar
step 1    
Martin Reinecke committed
1
from ..domain_tuple import DomainTuple
2
from ..utilities import frozendict
Martin Reinecke's avatar
step 1    
Martin Reinecke committed
3
4
5
6


class MultiDomain(frozendict):
    _domainCache = {}
Martin Reinecke's avatar
Martin Reinecke committed
7
8
    _subsetCache = set()
    _compatCache = set()
Martin Reinecke's avatar
step 1    
Martin Reinecke committed
9

Martin Reinecke's avatar
Martin Reinecke committed
10
    def __init__(self, domain, _callingfrommake=False):
Martin Reinecke's avatar
step 1    
Martin Reinecke committed
11
        if not _callingfrommake:
Martin Reinecke's avatar
Martin Reinecke committed
12
13
            raise NotImplementedError(
                'To create a MultiDomain call `MultiDomain.make()`.')
Martin Reinecke's avatar
step 1    
Martin Reinecke committed
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
        super(MultiDomain, self).__init__(domain)

    @staticmethod
    def make(domain):
        if isinstance(domain, MultiDomain):
            return domain
        if not isinstance(domain, dict):
            raise TypeError("dict expected")
        tmp = {}
        for key, value in domain.items():
            if not isinstance(key, str):
                raise TypeError("keys must be strings")
            tmp[key] = DomainTuple.make(value)
        domain = frozendict(tmp)
        obj = MultiDomain._domainCache.get(domain)
        if obj is not None:
            return obj
        obj = MultiDomain(domain, _callingfrommake=True)
        MultiDomain._domainCache[domain] = obj
        return obj
Martin Reinecke's avatar
Martin Reinecke committed
34
35

    def __eq__(self, x):
Martin Reinecke's avatar
Martin Reinecke committed
36
37
38
        if self is x:
            return True
        x = MultiDomain.make(x)
Martin Reinecke's avatar
Martin Reinecke committed
39
40
41
42
43
        return self is x

    def __ne__(self, x):
        return not self.__eq__(x)

Martin Reinecke's avatar
fix    
Martin Reinecke committed
44
45
46
    def __hash__(self):
        return super(MultiDomain, self).__hash__()

Martin Reinecke's avatar
Martin Reinecke committed
47
    def compatibleTo(self, x):
Martin Reinecke's avatar
Martin Reinecke committed
48
49
50
        if self is x:
            return True
        x = MultiDomain.make(x)
Martin Reinecke's avatar
Martin Reinecke committed
51
52
        if self is x:
            return True
Martin Reinecke's avatar
Martin Reinecke committed
53
54
        if (self, x) in MultiDomain._compatCache:
            return True
Martin Reinecke's avatar
Martin Reinecke committed
55
56
        commonKeys = set(self.keys()) & set(x.keys())
        for key in commonKeys:
Martin Reinecke's avatar
Martin Reinecke committed
57
            if self[key] is not x[key]:
Martin Reinecke's avatar
Martin Reinecke committed
58
                return False
Martin Reinecke's avatar
Martin Reinecke committed
59
60
        MultiDomain._compatCache.add((self, x))
        MultiDomain._compatCache.add((x, self))
Martin Reinecke's avatar
Martin Reinecke committed
61
62
63
        return True

    def subsetOf(self, x):
Martin Reinecke's avatar
Martin Reinecke committed
64
65
66
        if self is x:
            return True
        x = MultiDomain.make(x)
Martin Reinecke's avatar
Martin Reinecke committed
67
        if self is x:
Martin Reinecke's avatar
Martin Reinecke committed
68
            return True
69
        if len(x) == 0:
Martin Reinecke's avatar
Martin Reinecke committed
70
71
            return True
        if (self, x) in MultiDomain._subsetCache:
72
            return True
Martin Reinecke's avatar
Martin Reinecke committed
73
        for key in self.keys():
74
            if key not in x:
Martin Reinecke's avatar
Martin Reinecke committed
75
                return False
Martin Reinecke's avatar
Martin Reinecke committed
76
            if self[key] is not x[key]:
Martin Reinecke's avatar
Martin Reinecke committed
77
                return False
Martin Reinecke's avatar
Martin Reinecke committed
78
        MultiDomain._subsetCache.add((self, x))
Martin Reinecke's avatar
Martin Reinecke committed
79
80
81
        return True

    def unitedWith(self, x):
Martin Reinecke's avatar
Martin Reinecke committed
82
83
84
85
        if self is x:
            return self
        x = MultiDomain.make(x)
        if self is x:
Martin Reinecke's avatar
Martin Reinecke committed
86
87
88
89
90
91
92
93
94
            return self
        if not self.compatibleTo(x):
            raise ValueError("domain mismatch")
        res = {}
        for key, val in self.items():
            res[key] = val
        for key, val in x.items():
            res[key] = val
        return MultiDomain.make(res)