You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

196 lines
5.5 KiB

Merged revisions 86881,86887,86913-86915,86933,86943,86960,86964,86974,86980,86996,87008 via svnmerge from svn+ssh://pythondev@svn.python.org/python/branches/py3k ........ r86881 | georg.brandl | 2010-11-30 08:43:28 +0100 (Di, 30 Nov 2010) | 1 line #10584: fix bad links. ........ r86887 | georg.brandl | 2010-11-30 15:57:54 +0100 (Di, 30 Nov 2010) | 1 line Fix typo. ........ r86913 | georg.brandl | 2010-12-01 16:32:43 +0100 (Mi, 01 Dez 2010) | 1 line Add missing word, and add a better reference to the actual function. ........ r86914 | georg.brandl | 2010-12-01 16:36:33 +0100 (Mi, 01 Dez 2010) | 1 line #10594: fix parameter names in PyList API docs. ........ r86915 | georg.brandl | 2010-12-01 16:44:25 +0100 (Mi, 01 Dez 2010) | 1 line Fix some markup and style in the unittest docs. ........ r86933 | georg.brandl | 2010-12-02 19:02:01 +0100 (Do, 02 Dez 2010) | 1 line #10597: fix Py_SetPythonHome docs by pointing to where the meaning of PYTHONHOME is already documented. ........ r86943 | georg.brandl | 2010-12-02 23:35:25 +0100 (Do, 02 Dez 2010) | 1 line Re-add accidentally removed line. ........ r86960 | georg.brandl | 2010-12-03 08:55:44 +0100 (Fr, 03 Dez 2010) | 1 line #10360: catch TypeError in WeakSet.__contains__, just like WeakKeyDictionary does. ........ r86964 | georg.brandl | 2010-12-03 10:58:38 +0100 (Fr, 03 Dez 2010) | 1 line #10549: fix interface of docclass() for text documenter. ........ r86974 | georg.brandl | 2010-12-03 16:30:09 +0100 (Fr, 03 Dez 2010) | 1 line Markup consistency fixes. ........ r86980 | georg.brandl | 2010-12-03 18:19:27 +0100 (Fr, 03 Dez 2010) | 1 line Fix punctuation. ........ r86996 | georg.brandl | 2010-12-03 20:56:42 +0100 (Fr, 03 Dez 2010) | 1 line Fix indentation. ........ r87008 | georg.brandl | 2010-12-04 10:04:04 +0100 (Sa, 04 Dez 2010) | 1 line Fix typo. ........
16 years ago
  1. # Access WeakSet through the weakref module.
  2. # This code is separated-out because it is needed
  3. # by abc.py to load everything else at startup.
  4. from _weakref import ref
  5. __all__ = ['WeakSet']
  6. class _IterationGuard(object):
  7. # This context manager registers itself in the current iterators of the
  8. # weak container, such as to delay all removals until the context manager
  9. # exits.
  10. # This technique should be relatively thread-safe (since sets are).
  11. def __init__(self, weakcontainer):
  12. # Don't create cycles
  13. self.weakcontainer = ref(weakcontainer)
  14. def __enter__(self):
  15. w = self.weakcontainer()
  16. if w is not None:
  17. w._iterating.add(self)
  18. return self
  19. def __exit__(self, e, t, b):
  20. w = self.weakcontainer()
  21. if w is not None:
  22. s = w._iterating
  23. s.remove(self)
  24. if not s:
  25. w._commit_removals()
  26. class WeakSet(object):
  27. def __init__(self, data=None):
  28. self.data = set()
  29. def _remove(item, selfref=ref(self)):
  30. self = selfref()
  31. if self is not None:
  32. if self._iterating:
  33. self._pending_removals.append(item)
  34. else:
  35. self.data.discard(item)
  36. self._remove = _remove
  37. # A list of keys to be removed
  38. self._pending_removals = []
  39. self._iterating = set()
  40. if data is not None:
  41. self.update(data)
  42. def _commit_removals(self):
  43. l = self._pending_removals
  44. discard = self.data.discard
  45. while l:
  46. discard(l.pop())
  47. def __iter__(self):
  48. with _IterationGuard(self):
  49. for itemref in self.data:
  50. item = itemref()
  51. if item is not None:
  52. yield item
  53. def __len__(self):
  54. return len(self.data) - len(self._pending_removals)
  55. def __contains__(self, item):
  56. try:
  57. wr = ref(item)
  58. except TypeError:
  59. return False
  60. return wr in self.data
  61. def __reduce__(self):
  62. return (self.__class__, (list(self),),
  63. getattr(self, '__dict__', None))
  64. __hash__ = None
  65. def add(self, item):
  66. if self._pending_removals:
  67. self._commit_removals()
  68. self.data.add(ref(item, self._remove))
  69. def clear(self):
  70. if self._pending_removals:
  71. self._commit_removals()
  72. self.data.clear()
  73. def copy(self):
  74. return self.__class__(self)
  75. def pop(self):
  76. if self._pending_removals:
  77. self._commit_removals()
  78. while True:
  79. try:
  80. itemref = self.data.pop()
  81. except KeyError:
  82. raise KeyError('pop from empty WeakSet')
  83. item = itemref()
  84. if item is not None:
  85. return item
  86. def remove(self, item):
  87. if self._pending_removals:
  88. self._commit_removals()
  89. self.data.remove(ref(item))
  90. def discard(self, item):
  91. if self._pending_removals:
  92. self._commit_removals()
  93. self.data.discard(ref(item))
  94. def update(self, other):
  95. if self._pending_removals:
  96. self._commit_removals()
  97. for element in other:
  98. self.add(element)
  99. def __ior__(self, other):
  100. self.update(other)
  101. return self
  102. def difference(self, other):
  103. newset = self.copy()
  104. newset.difference_update(other)
  105. return newset
  106. __sub__ = difference
  107. def difference_update(self, other):
  108. self.__isub__(other)
  109. def __isub__(self, other):
  110. if self._pending_removals:
  111. self._commit_removals()
  112. if self is other:
  113. self.data.clear()
  114. else:
  115. self.data.difference_update(ref(item) for item in other)
  116. return self
  117. def intersection(self, other):
  118. return self.__class__(item for item in other if item in self)
  119. __and__ = intersection
  120. def intersection_update(self, other):
  121. self.__iand__(other)
  122. def __iand__(self, other):
  123. if self._pending_removals:
  124. self._commit_removals()
  125. self.data.intersection_update(ref(item) for item in other)
  126. return self
  127. def issubset(self, other):
  128. return self.data.issubset(ref(item) for item in other)
  129. __le__ = issubset
  130. def __lt__(self, other):
  131. return self.data < set(ref(item) for item in other)
  132. def issuperset(self, other):
  133. return self.data.issuperset(ref(item) for item in other)
  134. __ge__ = issuperset
  135. def __gt__(self, other):
  136. return self.data > set(ref(item) for item in other)
  137. def __eq__(self, other):
  138. if not isinstance(other, self.__class__):
  139. return NotImplemented
  140. return self.data == set(ref(item) for item in other)
  141. def symmetric_difference(self, other):
  142. newset = self.copy()
  143. newset.symmetric_difference_update(other)
  144. return newset
  145. __xor__ = symmetric_difference
  146. def symmetric_difference_update(self, other):
  147. self.__ixor__(other)
  148. def __ixor__(self, other):
  149. if self._pending_removals:
  150. self._commit_removals()
  151. if self is other:
  152. self.data.clear()
  153. else:
  154. self.data.symmetric_difference_update(ref(item, self._remove) for item in other)
  155. return self
  156. def union(self, other):
  157. return self.__class__(e for s in (self, other) for e in s)
  158. __or__ = union
  159. def isdisjoint(self, other):
  160. return len(self.intersection(other)) == 0