| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | 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: |
| | |
| | |
| | self.add(item) |
| |
|
| | 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 |
| | 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: |
| | 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: |
| | return |
| | |
| | |
| | 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: |
| | 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: |
| | 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 |
| |
|