Spaces:
Paused
Paused
| # Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license | |
| # Copyright (C) 2003-2017 Nominum, Inc. | |
| # | |
| # Permission to use, copy, modify, and distribute this software and its | |
| # documentation for any purpose with or without fee is hereby granted, | |
| # provided that the above copyright notice and this permission notice | |
| # appear in all copies. | |
| # | |
| # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES | |
| # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
| # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR | |
| # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
| # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | |
| # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
| import itertools | |
| class Set: | |
| """A simple set class. | |
| This class was originally used to deal with sets being missing in | |
| ancient versions of python, but dnspython will continue to use it | |
| as these sets are based on lists and are thus indexable, and this | |
| ability is widely used in dnspython applications. | |
| """ | |
| __slots__ = ["items"] | |
| def __init__(self, items=None): | |
| """Initialize the set. | |
| *items*, an iterable or ``None``, the initial set of items. | |
| """ | |
| self.items = dict() | |
| if items is not None: | |
| for item in items: | |
| # This is safe for how we use set, but if other code | |
| # subclasses it could be a legitimate issue. | |
| self.add(item) # lgtm[py/init-calls-subclass] | |
| def __repr__(self): | |
| return "dns.set.Set(%s)" % repr(list(self.items.keys())) | |
| def add(self, item): | |
| """Add an item to the set.""" | |
| if item not in self.items: | |
| self.items[item] = None | |
| def remove(self, item): | |
| """Remove an item from the set.""" | |
| try: | |
| del self.items[item] | |
| except KeyError: | |
| raise ValueError | |
| def discard(self, item): | |
| """Remove an item from the set if present.""" | |
| self.items.pop(item, None) | |
| def pop(self): | |
| """Remove an arbitrary item from the set.""" | |
| (k, _) = self.items.popitem() | |
| return k | |
| def _clone(self) -> "Set": | |
| """Make a (shallow) copy of the set. | |
| There is a 'clone protocol' that subclasses of this class | |
| should use. To make a copy, first call your super's _clone() | |
| method, and use the object returned as the new instance. Then | |
| make shallow copies of the attributes defined in the subclass. | |
| This protocol allows us to write the set algorithms that | |
| return new instances (e.g. union) once, and keep using them in | |
| subclasses. | |
| """ | |
| if hasattr(self, "_clone_class"): | |
| cls = self._clone_class # type: ignore | |
| else: | |
| cls = self.__class__ | |
| obj = cls.__new__(cls) | |
| obj.items = dict() | |
| obj.items.update(self.items) | |
| return obj | |
| def __copy__(self): | |
| """Make a (shallow) copy of the set.""" | |
| return self._clone() | |
| def copy(self): | |
| """Make a (shallow) copy of the set.""" | |
| return self._clone() | |
| def union_update(self, other): | |
| """Update the set, adding any elements from other which are not | |
| already in the set. | |
| """ | |
| if not isinstance(other, Set): | |
| raise ValueError("other must be a Set instance") | |
| if self is other: # lgtm[py/comparison-using-is] | |
| return | |
| for item in other.items: | |
| self.add(item) | |
| def intersection_update(self, other): | |
| """Update the set, removing any elements from other which are not | |
| in both sets. | |
| """ | |
| if not isinstance(other, Set): | |
| raise ValueError("other must be a Set instance") | |
| if self is other: # lgtm[py/comparison-using-is] | |
| return | |
| # we make a copy of the list so that we can remove items from | |
| # the list without breaking the iterator. | |
| for item in list(self.items): | |
| if item not in other.items: | |
| del self.items[item] | |
| def difference_update(self, other): | |
| """Update the set, removing any elements from other which are in | |
| the set. | |
| """ | |
| if not isinstance(other, Set): | |
| raise ValueError("other must be a Set instance") | |
| if self is other: # lgtm[py/comparison-using-is] | |
| self.items.clear() | |
| else: | |
| for item in other.items: | |
| self.discard(item) | |
| def symmetric_difference_update(self, other): | |
| """Update the set, retaining only elements unique to both sets.""" | |
| if not isinstance(other, Set): | |
| raise ValueError("other must be a Set instance") | |
| if self is other: # lgtm[py/comparison-using-is] | |
| self.items.clear() | |
| else: | |
| overlap = self.intersection(other) | |
| self.union_update(other) | |
| self.difference_update(overlap) | |
| def union(self, other): | |
| """Return a new set which is the union of ``self`` and ``other``. | |
| Returns the same Set type as this set. | |
| """ | |
| obj = self._clone() | |
| obj.union_update(other) | |
| return obj | |
| def intersection(self, other): | |
| """Return a new set which is the intersection of ``self`` and | |
| ``other``. | |
| Returns the same Set type as this set. | |
| """ | |
| obj = self._clone() | |
| obj.intersection_update(other) | |
| return obj | |
| def difference(self, other): | |
| """Return a new set which ``self`` - ``other``, i.e. the items | |
| in ``self`` which are not also in ``other``. | |
| Returns the same Set type as this set. | |
| """ | |
| obj = self._clone() | |
| obj.difference_update(other) | |
| return obj | |
| def symmetric_difference(self, other): | |
| """Return a new set which (``self`` - ``other``) | (``other`` | |
| - ``self), ie: the items in either ``self`` or ``other`` which | |
| are not contained in their intersection. | |
| Returns the same Set type as this set. | |
| """ | |
| obj = self._clone() | |
| obj.symmetric_difference_update(other) | |
| return obj | |
| def __or__(self, other): | |
| return self.union(other) | |
| def __and__(self, other): | |
| return self.intersection(other) | |
| def __add__(self, other): | |
| return self.union(other) | |
| def __sub__(self, other): | |
| return self.difference(other) | |
| def __xor__(self, other): | |
| return self.symmetric_difference(other) | |
| def __ior__(self, other): | |
| self.union_update(other) | |
| return self | |
| def __iand__(self, other): | |
| self.intersection_update(other) | |
| return self | |
| def __iadd__(self, other): | |
| self.union_update(other) | |
| return self | |
| def __isub__(self, other): | |
| self.difference_update(other) | |
| return self | |
| def __ixor__(self, other): | |
| self.symmetric_difference_update(other) | |
| return self | |
| def update(self, other): | |
| """Update the set, adding any elements from other which are not | |
| already in the set. | |
| *other*, the collection of items with which to update the set, which | |
| may be any iterable type. | |
| """ | |
| for item in other: | |
| self.add(item) | |
| def clear(self): | |
| """Make the set empty.""" | |
| self.items.clear() | |
| def __eq__(self, other): | |
| return self.items == other.items | |
| def __ne__(self, other): | |
| return not self.__eq__(other) | |
| def __len__(self): | |
| return len(self.items) | |
| def __iter__(self): | |
| return iter(self.items) | |
| def __getitem__(self, i): | |
| if isinstance(i, slice): | |
| return list(itertools.islice(self.items, i.start, i.stop, i.step)) | |
| else: | |
| return next(itertools.islice(self.items, i, i + 1)) | |
| def __delitem__(self, i): | |
| if isinstance(i, slice): | |
| for elt in list(self[i]): | |
| del self.items[elt] | |
| else: | |
| del self.items[self[i]] | |
| def issubset(self, other): | |
| """Is this set a subset of *other*? | |
| Returns a ``bool``. | |
| """ | |
| if not isinstance(other, Set): | |
| raise ValueError("other must be a Set instance") | |
| for item in self.items: | |
| if item not in other.items: | |
| return False | |
| return True | |
| def issuperset(self, other): | |
| """Is this set a superset of *other*? | |
| Returns a ``bool``. | |
| """ | |
| if not isinstance(other, Set): | |
| raise ValueError("other must be a Set instance") | |
| for item in other.items: | |
| if item not in self.items: | |
| return False | |
| return True | |
| def isdisjoint(self, other): | |
| if not isinstance(other, Set): | |
| raise ValueError("other must be a Set instance") | |
| for item in other.items: | |
| if item in self.items: | |
| return False | |
| return True | |