+++ /dev/null
-# Access WeakSet through the weakref module.\r
-# This code is separated-out because it is needed\r
-# by abc.py to load everything else at startup.\r
-\r
-from _weakref import ref\r
-\r
-__all__ = ['WeakSet']\r
-\r
-\r
-class _IterationGuard(object):\r
- # This context manager registers itself in the current iterators of the\r
- # weak container, such as to delay all removals until the context manager\r
- # exits.\r
- # This technique should be relatively thread-safe (since sets are).\r
-\r
- def __init__(self, weakcontainer):\r
- # Don't create cycles\r
- self.weakcontainer = ref(weakcontainer)\r
-\r
- def __enter__(self):\r
- w = self.weakcontainer()\r
- if w is not None:\r
- w._iterating.add(self)\r
- return self\r
-\r
- def __exit__(self, e, t, b):\r
- w = self.weakcontainer()\r
- if w is not None:\r
- s = w._iterating\r
- s.remove(self)\r
- if not s:\r
- w._commit_removals()\r
-\r
-\r
-class WeakSet(object):\r
- def __init__(self, data=None):\r
- self.data = set()\r
- def _remove(item, selfref=ref(self)):\r
- self = selfref()\r
- if self is not None:\r
- if self._iterating:\r
- self._pending_removals.append(item)\r
- else:\r
- self.data.discard(item)\r
- self._remove = _remove\r
- # A list of keys to be removed\r
- self._pending_removals = []\r
- self._iterating = set()\r
- if data is not None:\r
- self.update(data)\r
-\r
- def _commit_removals(self):\r
- l = self._pending_removals\r
- discard = self.data.discard\r
- while l:\r
- discard(l.pop())\r
-\r
- def __iter__(self):\r
- with _IterationGuard(self):\r
- for itemref in self.data:\r
- item = itemref()\r
- if item is not None:\r
- # Caveat: the iterator will keep a strong reference to\r
- # `item` until it is resumed or closed.\r
- yield item\r
-\r
- def __len__(self):\r
- return len(self.data) - len(self._pending_removals)\r
-\r
- def __contains__(self, item):\r
- try:\r
- wr = ref(item)\r
- except TypeError:\r
- return False\r
- return wr in self.data\r
-\r
- def __reduce__(self):\r
- return (self.__class__, (list(self),),\r
- getattr(self, '__dict__', None))\r
-\r
- __hash__ = None\r
-\r
- def add(self, item):\r
- if self._pending_removals:\r
- self._commit_removals()\r
- self.data.add(ref(item, self._remove))\r
-\r
- def clear(self):\r
- if self._pending_removals:\r
- self._commit_removals()\r
- self.data.clear()\r
-\r
- def copy(self):\r
- return self.__class__(self)\r
-\r
- def pop(self):\r
- if self._pending_removals:\r
- self._commit_removals()\r
- while True:\r
- try:\r
- itemref = self.data.pop()\r
- except KeyError:\r
- raise KeyError('pop from empty WeakSet')\r
- item = itemref()\r
- if item is not None:\r
- return item\r
-\r
- def remove(self, item):\r
- if self._pending_removals:\r
- self._commit_removals()\r
- self.data.remove(ref(item))\r
-\r
- def discard(self, item):\r
- if self._pending_removals:\r
- self._commit_removals()\r
- self.data.discard(ref(item))\r
-\r
- def update(self, other):\r
- if self._pending_removals:\r
- self._commit_removals()\r
- for element in other:\r
- self.add(element)\r
-\r
- def __ior__(self, other):\r
- self.update(other)\r
- return self\r
-\r
- def difference(self, other):\r
- newset = self.copy()\r
- newset.difference_update(other)\r
- return newset\r
- __sub__ = difference\r
-\r
- def difference_update(self, other):\r
- self.__isub__(other)\r
- def __isub__(self, other):\r
- if self._pending_removals:\r
- self._commit_removals()\r
- if self is other:\r
- self.data.clear()\r
- else:\r
- self.data.difference_update(ref(item) for item in other)\r
- return self\r
-\r
- def intersection(self, other):\r
- return self.__class__(item for item in other if item in self)\r
- __and__ = intersection\r
-\r
- def intersection_update(self, other):\r
- self.__iand__(other)\r
- def __iand__(self, other):\r
- if self._pending_removals:\r
- self._commit_removals()\r
- self.data.intersection_update(ref(item) for item in other)\r
- return self\r
-\r
- def issubset(self, other):\r
- return self.data.issubset(ref(item) for item in other)\r
- __le__ = issubset\r
-\r
- def __lt__(self, other):\r
- return self.data < set(ref(item) for item in other)\r
-\r
- def issuperset(self, other):\r
- return self.data.issuperset(ref(item) for item in other)\r
- __ge__ = issuperset\r
-\r
- def __gt__(self, other):\r
- return self.data > set(ref(item) for item in other)\r
-\r
- def __eq__(self, other):\r
- if not isinstance(other, self.__class__):\r
- return NotImplemented\r
- return self.data == set(ref(item) for item in other)\r
-\r
- def __ne__(self, other):\r
- opposite = self.__eq__(other)\r
- if opposite is NotImplemented:\r
- return NotImplemented\r
- return not opposite\r
-\r
- def symmetric_difference(self, other):\r
- newset = self.copy()\r
- newset.symmetric_difference_update(other)\r
- return newset\r
- __xor__ = symmetric_difference\r
-\r
- def symmetric_difference_update(self, other):\r
- self.__ixor__(other)\r
- def __ixor__(self, other):\r
- if self._pending_removals:\r
- self._commit_removals()\r
- if self is other:\r
- self.data.clear()\r
- else:\r
- self.data.symmetric_difference_update(ref(item, self._remove) for item in other)\r
- return self\r
-\r
- def union(self, other):\r
- return self.__class__(e for s in (self, other) for e in s)\r
- __or__ = union\r
-\r
- def isdisjoint(self, other):\r
- return len(self.intersection(other)) == 0\r