Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/dns/set.py: 31%
149 statements
« prev ^ index » next coverage.py v7.4.1, created at 2024-02-02 06:07 +0000
« prev ^ index » next coverage.py v7.4.1, created at 2024-02-02 06:07 +0000
1# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
3# Copyright (C) 2003-2017 Nominum, Inc.
4#
5# Permission to use, copy, modify, and distribute this software and its
6# documentation for any purpose with or without fee is hereby granted,
7# provided that the above copyright notice and this permission notice
8# appear in all copies.
9#
10# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
11# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
13# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
16# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18import itertools
21class Set:
23 """A simple set class.
25 This class was originally used to deal with sets being missing in
26 ancient versions of python, but dnspython will continue to use it
27 as these sets are based on lists and are thus indexable, and this
28 ability is widely used in dnspython applications.
29 """
31 __slots__ = ["items"]
33 def __init__(self, items=None):
34 """Initialize the set.
36 *items*, an iterable or ``None``, the initial set of items.
37 """
39 self.items = dict()
40 if items is not None:
41 for item in items:
42 # This is safe for how we use set, but if other code
43 # subclasses it could be a legitimate issue.
44 self.add(item) # lgtm[py/init-calls-subclass]
46 def __repr__(self):
47 return "dns.set.Set(%s)" % repr(list(self.items.keys()))
49 def add(self, item):
50 """Add an item to the set."""
52 if item not in self.items:
53 self.items[item] = None
55 def remove(self, item):
56 """Remove an item from the set."""
58 try:
59 del self.items[item]
60 except KeyError:
61 raise ValueError
63 def discard(self, item):
64 """Remove an item from the set if present."""
66 self.items.pop(item, None)
68 def pop(self):
69 """Remove an arbitrary item from the set."""
70 (k, _) = self.items.popitem()
71 return k
73 def _clone(self) -> "Set":
74 """Make a (shallow) copy of the set.
76 There is a 'clone protocol' that subclasses of this class
77 should use. To make a copy, first call your super's _clone()
78 method, and use the object returned as the new instance. Then
79 make shallow copies of the attributes defined in the subclass.
81 This protocol allows us to write the set algorithms that
82 return new instances (e.g. union) once, and keep using them in
83 subclasses.
84 """
86 if hasattr(self, "_clone_class"):
87 cls = self._clone_class # type: ignore
88 else:
89 cls = self.__class__
90 obj = cls.__new__(cls)
91 obj.items = dict()
92 obj.items.update(self.items)
93 return obj
95 def __copy__(self):
96 """Make a (shallow) copy of the set."""
98 return self._clone()
100 def copy(self):
101 """Make a (shallow) copy of the set."""
103 return self._clone()
105 def union_update(self, other):
106 """Update the set, adding any elements from other which are not
107 already in the set.
108 """
110 if not isinstance(other, Set):
111 raise ValueError("other must be a Set instance")
112 if self is other: # lgtm[py/comparison-using-is]
113 return
114 for item in other.items:
115 self.add(item)
117 def intersection_update(self, other):
118 """Update the set, removing any elements from other which are not
119 in both sets.
120 """
122 if not isinstance(other, Set):
123 raise ValueError("other must be a Set instance")
124 if self is other: # lgtm[py/comparison-using-is]
125 return
126 # we make a copy of the list so that we can remove items from
127 # the list without breaking the iterator.
128 for item in list(self.items):
129 if item not in other.items:
130 del self.items[item]
132 def difference_update(self, other):
133 """Update the set, removing any elements from other which are in
134 the set.
135 """
137 if not isinstance(other, Set):
138 raise ValueError("other must be a Set instance")
139 if self is other: # lgtm[py/comparison-using-is]
140 self.items.clear()
141 else:
142 for item in other.items:
143 self.discard(item)
145 def symmetric_difference_update(self, other):
146 """Update the set, retaining only elements unique to both sets."""
148 if not isinstance(other, Set):
149 raise ValueError("other must be a Set instance")
150 if self is other: # lgtm[py/comparison-using-is]
151 self.items.clear()
152 else:
153 overlap = self.intersection(other)
154 self.union_update(other)
155 self.difference_update(overlap)
157 def union(self, other):
158 """Return a new set which is the union of ``self`` and ``other``.
160 Returns the same Set type as this set.
161 """
163 obj = self._clone()
164 obj.union_update(other)
165 return obj
167 def intersection(self, other):
168 """Return a new set which is the intersection of ``self`` and
169 ``other``.
171 Returns the same Set type as this set.
172 """
174 obj = self._clone()
175 obj.intersection_update(other)
176 return obj
178 def difference(self, other):
179 """Return a new set which ``self`` - ``other``, i.e. the items
180 in ``self`` which are not also in ``other``.
182 Returns the same Set type as this set.
183 """
185 obj = self._clone()
186 obj.difference_update(other)
187 return obj
189 def symmetric_difference(self, other):
190 """Return a new set which (``self`` - ``other``) | (``other``
191 - ``self), ie: the items in either ``self`` or ``other`` which
192 are not contained in their intersection.
194 Returns the same Set type as this set.
195 """
197 obj = self._clone()
198 obj.symmetric_difference_update(other)
199 return obj
201 def __or__(self, other):
202 return self.union(other)
204 def __and__(self, other):
205 return self.intersection(other)
207 def __add__(self, other):
208 return self.union(other)
210 def __sub__(self, other):
211 return self.difference(other)
213 def __xor__(self, other):
214 return self.symmetric_difference(other)
216 def __ior__(self, other):
217 self.union_update(other)
218 return self
220 def __iand__(self, other):
221 self.intersection_update(other)
222 return self
224 def __iadd__(self, other):
225 self.union_update(other)
226 return self
228 def __isub__(self, other):
229 self.difference_update(other)
230 return self
232 def __ixor__(self, other):
233 self.symmetric_difference_update(other)
234 return self
236 def update(self, other):
237 """Update the set, adding any elements from other which are not
238 already in the set.
240 *other*, the collection of items with which to update the set, which
241 may be any iterable type.
242 """
244 for item in other:
245 self.add(item)
247 def clear(self):
248 """Make the set empty."""
249 self.items.clear()
251 def __eq__(self, other):
252 return self.items == other.items
254 def __ne__(self, other):
255 return not self.__eq__(other)
257 def __len__(self):
258 return len(self.items)
260 def __iter__(self):
261 return iter(self.items)
263 def __getitem__(self, i):
264 if isinstance(i, slice):
265 return list(itertools.islice(self.items, i.start, i.stop, i.step))
266 else:
267 return next(itertools.islice(self.items, i, i + 1))
269 def __delitem__(self, i):
270 if isinstance(i, slice):
271 for elt in list(self[i]):
272 del self.items[elt]
273 else:
274 del self.items[self[i]]
276 def issubset(self, other):
277 """Is this set a subset of *other*?
279 Returns a ``bool``.
280 """
282 if not isinstance(other, Set):
283 raise ValueError("other must be a Set instance")
284 for item in self.items:
285 if item not in other.items:
286 return False
287 return True
289 def issuperset(self, other):
290 """Is this set a superset of *other*?
292 Returns a ``bool``.
293 """
295 if not isinstance(other, Set):
296 raise ValueError("other must be a Set instance")
297 for item in other.items:
298 if item not in self.items:
299 return False
300 return True
302 def isdisjoint(self, other):
303 if not isinstance(other, Set):
304 raise ValueError("other must be a Set instance")
305 for item in other.items:
306 if item in self.items:
307 return False
308 return True