Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
ciDict.py200 linesDownload Raw Back to utils
1"""
2"""
3
4# Created on 2014.08.23
5#
6# Author: Giovanni Cannata
7#
8# Copyright 2014 - 2020 Giovanni Cannata
9#
10# This file is part of ldap3.
11#
12# ldap3 is free software: you can redistribute it and/or modify
13# it under the terms of the GNU Lesser General Public License as published
14# by the Free Software Foundation, either version 3 of the License, or
15# (at your option) any later version.
16#
17# ldap3 is distributed in the hope that it will be useful,
18# but WITHOUT ANY WARRANTY; without even the implied warranty of
19# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20# GNU Lesser General Public License for more details.
21#
22# You should have received a copy of the GNU Lesser General Public License
23# along with ldap3 in the COPYING and COPYING.LESSER files.
24# If not, see <http://www.gnu.org/licenses/>.
25
26try:
27    from collections.abc import MutableMapping, Mapping
28except ImportError:
29    from collections import MutableMapping, Mapping
30
31from .. import SEQUENCE_TYPES
32
33
34class CaseInsensitiveDict(MutableMapping):
35    def __init__(self, other=None, **kwargs):
36        self._store = dict()  # store use the original key
37        self._case_insensitive_keymap = dict()  # is a mapping ci_key -> key
38        if other or kwargs:
39            if other is None:
40                other = dict()
41            self.update(other, **kwargs)
42
43    def __contains__(self, item):
44        try:
45            self.__getitem__(item)
46            return True
47        except KeyError:
48            return False
49
50    @staticmethod
51    def _ci_key(key):
52        return key.strip().lower() if hasattr(key, 'lower') else key
53
54    def __delitem__(self, key):
55        ci_key = self._ci_key(key)
56        del self._store[self._case_insensitive_keymap[ci_key]]
57        del self._case_insensitive_keymap[ci_key]
58
59    def __setitem__(self, key, item):
60        ci_key = self._ci_key(key)
61        if ci_key in self._case_insensitive_keymap:  # updates existing value
62            self._store[self._case_insensitive_keymap[ci_key]] = item
63        else:  # new key
64            self._store[key] = item
65            self._case_insensitive_keymap[ci_key] = key
66
67    def __getitem__(self, key):
68        return self._store[self._case_insensitive_keymap[self._ci_key(key)]]
69
70    def __iter__(self):
71        return self._store.__iter__()
72
73    def __len__(self):  # if len is 0 then the cidict appears as False in IF statement
74        return len(self._store)
75
76    def __repr__(self):
77        return repr(self._store)
78
79    def __str__(self):
80        return str(self._store)
81
82    def keys(self):
83        return self._store.keys()
84
85    def values(self):
86        return self._store.values()
87
88    def items(self):
89        return self._store.items()
90
91    def __eq__(self, other):
92        if not isinstance(other, (Mapping, dict)):
93            return NotImplemented
94
95        if isinstance(other, CaseInsensitiveDict):
96            if len(self.items()) != len(other.items()):
97                return False
98            else:
99                for key, value in self.items():
100                    if not (key in other and other[key] == value):
101                        return False
102                return True
103
104        return self == CaseInsensitiveDict(other)
105
106    def copy(self):
107        return CaseInsensitiveDict(self._store)
108
109
110class CaseInsensitiveWithAliasDict(CaseInsensitiveDict):
111    def __init__(self, other=None, **kwargs):
112        self._aliases = dict()
113        self._alias_keymap = dict()  # is a mapping key -> [alias1, alias2, ...]
114        CaseInsensitiveDict.__init__(self, other, **kwargs)
115
116    def aliases(self):
117        return self._aliases.keys()
118
119    def __setitem__(self, key, value):
120        if isinstance(key, SEQUENCE_TYPES):
121            ci_key = self._ci_key(key[0])
122            if ci_key not in self._aliases:
123                CaseInsensitiveDict.__setitem__(self, key[0], value)
124                self.set_alias(ci_key, key[1:])
125            else:
126                raise KeyError('\'' + str(key[0] + ' already used as alias'))
127        else:
128            ci_key = self._ci_key(key)
129            if ci_key not in self._aliases:
130                CaseInsensitiveDict.__setitem__(self, key, value)
131            else:
132                self[self._aliases[ci_key]] = value
133
134    def __delitem__(self, key):
135        ci_key = self._ci_key(key)
136        try:
137            CaseInsensitiveDict.__delitem__(self, ci_key)
138            if ci_key in self._alias_keymap:
139                for alias in self._alias_keymap[ci_key][:]:  # removes aliases, uses a copy of _alias_keymap because iterator gets confused when aliases are removed from _alias_keymap
140                    self.remove_alias(alias)
141            return
142        except KeyError:  # try to remove alias
143            if ci_key in self._aliases:
144                self.remove_alias(ci_key)
145
146    def set_alias(self, key, alias, ignore_duplicates=False):
147        if not isinstance(alias, SEQUENCE_TYPES):
148            alias = [alias]
149        for alias_to_add in alias:
150            ci_key = self._ci_key(key)
151            if ci_key in self._case_insensitive_keymap:
152                ci_alias = self._ci_key(alias_to_add)
153                if ci_alias not in self._case_insensitive_keymap:  # checks if alias is used a key
154                    if ci_alias not in self._aliases:  # checks if alias is used as another alias
155                        self._aliases[ci_alias] = ci_key
156                        if ci_key in self._alias_keymap:  # extends alias keymap
157                            self._alias_keymap[ci_key].append(self._ci_key(ci_alias))
158                        else:
159                            self._alias_keymap[ci_key] = list()
160                            self._alias_keymap[ci_key].append(self._ci_key(ci_alias))
161                    else:
162                        if ci_key in self._alias_keymap and ci_alias in self._alias_keymap[ci_key]:  # passes if alias is already defined to the same key
163                            pass
164                        elif not ignore_duplicates:
165                            raise KeyError('\'' + str(alias_to_add) + '\' already used as alias')
166                else:
167                    if ci_key == self._ci_key(self._case_insensitive_keymap[ci_alias]):  # passes if alias is already defined to the same key
168                        pass
169                    elif not ignore_duplicates:
170                        raise KeyError('\'' + str(alias_to_add) + '\' already used as key')
171            else:
172                for keymap in self._alias_keymap:
173                    if ci_key in self._alias_keymap[keymap]:  # kye is already aliased
174                        self.set_alias(keymap, alias + [ci_key], ignore_duplicates=ignore_duplicates)
175                        break
176                else:
177                    raise KeyError('\'' + str(ci_key) + '\' is not an existing alias or key')
178
179    def remove_alias(self, alias):
180        if not isinstance(alias, SEQUENCE_TYPES):
181            alias = [alias]
182        for alias_to_remove in alias:
183            ci_alias = self._ci_key(alias_to_remove)
184            self._alias_keymap[self._aliases[ci_alias]].remove(ci_alias)
185            if not self._alias_keymap[self._aliases[ci_alias]]:  # remove keymap if empty
186                del self._alias_keymap[self._aliases[ci_alias]]
187            del self._aliases[ci_alias]
188
189    def __getitem__(self, key):
190        try:
191            return CaseInsensitiveDict.__getitem__(self, key)
192        except KeyError:
193            return CaseInsensitiveDict.__getitem__(self, self._aliases[self._ci_key(key)])
194
195    def copy(self):
196        new = CaseInsensitiveWithAliasDict(self._store)
197        new._aliases = self._aliases.copy()
198        new._alias_keymap = self._alias_keymap
199        return new
200 
codekingpro/portable-devtools · Team Ai