crosshair-tool 0.0.99__cp312-cp312-macosx_10_13_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. _crosshair_tracers.cpython-312-darwin.so +0 -0
  2. crosshair/__init__.py +42 -0
  3. crosshair/__main__.py +8 -0
  4. crosshair/_mark_stacks.h +790 -0
  5. crosshair/_preliminaries_test.py +18 -0
  6. crosshair/_tracers.h +94 -0
  7. crosshair/_tracers_pycompat.h +522 -0
  8. crosshair/_tracers_test.py +138 -0
  9. crosshair/abcstring.py +245 -0
  10. crosshair/auditwall.py +190 -0
  11. crosshair/auditwall_test.py +77 -0
  12. crosshair/codeconfig.py +113 -0
  13. crosshair/codeconfig_test.py +117 -0
  14. crosshair/condition_parser.py +1237 -0
  15. crosshair/condition_parser_test.py +497 -0
  16. crosshair/conftest.py +30 -0
  17. crosshair/copyext.py +155 -0
  18. crosshair/copyext_test.py +84 -0
  19. crosshair/core.py +1763 -0
  20. crosshair/core_and_libs.py +149 -0
  21. crosshair/core_regestered_types_test.py +82 -0
  22. crosshair/core_test.py +1316 -0
  23. crosshair/diff_behavior.py +314 -0
  24. crosshair/diff_behavior_test.py +261 -0
  25. crosshair/dynamic_typing.py +346 -0
  26. crosshair/dynamic_typing_test.py +210 -0
  27. crosshair/enforce.py +282 -0
  28. crosshair/enforce_test.py +182 -0
  29. crosshair/examples/PEP316/__init__.py +1 -0
  30. crosshair/examples/PEP316/bugs_detected/__init__.py +0 -0
  31. crosshair/examples/PEP316/bugs_detected/getattr_magic.py +16 -0
  32. crosshair/examples/PEP316/bugs_detected/hash_consistent_with_equals.py +31 -0
  33. crosshair/examples/PEP316/bugs_detected/shopping_cart.py +24 -0
  34. crosshair/examples/PEP316/bugs_detected/showcase.py +39 -0
  35. crosshair/examples/PEP316/correct_code/__init__.py +0 -0
  36. crosshair/examples/PEP316/correct_code/arith.py +60 -0
  37. crosshair/examples/PEP316/correct_code/chess.py +77 -0
  38. crosshair/examples/PEP316/correct_code/nesting_inference.py +17 -0
  39. crosshair/examples/PEP316/correct_code/numpy_examples.py +132 -0
  40. crosshair/examples/PEP316/correct_code/rolling_average.py +35 -0
  41. crosshair/examples/PEP316/correct_code/showcase.py +104 -0
  42. crosshair/examples/__init__.py +0 -0
  43. crosshair/examples/check_examples_test.py +146 -0
  44. crosshair/examples/deal/__init__.py +1 -0
  45. crosshair/examples/icontract/__init__.py +1 -0
  46. crosshair/examples/icontract/bugs_detected/__init__.py +0 -0
  47. crosshair/examples/icontract/bugs_detected/showcase.py +41 -0
  48. crosshair/examples/icontract/bugs_detected/wrong_sign.py +8 -0
  49. crosshair/examples/icontract/correct_code/__init__.py +0 -0
  50. crosshair/examples/icontract/correct_code/arith.py +51 -0
  51. crosshair/examples/icontract/correct_code/showcase.py +94 -0
  52. crosshair/fnutil.py +391 -0
  53. crosshair/fnutil_test.py +75 -0
  54. crosshair/fuzz_core_test.py +516 -0
  55. crosshair/libimpl/__init__.py +0 -0
  56. crosshair/libimpl/arraylib.py +161 -0
  57. crosshair/libimpl/binascii_ch_test.py +30 -0
  58. crosshair/libimpl/binascii_test.py +67 -0
  59. crosshair/libimpl/binasciilib.py +150 -0
  60. crosshair/libimpl/bisectlib_test.py +23 -0
  61. crosshair/libimpl/builtinslib.py +5228 -0
  62. crosshair/libimpl/builtinslib_ch_test.py +1191 -0
  63. crosshair/libimpl/builtinslib_test.py +3735 -0
  64. crosshair/libimpl/codecslib.py +86 -0
  65. crosshair/libimpl/codecslib_test.py +86 -0
  66. crosshair/libimpl/collectionslib.py +264 -0
  67. crosshair/libimpl/collectionslib_ch_test.py +252 -0
  68. crosshair/libimpl/collectionslib_test.py +332 -0
  69. crosshair/libimpl/copylib.py +23 -0
  70. crosshair/libimpl/copylib_test.py +18 -0
  71. crosshair/libimpl/datetimelib.py +2559 -0
  72. crosshair/libimpl/datetimelib_ch_test.py +354 -0
  73. crosshair/libimpl/datetimelib_test.py +112 -0
  74. crosshair/libimpl/decimallib.py +5257 -0
  75. crosshair/libimpl/decimallib_ch_test.py +78 -0
  76. crosshair/libimpl/decimallib_test.py +76 -0
  77. crosshair/libimpl/encodings/__init__.py +23 -0
  78. crosshair/libimpl/encodings/_encutil.py +187 -0
  79. crosshair/libimpl/encodings/ascii.py +44 -0
  80. crosshair/libimpl/encodings/latin_1.py +40 -0
  81. crosshair/libimpl/encodings/utf_8.py +93 -0
  82. crosshair/libimpl/encodings_ch_test.py +83 -0
  83. crosshair/libimpl/fractionlib.py +16 -0
  84. crosshair/libimpl/fractionlib_test.py +80 -0
  85. crosshair/libimpl/functoolslib.py +34 -0
  86. crosshair/libimpl/functoolslib_test.py +56 -0
  87. crosshair/libimpl/hashliblib.py +30 -0
  88. crosshair/libimpl/hashliblib_test.py +18 -0
  89. crosshair/libimpl/heapqlib.py +47 -0
  90. crosshair/libimpl/heapqlib_test.py +21 -0
  91. crosshair/libimpl/importliblib.py +18 -0
  92. crosshair/libimpl/importliblib_test.py +38 -0
  93. crosshair/libimpl/iolib.py +216 -0
  94. crosshair/libimpl/iolib_ch_test.py +128 -0
  95. crosshair/libimpl/iolib_test.py +19 -0
  96. crosshair/libimpl/ipaddresslib.py +8 -0
  97. crosshair/libimpl/itertoolslib.py +44 -0
  98. crosshair/libimpl/itertoolslib_test.py +44 -0
  99. crosshair/libimpl/jsonlib.py +984 -0
  100. crosshair/libimpl/jsonlib_ch_test.py +42 -0
  101. crosshair/libimpl/jsonlib_test.py +51 -0
  102. crosshair/libimpl/mathlib.py +179 -0
  103. crosshair/libimpl/mathlib_ch_test.py +44 -0
  104. crosshair/libimpl/mathlib_test.py +67 -0
  105. crosshair/libimpl/oslib.py +7 -0
  106. crosshair/libimpl/pathliblib_test.py +10 -0
  107. crosshair/libimpl/randomlib.py +178 -0
  108. crosshair/libimpl/randomlib_test.py +120 -0
  109. crosshair/libimpl/relib.py +846 -0
  110. crosshair/libimpl/relib_ch_test.py +169 -0
  111. crosshair/libimpl/relib_test.py +493 -0
  112. crosshair/libimpl/timelib.py +72 -0
  113. crosshair/libimpl/timelib_test.py +82 -0
  114. crosshair/libimpl/typeslib.py +15 -0
  115. crosshair/libimpl/typeslib_test.py +36 -0
  116. crosshair/libimpl/unicodedatalib.py +75 -0
  117. crosshair/libimpl/unicodedatalib_test.py +42 -0
  118. crosshair/libimpl/urlliblib.py +23 -0
  119. crosshair/libimpl/urlliblib_test.py +19 -0
  120. crosshair/libimpl/weakreflib.py +13 -0
  121. crosshair/libimpl/weakreflib_test.py +69 -0
  122. crosshair/libimpl/zliblib.py +15 -0
  123. crosshair/libimpl/zliblib_test.py +13 -0
  124. crosshair/lsp_server.py +261 -0
  125. crosshair/lsp_server_test.py +30 -0
  126. crosshair/main.py +973 -0
  127. crosshair/main_test.py +543 -0
  128. crosshair/objectproxy.py +376 -0
  129. crosshair/objectproxy_test.py +41 -0
  130. crosshair/opcode_intercept.py +601 -0
  131. crosshair/opcode_intercept_test.py +304 -0
  132. crosshair/options.py +218 -0
  133. crosshair/options_test.py +10 -0
  134. crosshair/patch_equivalence_test.py +75 -0
  135. crosshair/path_cover.py +209 -0
  136. crosshair/path_cover_test.py +138 -0
  137. crosshair/path_search.py +161 -0
  138. crosshair/path_search_test.py +52 -0
  139. crosshair/pathing_oracle.py +271 -0
  140. crosshair/pathing_oracle_test.py +21 -0
  141. crosshair/pure_importer.py +27 -0
  142. crosshair/pure_importer_test.py +16 -0
  143. crosshair/py.typed +0 -0
  144. crosshair/register_contract.py +273 -0
  145. crosshair/register_contract_test.py +190 -0
  146. crosshair/simplestructs.py +1165 -0
  147. crosshair/simplestructs_test.py +283 -0
  148. crosshair/smtlib.py +24 -0
  149. crosshair/smtlib_test.py +14 -0
  150. crosshair/statespace.py +1199 -0
  151. crosshair/statespace_test.py +108 -0
  152. crosshair/stubs_parser.py +352 -0
  153. crosshair/stubs_parser_test.py +43 -0
  154. crosshair/test_util.py +329 -0
  155. crosshair/test_util_test.py +26 -0
  156. crosshair/tools/__init__.py +0 -0
  157. crosshair/tools/check_help_in_doc.py +264 -0
  158. crosshair/tools/check_init_and_setup_coincide.py +119 -0
  159. crosshair/tools/generate_demo_table.py +127 -0
  160. crosshair/tracers.py +544 -0
  161. crosshair/tracers_test.py +154 -0
  162. crosshair/type_repo.py +151 -0
  163. crosshair/unicode_categories.py +589 -0
  164. crosshair/unicode_categories_test.py +27 -0
  165. crosshair/util.py +741 -0
  166. crosshair/util_test.py +173 -0
  167. crosshair/watcher.py +307 -0
  168. crosshair/watcher_test.py +107 -0
  169. crosshair/z3util.py +76 -0
  170. crosshair/z3util_test.py +11 -0
  171. crosshair_tool-0.0.99.dist-info/METADATA +144 -0
  172. crosshair_tool-0.0.99.dist-info/RECORD +176 -0
  173. crosshair_tool-0.0.99.dist-info/WHEEL +6 -0
  174. crosshair_tool-0.0.99.dist-info/entry_points.txt +3 -0
  175. crosshair_tool-0.0.99.dist-info/licenses/LICENSE +93 -0
  176. crosshair_tool-0.0.99.dist-info/top_level.txt +2 -0
@@ -0,0 +1,1165 @@
1
+ import collections.abc
2
+ import copy
3
+ import dataclasses
4
+ import functools
5
+ import itertools
6
+ import numbers
7
+ import operator
8
+ import sys
9
+ from typing import (
10
+ Any,
11
+ Callable,
12
+ Iterable,
13
+ Mapping,
14
+ MutableMapping,
15
+ MutableSequence,
16
+ Optional,
17
+ Sequence,
18
+ Set,
19
+ Tuple,
20
+ Union,
21
+ )
22
+
23
+ from crosshair.core import deep_realize
24
+ from crosshair.tracers import NoTracing, ResumedTracing, tracing_iter
25
+ from crosshair.util import (
26
+ CrossHairValue,
27
+ assert_tracing,
28
+ is_hashable,
29
+ is_iterable,
30
+ name_of_type,
31
+ )
32
+
33
+
34
+ class MapBase(collections.abc.MutableMapping):
35
+ def __eq__(self, other):
36
+ # Make our own __eq__ because the one in abc will hash all of our keys.
37
+ if not isinstance(other, collections.abc.Mapping):
38
+ return NotImplemented
39
+ if len(self) != len(other):
40
+ return False
41
+ for k, self_value in self.items():
42
+ found = False
43
+ # We do a slow nested loop search because we don't want to hash the key.
44
+ for other_key, other_value in other.items():
45
+ if other_key != k:
46
+ continue
47
+ if self_value == other_value:
48
+ found = True
49
+ break
50
+ else:
51
+ return False
52
+ if not found:
53
+ return False
54
+ return True
55
+
56
+ def copy(self):
57
+ raise NotImplementedError
58
+
59
+ def __ch_pytype__(self):
60
+ return dict
61
+
62
+ def __ch_realize__(self):
63
+ memo = {}
64
+ return {deep_realize(k, memo): v for k, v in tracing_iter(self.items())}
65
+
66
+ def __ch_deep_realize__(self, memo):
67
+ return {
68
+ deep_realize(k, memo): deep_realize(v, memo)
69
+ for k, v in tracing_iter(self.items())
70
+ }
71
+
72
+ def __repr__(self):
73
+ contents = ", ".join(f"{repr(k)}: {repr(v)}" for (k, v) in self.items())
74
+ return "{" + contents + "}"
75
+
76
+ if sys.version_info >= (3, 9):
77
+
78
+ def __or__(self, other: Mapping) -> Mapping:
79
+ if not isinstance(other, Mapping):
80
+ raise TypeError
81
+ union_map = self.copy()
82
+ union_map.update(other)
83
+ return union_map
84
+
85
+ __ror__ = __or__
86
+
87
+
88
+ _MISSING = object()
89
+
90
+
91
+ class SimpleDict(MapBase):
92
+ """
93
+ A pure Python implementation of a dictionary.
94
+ Intentionally does no hashing (linear searches).
95
+
96
+ #inv: set(self.keys()) == set(dict(self.items()).keys())
97
+
98
+ >>> d = SimpleDict([(1, 'one'), (2, 'two')])
99
+ >>> d
100
+ {1: 'one', 2: 'two'}
101
+ >>> d[3] = 'three'
102
+ >>> len(d)
103
+ 3
104
+ >>> d[2] = 'cat'
105
+ >>> d[2]
106
+ 'cat'
107
+ >>> del d[1]
108
+ >>> list(d.keys())
109
+ [2, 3]
110
+ """
111
+
112
+ contents_: MutableSequence
113
+
114
+ def __init__(self, contents: MutableSequence):
115
+ """
116
+ Initialize with (key, value) pairs.
117
+
118
+ ``contents`` is assumed to not have duplicate keys.
119
+ """
120
+ self.contents_ = contents
121
+
122
+ def __getitem__(self, key, default=_MISSING):
123
+ if not is_hashable(key):
124
+ raise TypeError("unhashable type")
125
+ for k, v in self.contents_:
126
+ # Note that the identity check below is not just an optimization;
127
+ # it is required to implement the semantics of NaN dict keys
128
+ if k is key or k == key:
129
+ return v
130
+ if default is _MISSING:
131
+ raise KeyError
132
+ return default
133
+
134
+ def __setitem__(self, key, value):
135
+ if not is_hashable(key):
136
+ raise TypeError("unhashable type")
137
+ for i, (k, v) in enumerate(self.contents_):
138
+ if k == key:
139
+ self.contents_[i] = (k, value)
140
+ return
141
+ self.contents_.append((key, value))
142
+
143
+ def __delitem__(self, key):
144
+ if not is_hashable(key):
145
+ raise TypeError("unhashable type")
146
+ for i, (k, v) in enumerate(self.contents_):
147
+ if k == key:
148
+ del self.contents_[i]
149
+ return
150
+ raise KeyError
151
+
152
+ def __iter__(self):
153
+ return (k for (k, v) in self.contents_)
154
+
155
+ def __reversed__(self):
156
+ return (k for (k, v) in reversed(self.contents_))
157
+
158
+ def __bool__(self):
159
+ return (len(self.contents_) > 0).__bool__()
160
+
161
+ def __len__(self):
162
+ return self.contents_.__len__()
163
+
164
+ def popitem(self):
165
+ if not self.contents_:
166
+ raise KeyError
167
+ (k, v) = self.contents_.pop()
168
+ return (k, v)
169
+
170
+ def copy(self):
171
+ return SimpleDict(self.contents_[:])
172
+
173
+
174
+ _DELETED = object()
175
+ _NOT_FOUND = object()
176
+
177
+
178
+ class ShellMutableMap(MapBase, collections.abc.MutableMapping):
179
+ def __init__(self, inner: Mapping):
180
+ self._mutations: MutableMapping = SimpleDict([])
181
+ self._inner = inner
182
+ self._len = inner.__len__()
183
+
184
+ def __getitem__(self, key):
185
+ ret = self._mutations.get(key, _NOT_FOUND)
186
+ if ret is _DELETED:
187
+ raise KeyError
188
+ elif ret is _NOT_FOUND:
189
+ return self._inner.__getitem__(key)
190
+ else:
191
+ return ret
192
+
193
+ if sys.version_info >= (3, 8):
194
+
195
+ def __reversed__(self):
196
+ return self._reversed()
197
+
198
+ def _reversed(self):
199
+ deleted = []
200
+ mutations = self._mutations
201
+ for k in reversed(mutations):
202
+ if mutations[k] is _DELETED:
203
+ deleted.append(k)
204
+ continue
205
+ else:
206
+ yield k
207
+ inner = self._inner
208
+ for k in reversed(inner):
209
+ if k in deleted:
210
+ continue
211
+ else:
212
+ yield k
213
+
214
+ def __iter__(self):
215
+ mutations = self._mutations
216
+ suppress = list(mutations.keys()) # check against list to avoid hash
217
+ for k in self._inner:
218
+ if k not in suppress:
219
+ yield k
220
+ for k, v in self._mutations.items():
221
+ if v is not _DELETED:
222
+ yield k
223
+
224
+ def __eq__(self, other):
225
+ if not self._mutations:
226
+ return self._inner.__eq__(other)
227
+ if not isinstance(other, collections.abc.Mapping):
228
+ return False
229
+ if len(self) != len(other):
230
+ return False
231
+ for k, v in other.items():
232
+ if k not in self or self[k] != v:
233
+ return False
234
+ return True
235
+
236
+ def __bool__(self):
237
+ return bool(self._len > 0)
238
+
239
+ def __len__(self):
240
+ return self._len
241
+
242
+ def __setitem__(self, key, val):
243
+ if key not in self:
244
+ self._len += 1
245
+ self._mutations[key] = val
246
+
247
+ def __delitem__(self, key):
248
+ first_hit = self._mutations.get(key, _NOT_FOUND)
249
+ if first_hit is _DELETED:
250
+ raise KeyError
251
+ if first_hit is _NOT_FOUND:
252
+ if key not in self._inner:
253
+ raise KeyError
254
+ self._mutations[key] = _DELETED
255
+ self._len -= 1
256
+
257
+ def _lastitem(self):
258
+ raise KeyError
259
+
260
+ def pop(self, key, default=_MISSING):
261
+ # CPython checks the empty case before attempting to hash the key.
262
+ # So this must happen before the hash-ability check:
263
+ if self._len > 0:
264
+ try:
265
+ value = self[key]
266
+ except KeyError:
267
+ pass
268
+ else:
269
+ del self[key]
270
+ return value
271
+ # Not found:
272
+ if default is _MISSING:
273
+ raise KeyError(key)
274
+ return default
275
+
276
+ def popitem(self):
277
+ for key in self._reversed():
278
+ val = self.__getitem__(key)
279
+ self.__delitem__(key)
280
+ return (key, val)
281
+ raise KeyError
282
+
283
+ def copy(self):
284
+ m = ShellMutableMap(self._inner)
285
+ m._mutations = self._mutations.copy()
286
+ return m
287
+
288
+
289
+ def normalize_idx(idx: Any, container_len: int) -> int:
290
+ if (idx is not None) and (not hasattr(idx, "__index__")):
291
+ raise TypeError("indices must be integers or slices")
292
+ if idx < 0:
293
+ return idx + container_len
294
+ return idx
295
+
296
+
297
+ def check_idx(idx: Any, container_len: int) -> int:
298
+ if not hasattr(idx, "__index__"):
299
+ raise TypeError("indices must be integers or slices, not str")
300
+ normalized_idx = normalize_idx(idx, container_len)
301
+ if 0 <= normalized_idx < container_len:
302
+ return normalized_idx
303
+ raise IndexError
304
+
305
+
306
+ def clamp_slice(s: slice, container_len: int) -> slice:
307
+ if s.step < 0:
308
+ if s.start < 0 or s.stop >= container_len - 1:
309
+ return slice(0, 0, s.step)
310
+
311
+ def clamper(i):
312
+ if i < 0:
313
+ return None
314
+ if i >= container_len:
315
+ return container_len - 1
316
+ return i
317
+
318
+ else:
319
+
320
+ def clamper(i):
321
+ if i < 0:
322
+ return 0
323
+ if i > container_len:
324
+ return container_len
325
+ return i
326
+
327
+ return slice(clamper(s.start), clamper(s.stop), s.step)
328
+
329
+
330
+ def offset_slice(s: slice, offset: int) -> slice:
331
+ return slice(s.start + offset, s.stop + offset, s.step)
332
+
333
+
334
+ def compose_slices(prelen: int, postlen: int, s: slice):
335
+ """Transform a slice to apply to a larger sequence."""
336
+ start, stop = s.start, s.stop
337
+ if start >= 0:
338
+ start += prelen
339
+ else:
340
+ start -= prelen
341
+ if stop >= 0:
342
+ stop += prelen
343
+ else:
344
+ stop -= postlen
345
+ return slice(start, stop, s.step)
346
+
347
+
348
+ def cut_slice(start: int, stop: int, step: int, cut: int) -> Tuple[slice, slice]:
349
+ backwards = step < 0
350
+ if backwards:
351
+ start, stop, step, cut = -start, -stop, -step, -cut
352
+ # Modulous with negatives is super hard to reason about, shift everything >= 0:
353
+ delta = -min(start, stop, cut)
354
+ start, stop, cut = start + delta, stop + delta, cut + delta
355
+ if cut < start:
356
+ lstart, lstop = cut, cut
357
+ rstart, rstop = start, stop
358
+ elif cut > stop:
359
+ lstart, lstop = start, stop
360
+ rstart, rstop = cut, cut
361
+ else:
362
+ mid = min(cut, stop)
363
+ lstart, lstop = start, mid
364
+ empties_at_tail = mid % step
365
+ if empties_at_tail > 0:
366
+ mid += step - empties_at_tail
367
+ rstart = mid
368
+ rstop = stop
369
+ lstart, lstop = lstart - delta, lstop - delta
370
+ rstart, rstop = rstart - delta, rstop - delta
371
+ if backwards:
372
+ lstart, lstop = -lstart, -lstop
373
+ rstart, rstop = -rstart, -rstop
374
+ step = -step
375
+ return (slice(lstart, lstop, step), slice(rstart, rstop, step))
376
+
377
+
378
+ def indices(s: slice, container_len: int) -> Tuple[int, int, int]:
379
+ """
380
+ (Mostly) mimic ``slice.indices``.
381
+
382
+ This is a pure Python version of ``slice.indices()`` that doesn't force integers
383
+ into existence.
384
+ Note that, unlike `slice.indices`, this function does not "clamp" the index to the
385
+ range [0, container_len).
386
+ """
387
+ start, stop, step = s.start, s.stop, s.step
388
+ if (step is not None) and (not hasattr(step, "__index__")):
389
+ raise TypeError(
390
+ "slice indices must be integers or None or have an __index__ method"
391
+ )
392
+ if step is None:
393
+ step = 1
394
+ elif step <= 0:
395
+ # fallback to python implementation (this will realize values)
396
+ return s.indices(container_len)
397
+ return (
398
+ 0 if start is None else normalize_idx(start, container_len),
399
+ container_len if stop is None else normalize_idx(stop, container_len),
400
+ step,
401
+ )
402
+
403
+
404
+ @functools.total_ordering
405
+ class SeqBase(CrossHairValue):
406
+ def __hash__(self):
407
+ # TODO: test
408
+ return hash(tuple(self))
409
+
410
+ def __eq__(self, other):
411
+ if self is other:
412
+ return True
413
+ if not is_iterable(other):
414
+ return False
415
+ if len(self) != len(other):
416
+ return False
417
+ for myval, otherval in zip(self, other):
418
+ if myval is otherval:
419
+ continue
420
+ if myval != otherval:
421
+ return False
422
+ return True
423
+
424
+ def __lt__(self, other):
425
+ # NOTE: subclasses will need further type restrictions.
426
+ # For example, `[1,2] <= (1,2)` raises a TypeError.
427
+ if not is_iterable(other):
428
+ return NotImplemented
429
+ for v1, v2 in zip(self, other):
430
+ if v1 == v2:
431
+ continue
432
+ return v1 < v2
433
+ return len(self) < len(other)
434
+
435
+ def __bool__(self):
436
+ return bool(self.__len__() > 0)
437
+
438
+ def __add__(self, other):
439
+ if isinstance(other, collections.abc.Sequence):
440
+ return concatenate_sequences(self, other)
441
+ raise TypeError(f"unsupported operand type(s) for +")
442
+
443
+ def __radd__(self, other):
444
+ if isinstance(other, collections.abc.Sequence):
445
+ return concatenate_sequences(other, self)
446
+ raise TypeError(f"unsupported operand type(s) for +")
447
+
448
+ def __mul__(self, other):
449
+ if not isinstance(other, int):
450
+ raise TypeError("can't multiply by non-int xx")
451
+ if other <= 0:
452
+ # A trick to get an empty thing of the same type!:
453
+ return self[0:0]
454
+ ret = self
455
+ for idx in range(1, other):
456
+ ret = self.__add__(ret)
457
+ return ret
458
+
459
+ def __rmul__(self, other):
460
+ return self.__mul__(other)
461
+
462
+
463
+ @dataclasses.dataclass(eq=False)
464
+ class SequenceConcatenation(collections.abc.Sequence, SeqBase):
465
+ _first: Sequence
466
+ _second: Sequence
467
+ _len: Optional[int] = None
468
+
469
+ def __ch_pytype__(self):
470
+ return tuple
471
+
472
+ def __getitem__(self, i: Union[int, slice]):
473
+ """Get the item from the concatenation."""
474
+ first, second = self._first, self._second
475
+ firstlen, secondlen = len(first), len(second)
476
+ totallen = firstlen + secondlen
477
+ if isinstance(i, int):
478
+ i = check_idx(i, totallen)
479
+ return first[i] if i < firstlen else second[i - firstlen]
480
+ else:
481
+ if i.step is None or i.step > 0:
482
+ # This block is functionally redundant with the more general
483
+ # logic afterwards. It exists for additional efficency when
484
+ # we can easily slice using one side or the other.
485
+ if i.stop is not None and 0 <= i.stop <= firstlen:
486
+ if i.start is None or i.start >= 0:
487
+ return first.__getitem__(i)
488
+ if i.start < -secondlen:
489
+ return first.__getitem__(
490
+ slice(i.start + secondlen, i.stop, i.step)
491
+ )
492
+ if i.start is not None and i.start >= firstlen:
493
+ return second.__getitem__(
494
+ slice(
495
+ i.start - firstlen,
496
+ (
497
+ i.stop
498
+ if i.stop is None or i.stop < 0
499
+ else i.stop - firstlen
500
+ ),
501
+ i.step,
502
+ )
503
+ )
504
+ start, stop, step = i.indices(totallen)
505
+ cutpoint = firstlen if step > 0 else firstlen - 1
506
+ slice1, slice2 = cut_slice(start, stop, step, cutpoint)
507
+ if step > 0:
508
+ slice1 = clamp_slice(slice1, firstlen)
509
+ slice2 = clamp_slice(offset_slice(slice2, -firstlen), secondlen)
510
+ return concatenate_sequences(first[slice1], second[slice2])
511
+ else:
512
+ slice1 = clamp_slice(offset_slice(slice1, -firstlen), secondlen)
513
+ slice2 = clamp_slice(slice2, firstlen)
514
+ return concatenate_sequences(second[slice1], first[slice2])
515
+
516
+ def __eq__(self, other):
517
+ with NoTracing():
518
+ if not hasattr(other, "__len__"):
519
+ return False
520
+ first, second = self._first, self._second
521
+ if self.__len__() != other.__len__():
522
+ return False
523
+ firstlen = first.__len__()
524
+ return first == other[:firstlen] and second == other[firstlen:]
525
+
526
+ def __contains__(self, item):
527
+ return self._first.__contains__(item) or self._second.__contains__(item)
528
+
529
+ def __iter__(self):
530
+ return itertools.chain(self._first, self._second)
531
+
532
+ def __len__(self):
533
+ if self._len is None:
534
+ self._len = len(self._first) + len(self._second)
535
+ return self._len
536
+
537
+
538
+ @dataclasses.dataclass(eq=False) # type: ignore # (https://github.com/python/mypy/issues/5374)
539
+ class SliceView(collections.abc.Sequence, SeqBase):
540
+ seq: Sequence
541
+ start: int
542
+ stop: int
543
+
544
+ def __ch_pytype__(self):
545
+ return tuple
546
+
547
+ @staticmethod
548
+ def slice(seq: Sequence, start: int, stop: int) -> Sequence:
549
+ seqlen = seq.__len__()
550
+ left_at_end = start <= 0
551
+ right_at_end = stop >= seqlen
552
+ if left_at_end:
553
+ if right_at_end:
554
+ return seq
555
+ start = 0
556
+ if right_at_end:
557
+ stop = seqlen
558
+ if stop <= start:
559
+ stop = start
560
+ return SliceView(seq, start, stop)
561
+
562
+ def __getitem__(self, key):
563
+ mystart = self.start
564
+ mylen = self.stop - mystart
565
+ if type(key) is slice:
566
+ start, stop, step = indices(key, mylen)
567
+ if step == 1:
568
+ clamped = clamp_slice(slice(start, stop, step), mylen)
569
+ slice_start = mystart + clamped.start
570
+ slice_stop = mystart + clamped.stop
571
+ if slice_stop <= slice_start:
572
+ return SliceView((), 0, 0)
573
+ return SliceView(self.seq, slice_start, slice_stop)
574
+ else:
575
+ return list(self)[key]
576
+ else:
577
+ key = self.start + check_idx(key, mylen)
578
+ return self.seq[key]
579
+
580
+ def __len__(self) -> int:
581
+ return self.stop - self.start
582
+
583
+ def __iter__(self):
584
+ for i in range(self.start, self.stop):
585
+ yield self.seq[i]
586
+
587
+
588
+ def concatenate_sequences(a: Sequence, b: Sequence) -> Sequence:
589
+ with NoTracing():
590
+ if isinstance(a, list):
591
+ if isinstance(b, list):
592
+ return a + b
593
+ elif isinstance(b, SequenceConcatenation) and isinstance(b._first, list):
594
+ return SequenceConcatenation(a + b._first, b._second)
595
+ elif (
596
+ isinstance(a, SequenceConcatenation)
597
+ and isinstance(b, list)
598
+ and isinstance(a._second, list)
599
+ ):
600
+ return SequenceConcatenation(a._first, a._second + b)
601
+ return SequenceConcatenation(a, b)
602
+
603
+
604
+ def sequence_evaluation(seq: Sequence):
605
+ with NoTracing():
606
+ if is_hashable(seq):
607
+ return seq # immutable datastructures are fine
608
+ elif isinstance(seq, ShellMutableSequence):
609
+ return seq.inner
610
+ else:
611
+ return list(seq) # TODO: use tracing_iter() here?
612
+
613
+
614
+ @dataclasses.dataclass(eq=False)
615
+ class ShellMutableSequence(collections.abc.MutableSequence, SeqBase):
616
+ """
617
+ Wrap a sequence and provide mutating operations without modifying the original.
618
+
619
+ It reuses portions of the original list as best it can.
620
+ """
621
+
622
+ inner: Sequence
623
+
624
+ __hash__ = None # type: ignore
625
+
626
+ def _spawn(self, items: Sequence) -> "ShellMutableSequence":
627
+ # For overriding in subclasses.
628
+ return ShellMutableSequence(items)
629
+
630
+ def __eq__(self, other):
631
+ with NoTracing():
632
+ if isinstance(other, ShellMutableSequence):
633
+ other = other.inner
634
+ return self.inner.__eq__(other)
635
+
636
+ def __setitem__(self, k, v):
637
+ inner = self.inner
638
+ old_len = len(inner)
639
+ if isinstance(k, slice):
640
+ if not isinstance(v, collections.abc.Iterable):
641
+ raise TypeError("can only assign an iterable")
642
+ # Make a copy if the argument is a mutable container:
643
+ v = sequence_evaluation(v)
644
+ start, stop, step = indices(k, old_len)
645
+ if step != 1:
646
+ # abort cleverness:
647
+ newinner = list(inner)
648
+ newinner[k] = v
649
+ self.inner = newinner
650
+ return
651
+ else:
652
+ newinner = v
653
+ elif isinstance(k, numbers.Integral):
654
+ k = check_idx(k, old_len)
655
+ start, stop = k, k + 1
656
+ newinner = [v]
657
+ else:
658
+ raise TypeError(
659
+ f'indices must be integers or slices, not "{name_of_type(k)}"'
660
+ )
661
+
662
+ if stop < start:
663
+ stop = start
664
+ # At this point, `stop` >= `start`
665
+ if start > 0:
666
+ newinner = concatenate_sequences(inner[:start], newinner)
667
+ elif stop <= 0:
668
+ stop = 0
669
+ # At this point, `stop` must be >= 0
670
+ if stop < old_len:
671
+ newinner = concatenate_sequences(newinner, inner[stop:])
672
+ self.inner = newinner
673
+
674
+ def __delitem__(self, k):
675
+ if isinstance(k, slice):
676
+ if k.step in (None, 1):
677
+ self.__setitem__(k, [])
678
+ else:
679
+ self.inner = list(self.inner)
680
+ self.inner.__delitem__(k)
681
+ else:
682
+ mylen = self.inner.__len__()
683
+ idx = check_idx(k, mylen)
684
+ self.__setitem__(slice(idx, idx + 1, 1), [])
685
+
686
+ def __add__(self, other):
687
+ if isinstance(other, collections.abc.Sequence):
688
+ return self._spawn(
689
+ concatenate_sequences(self.inner, sequence_evaluation(other))
690
+ )
691
+ raise TypeError(f"unsupported operand type(s) for +")
692
+
693
+ def __radd__(self, other):
694
+ if isinstance(other, collections.abc.Sequence):
695
+ return self._spawn(
696
+ concatenate_sequences(sequence_evaluation(other), self.inner)
697
+ )
698
+ raise TypeError(f"unsupported operand type(s) for +")
699
+
700
+ def __imul__(self, other):
701
+ return self._spawn(self * other)
702
+
703
+ def append(self, item):
704
+ inner = self.inner
705
+ self.inner = concatenate_sequences(inner, [item])
706
+
707
+ def extend(self, other):
708
+ if not isinstance(other, collections.abc.Iterable):
709
+ raise TypeError("object is not iterable")
710
+ self.inner = concatenate_sequences(self.inner, sequence_evaluation(other))
711
+
712
+ def index(self, *a) -> int:
713
+ return self.inner.index(*a)
714
+
715
+ def sort(self, key=None, reverse=False):
716
+ self.inner = sorted(self.inner, key=key, reverse=reverse)
717
+
718
+ def copy(self):
719
+ return self[:]
720
+
721
+ def __len__(self):
722
+ return self.inner.__len__()
723
+
724
+ def insert(self, index, item):
725
+ self.__setitem__(slice(index, index, 1), [item])
726
+
727
+ def __getitem__(self, key):
728
+ if isinstance(key, slice):
729
+ return self._spawn(self.inner.__getitem__(key))
730
+ else:
731
+ return self.inner.__getitem__(key)
732
+
733
+ def __repr__(self):
734
+ contents = ", ".join(map(repr, self))
735
+ return f"[{contents}]"
736
+
737
+ def __contains__(self, other):
738
+ return self.inner.__contains__(other)
739
+
740
+ def __iter__(self):
741
+ return self.inner.__iter__()
742
+
743
+ def reverse(self):
744
+ self.inner = list(reversed(self.inner))
745
+
746
+
747
+ AbcSet = collections.abc.Set
748
+ AbcMutableSet = collections.abc.MutableSet
749
+
750
+
751
+ def _force_arg_to_set(x: object) -> AbcSet:
752
+ with NoTracing():
753
+ if isinstance(x, AbcSet):
754
+ while isinstance(x, ShellMutableSet):
755
+ x = x._inner
756
+ if isinstance(x, AbcMutableSet):
757
+ # Already known to have unique elements:
758
+ return LinearSet(list(tracing_iter(x)))
759
+ elif isinstance(x, (frozenset, FrozenSetBase)):
760
+ return x # Immutable set
761
+ if is_iterable(x):
762
+ with ResumedTracing():
763
+ return LinearSet.check_unique_and_create(x)
764
+ raise TypeError
765
+
766
+
767
+ class SetBase(CrossHairValue):
768
+ def __bool__(self):
769
+ itr = iter(self)
770
+ try:
771
+ next(itr)
772
+ return True
773
+ except StopIteration:
774
+ return False
775
+
776
+ def __repr__(self):
777
+ return deep_realize(self).__repr__()
778
+
779
+ def __and__(self, x):
780
+ if not isinstance(x, AbcSet):
781
+ return NotImplemented
782
+ return AbcSet.__and__(self, x)
783
+
784
+ def __or__(self, x):
785
+ if not isinstance(x, AbcSet):
786
+ return NotImplemented
787
+ return AbcSet.__or__(self, x)
788
+
789
+ def __xor__(self, x):
790
+ if not isinstance(x, AbcSet):
791
+ return NotImplemented
792
+ return AbcSet.__xor__(self, x)
793
+
794
+ __rxor__ = __xor__
795
+ __ror__ = __or__
796
+ __rand__ = __and__
797
+
798
+ def __sub__(self, x):
799
+ if not isinstance(x, AbcSet):
800
+ return NotImplemented
801
+ return AbcSet.__sub__(self, x)
802
+
803
+ def __rsub__(self, x):
804
+ if not isinstance(x, AbcSet):
805
+ return NotImplemented
806
+ return AbcSet.__rsub__(self, x)
807
+
808
+ def copy(self):
809
+ return copy.copy(self)
810
+
811
+ def difference(self, *itrs):
812
+ for itr in itrs:
813
+ self = self.__sub__(_force_arg_to_set(itr))
814
+ return self
815
+
816
+ def intersection(self, *itrs):
817
+ for itr in itrs:
818
+ self = self.__and__(_force_arg_to_set(itr))
819
+ return self
820
+
821
+ def isdisjoint(self, x):
822
+ return not (self.intersection(x))
823
+
824
+ def issubset(self, x):
825
+ return self <= _force_arg_to_set(x)
826
+
827
+ def issuperset(self, x):
828
+ return self >= _force_arg_to_set(x)
829
+
830
+ def symmetric_difference(self, x):
831
+ return self.__xor__(_force_arg_to_set(x))
832
+
833
+ def union(self, *itrs):
834
+ for itr in itrs:
835
+ self = self.__or__(_force_arg_to_set(itr))
836
+ return self
837
+
838
+
839
+ class FrozenSetBase(SetBase, AbcSet):
840
+ def __ch_realize__(self):
841
+ # We are going to have to hash all of our contents,
842
+ # so just realize everything.
843
+ return self.__ch_deep_realize__({})
844
+
845
+ @assert_tracing(False)
846
+ def __ch_deep_realize__(self, memo):
847
+ contents = []
848
+ for item in tracing_iter(self):
849
+ contents.append(deep_realize(item, memo))
850
+ # TODO: This fails to preserve the iteration order;
851
+ # should we do something about that?:
852
+ return frozenset(contents)
853
+
854
+ def __ch_pytype__(self):
855
+ return frozenset
856
+
857
+ @classmethod
858
+ def _from_iterable(cls, it):
859
+ # overrides collections.abc.Set's version
860
+ return LinearSet.check_unique_and_create(it)
861
+
862
+ def __hash__(self):
863
+ return hash(deep_realize(self))
864
+
865
+
866
+ class SingletonSet(FrozenSetBase):
867
+ # Primarily this exists to avoid hashing values.
868
+ # TODO: should we fold uses of this into LinearSet, below?
869
+
870
+ def __init__(self, item):
871
+ self._item = item
872
+
873
+ def __contains__(self, x):
874
+ return x == self._item
875
+
876
+ def __iter__(self):
877
+ yield self._item
878
+
879
+ def __len__(self):
880
+ return 1
881
+
882
+
883
+ class EmptySet(FrozenSetBase):
884
+ def __contains__(self, x):
885
+ if not is_hashable(x):
886
+ raise TypeError
887
+ return False
888
+
889
+ def __iter__(self):
890
+ return
891
+ yield
892
+
893
+ def __len__(self):
894
+ return 0
895
+
896
+
897
+ class LinearSet(FrozenSetBase):
898
+ # Primarily this exists to avoid hashing values.
899
+ # Presumes that its arguments are already unique.
900
+
901
+ def __init__(self, items: Iterable):
902
+ self._items = items
903
+
904
+ @staticmethod
905
+ def check_unique_and_create(seq):
906
+ accepted = []
907
+ # duplicate detection:
908
+ # (alternatively, we could defer using LazySetCombination)
909
+ for item in seq:
910
+ if not is_hashable(item):
911
+ raise TypeError
912
+ if item not in accepted:
913
+ accepted.append(item)
914
+ return LinearSet(accepted)
915
+
916
+ def __contains__(self, x):
917
+ if not is_hashable(x):
918
+ raise TypeError
919
+ for item in self._items:
920
+ if x == item:
921
+ return True
922
+ return False
923
+
924
+ def __iter__(self):
925
+ for item in self._items:
926
+ yield item
927
+
928
+ def __len__(self):
929
+ return len(self._items)
930
+
931
+
932
+ class LazySetCombination(FrozenSetBase):
933
+ """
934
+ Provide a view over two sets and a logical operation in-between.
935
+
936
+ The view itself is an immutable set.
937
+
938
+ >>> a = {2, 4, 6 }
939
+ >>> b = { 4, 5, 6, 7}
940
+ >>> s = LazySetCombination(lambda a,b: (a and b), a, b)
941
+ >>> sorted(s)
942
+ [4, 6]
943
+ >>> a.add(5)
944
+ >>> sorted(s)
945
+ [4, 5, 6]
946
+ """
947
+
948
+ def __init__(self, op: Callable[[bool, bool], bool], a: Set, b: Set):
949
+ self._op = op
950
+ self._a = a
951
+ self._b = b
952
+
953
+ def __contains__(self, x):
954
+ ina = self._a.__contains__(x)
955
+ inb = self._b.__contains__(x)
956
+ return self._op(ina, inb)
957
+
958
+ def __iter__(self):
959
+ op, a, b = self._op, self._a, self._b
960
+
961
+ def afilter(a_item):
962
+ return op(True, a_item in b)
963
+
964
+ def bfilter(b_item):
965
+ ina = b_item in a
966
+ if ina:
967
+ # We've already seen this item and would have returned it
968
+ # while traversing a, if we were supposed to.
969
+ return False
970
+ return op(ina, True)
971
+
972
+ return itertools.chain(filter(afilter, a), filter(bfilter, b))
973
+
974
+ def __len__(self):
975
+ return sum(1 for i in self.__iter__())
976
+
977
+
978
+ class ShellMutableSet(SetBase, AbcMutableSet):
979
+ """
980
+ Provide a mutable view over an immutable set.
981
+
982
+ The mutating operations simply replace the underlying
983
+ data structure entirely.
984
+ This set also attempts to preserve insertion order of the set,
985
+ assuming the underlying set(s) do so as well.
986
+ """
987
+
988
+ _inner: Union[frozenset, FrozenSetBase]
989
+
990
+ @assert_tracing(False)
991
+ def __init__(self, inner: Iterable = EmptySet()):
992
+ if isinstance(inner, FrozenSetBase):
993
+ self._inner = inner
994
+ elif isinstance(inner, frozenset):
995
+ self._inner = LinearSet(inner)
996
+ elif isinstance(inner, set):
997
+ self._inner = LinearSet(frozenset(inner))
998
+ elif is_iterable(inner):
999
+ with ResumedTracing():
1000
+ self._inner = LinearSet.check_unique_and_create(inner)
1001
+ else:
1002
+ raise TypeError
1003
+
1004
+ def __ch_realize__(self):
1005
+ # Deep realize contents because the real set will want to hash them:
1006
+ return set(map(deep_realize, tracing_iter(self)))
1007
+
1008
+ def __ch_pytype__(self):
1009
+ return set
1010
+
1011
+ # methods that just defer to _inner
1012
+ def __contains__(self, x):
1013
+ return self._inner.__contains__(x)
1014
+
1015
+ def __iter__(self):
1016
+ # TODO: replace _inner after iteration (to avoid recalculation of lazy sub-sets)
1017
+ return self._inner.__iter__()
1018
+
1019
+ def __len__(self):
1020
+ return self._inner.__len__()
1021
+
1022
+ def __le__(self, x):
1023
+ return self._inner.__le__(x)
1024
+
1025
+ def __lt__(self, x):
1026
+ return self._inner.__lt__(x)
1027
+
1028
+ def __eq__(self, x):
1029
+ return self._inner.__eq__(x)
1030
+
1031
+ def __ne__(self, x):
1032
+ return self._inner.__ne__(x)
1033
+
1034
+ def __gt__(self, x):
1035
+ return self._inner.__gt__(x)
1036
+
1037
+ def __ge__(self, x):
1038
+ return self._inner.__ge__(x)
1039
+
1040
+ def isdisjoint(self, x):
1041
+ return self._inner.isdisjoint(x)
1042
+
1043
+ # mutation operations
1044
+ def add(self, x):
1045
+ if not is_hashable(x):
1046
+ raise TypeError(f"unhashable type: '{name_of_type(type(x))}'")
1047
+ self.__ior__(SingletonSet(x))
1048
+
1049
+ def clear(self):
1050
+ self._inner = frozenset()
1051
+
1052
+ def difference_update(self, x):
1053
+ self._inner = self._inner.difference(x)
1054
+
1055
+ def discard(self, x):
1056
+ if not is_hashable(x):
1057
+ raise TypeError(f"unhashable type: '{name_of_type(type(x))}'")
1058
+ self.__isub__(SingletonSet(x))
1059
+
1060
+ def intersection_update(self, x):
1061
+ self._inner = self._inner.intersection(x)
1062
+
1063
+ def pop(self):
1064
+ if self:
1065
+ x = next(iter(self))
1066
+ self.remove(x)
1067
+ return x
1068
+ else:
1069
+ raise KeyError
1070
+
1071
+ def remove(self, x):
1072
+ if x not in self:
1073
+ raise KeyError
1074
+ self.discard(x)
1075
+
1076
+ def symmetric_difference_update(self, x):
1077
+ self._inner = self._inner.symmetric_difference(x)
1078
+
1079
+ def update(self, *iterables):
1080
+ for itr in iterables:
1081
+ additions = _force_arg_to_set(itr)
1082
+ self._inner = LazySetCombination(operator.or_, self._inner, additions)
1083
+
1084
+ def __or__(self, x):
1085
+ with NoTracing():
1086
+ if not isinstance(x, AbcSet):
1087
+ return NotImplemented
1088
+ return ShellMutableSet(
1089
+ LazySetCombination(operator.or_, self._inner, _force_arg_to_set(x))
1090
+ )
1091
+
1092
+ __ror__ = __or__
1093
+
1094
+ def __and__(self, x):
1095
+ with NoTracing():
1096
+ if not isinstance(x, AbcSet):
1097
+ return NotImplemented
1098
+ return ShellMutableSet(
1099
+ LazySetCombination(operator.and_, self._inner, _force_arg_to_set(x))
1100
+ )
1101
+
1102
+ __rand__ = __and__
1103
+
1104
+ def __xor__(self, x):
1105
+ with NoTracing():
1106
+ if not isinstance(x, AbcSet):
1107
+ return NotImplemented
1108
+ return ShellMutableSet(
1109
+ LazySetCombination(operator.xor, self._inner, _force_arg_to_set(x))
1110
+ )
1111
+
1112
+ __rxor__ = __xor__
1113
+
1114
+ def __sub__(self, x):
1115
+ with NoTracing():
1116
+ if not isinstance(x, AbcSet):
1117
+ return NotImplemented
1118
+ # TODO: why not lazy set combination here?
1119
+ return ShellMutableSet(
1120
+ LazySetCombination(lambda x, y: (x and not y), self._inner, x)
1121
+ )
1122
+
1123
+ def __rsub__(self, x):
1124
+ with NoTracing():
1125
+ if not isinstance(x, AbcSet):
1126
+ return NotImplemented
1127
+ return ShellMutableSet(
1128
+ LazySetCombination(lambda x, y: (y and not x), self._inner, x)
1129
+ )
1130
+
1131
+ def __ior__(self, x):
1132
+ with NoTracing():
1133
+ if not isinstance(x, AbcSet):
1134
+ return NotImplemented
1135
+ self._inner = LazySetCombination(
1136
+ operator.or_, self._inner, _force_arg_to_set(x)
1137
+ )
1138
+ return self
1139
+
1140
+ def __iand__(self, x):
1141
+ with NoTracing():
1142
+ if not isinstance(x, AbcSet):
1143
+ return NotImplemented
1144
+ self._inner = LazySetCombination(
1145
+ operator.and_, self._inner, _force_arg_to_set(x)
1146
+ )
1147
+ return self
1148
+
1149
+ def __ixor__(self, x):
1150
+ with NoTracing():
1151
+ if not isinstance(x, AbcSet):
1152
+ return NotImplemented
1153
+ self._inner = LazySetCombination(
1154
+ operator.xor, self._inner, _force_arg_to_set(x)
1155
+ )
1156
+ return self
1157
+
1158
+ def __isub__(self, x):
1159
+ with NoTracing():
1160
+ if not isinstance(x, AbcSet):
1161
+ return NotImplemented
1162
+ self._inner = LazySetCombination(
1163
+ lambda x, y: (x and not y), self._inner, _force_arg_to_set(x)
1164
+ )
1165
+ return self