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,86 @@
1
+ import codecs
2
+
3
+ from crosshair import NoTracing, register_patch
4
+ from crosshair.core import class_with_realized_methods, realize, with_realized_args
5
+ from crosshair.libimpl.encodings import codec_search
6
+ from crosshair.util import is_iterable
7
+
8
+
9
+ class RealizingCodecInfo(codecs.CodecInfo):
10
+ def __new__(cls, c: codecs.CodecInfo):
11
+ encode = with_realized_args(c.encode)
12
+ decode = with_realized_args(c.decode)
13
+ streamreader = class_with_realized_methods(c.streamreader)
14
+ streamwriter = class_with_realized_methods(c.streamwriter)
15
+ incrementaldecoder = class_with_realized_methods(c.incrementaldecoder)
16
+ incrementalencoder = class_with_realized_methods(c.incrementalencoder)
17
+ return codecs.CodecInfo(
18
+ encode,
19
+ decode,
20
+ streamreader=streamreader,
21
+ streamwriter=streamwriter,
22
+ incrementalencoder=incrementalencoder,
23
+ incrementaldecoder=incrementaldecoder,
24
+ name=c.name,
25
+ )
26
+
27
+
28
+ def _decode(obj, encoding="utf-8", errors="strict"):
29
+ errors = realize(errors)
30
+ (out, _len_consumed) = _getdecoder(encoding)(obj, errors)
31
+ return out
32
+
33
+
34
+ def _encode(obj, encoding="utf-8", errors="strict"):
35
+ with NoTracing():
36
+ errors = realize(errors)
37
+ if "\x00" in errors:
38
+ raise ValueError
39
+ (out, _len_consumed) = _getencoder(encoding)(obj, errors)
40
+ return out
41
+
42
+
43
+ def _getencoder(encoding):
44
+ return _lookup(encoding).encode
45
+
46
+
47
+ def _getdecoder(encoding):
48
+ return _lookup(encoding).decode
49
+
50
+
51
+ def _getincrementaldecoder(encoding):
52
+ return _lookup(encoding).incrementaldecoder
53
+
54
+
55
+ def _getincrementalencoder(encoding):
56
+ return _lookup(encoding).incrementalencoder
57
+
58
+
59
+ def _getreader(encoding):
60
+ return _lookup(encoding).streamreader
61
+
62
+
63
+ def _getwriter(encoding):
64
+ return _lookup(encoding).streamwriter
65
+
66
+
67
+ def _lookup(encoding: str) -> codecs.CodecInfo:
68
+ with NoTracing():
69
+ encoding = realize(encoding)
70
+ try:
71
+ return codecs.lookup("crosshair_" + encoding)
72
+ except LookupError:
73
+ return RealizingCodecInfo(codecs.lookup(encoding))
74
+
75
+
76
+ def make_registrations() -> None:
77
+ codecs.register(codec_search)
78
+ register_patch(codecs.decode, _decode)
79
+ register_patch(codecs.getencoder, _getencoder)
80
+ register_patch(codecs.getdecoder, _getdecoder)
81
+ register_patch(codecs.getincrementalencoder, _getincrementalencoder)
82
+ register_patch(codecs.getincrementaldecoder, _getincrementaldecoder)
83
+ register_patch(codecs.getreader, _getreader)
84
+ register_patch(codecs.getwriter, _getwriter)
85
+ register_patch(codecs.encode, _encode)
86
+ register_patch(codecs.lookup, _lookup)
@@ -0,0 +1,86 @@
1
+ import codecs
2
+ import io
3
+ import sys
4
+
5
+ import pytest
6
+
7
+ from crosshair.core import proxy_for_type
8
+ from crosshair.core_and_libs import ResumedTracing, standalone_statespace
9
+ from crosshair.libimpl.builtinslib import LazyIntSymbolicStr, SymbolicBytes, SymbolicInt
10
+ from crosshair.options import AnalysisOptionSet
11
+ from crosshair.statespace import POST_FAIL, MessageType
12
+ from crosshair.test_util import check_states
13
+
14
+
15
+ def test_encode_strict(space):
16
+ with ResumedTracing():
17
+ with pytest.raises(UnicodeError):
18
+ codecs.encode("Â", "ascii")
19
+
20
+
21
+ def test_encode_utf8_literal(space):
22
+ with ResumedTracing():
23
+ assert codecs.encode("Â", "utf-8") == b"\xc3\x82"
24
+
25
+
26
+ def test_encode_utf8_symbolic_char(space):
27
+ cp = SymbolicInt("cp")
28
+ with ResumedTracing():
29
+ space.add(cp >= ord("a"))
30
+ space.add(cp <= ord("z"))
31
+ encoded = codecs.encode(chr(cp), "utf-8")
32
+ assert isinstance(encoded, SymbolicBytes)
33
+ byte_value = encoded[0]
34
+ with ResumedTracing():
35
+ assert space.is_possible(byte_value == ord("a"))
36
+ assert space.is_possible(byte_value == ord("b"))
37
+
38
+
39
+ def test_decode_utf8_symbolic_char(space):
40
+ cp = SymbolicInt("cp")
41
+ with ResumedTracing():
42
+ space.add(cp >= ord("a"))
43
+ space.add(cp <= ord("z"))
44
+ decoded = codecs.decode(SymbolicBytes([cp]), "utf-8")
45
+ assert isinstance(decoded, LazyIntSymbolicStr)
46
+ with ResumedTracing():
47
+ assert space.is_possible(decoded._codepoints[0] == ord("a"))
48
+ assert space.is_possible(decoded._codepoints[0] == ord("b"))
49
+
50
+
51
+ def test_unsupported_codec_encode(space):
52
+ s = proxy_for_type(str, "s")
53
+ with ResumedTracing():
54
+ s.encode("cp858")
55
+
56
+
57
+ def test_unsupported_codec_streamwriter(space):
58
+ s = proxy_for_type(str, "s")
59
+ buf = bytearray()
60
+ with ResumedTracing():
61
+ codecs.getwriter("cp858")(io.BytesIO(buf)).write(s)
62
+
63
+
64
+ @pytest.mark.xfail(reason="not yet implemented")
65
+ def test_supported_codec_streamwriter(space):
66
+ s = proxy_for_type(str, "s")
67
+ with ResumedTracing():
68
+ space.add(len(s) == 1)
69
+ buf = bytearray()
70
+ codecs.getwriter("ascii")(io.BytesIO(buf)).write(s)
71
+ space.is_possible(buf[0] == ord("x"))
72
+
73
+
74
+ @pytest.mark.skipif(
75
+ sys.version_info >= (3, 13),
76
+ reason="Need to intercept UnicodeDecodeError.str in 3.13+",
77
+ )
78
+ def test_decode_e2e():
79
+ def f(byts: bytes) -> str:
80
+ """
81
+ post: _ != 'Â'
82
+ raises: UnicodeDecodeError
83
+ """
84
+ return byts.decode("utf-8", errors="strict")
85
+
86
+ check_states(f, POST_FAIL)
@@ -0,0 +1,264 @@
1
+ import collections
2
+ import sys
3
+ from typing import (
4
+ Any,
5
+ Callable,
6
+ Dict,
7
+ Generic,
8
+ Iterable,
9
+ KeysView,
10
+ List,
11
+ Optional,
12
+ Set,
13
+ Tuple,
14
+ TypeVar,
15
+ Union,
16
+ ValuesView,
17
+ )
18
+
19
+ from crosshair import register_type
20
+ from crosshair.core import realize
21
+ from crosshair.tracers import NoTracing, ResumedTracing
22
+ from crosshair.util import CrossHairValue, is_iterable
23
+
24
+ T = TypeVar("T")
25
+
26
+
27
+ class ListBasedDeque(collections.abc.MutableSequence, CrossHairValue, Generic[T]):
28
+ def __init__(self, contents: List[T], maxlen: Optional[int] = None):
29
+ self._contents = contents
30
+ self._maxlen = maxlen
31
+
32
+ def __ch_pytype__(self):
33
+ return collections.deque
34
+
35
+ def __ch_realize__(self):
36
+ with ResumedTracing():
37
+ return collections.deque(self._contents, maxlen=realize(self._maxlen))
38
+
39
+ def __add__(self, other):
40
+ if not isinstance(other, collections.deque):
41
+ raise TypeError
42
+ ret = self.copy()
43
+ ret.extend(other)
44
+ return ret
45
+
46
+ def __eq__(self, other: object) -> bool:
47
+ with NoTracing():
48
+ mycontents = self._contents
49
+ if isinstance(other, ListBasedDeque):
50
+ with ResumedTracing():
51
+ return mycontents == other._contents
52
+ elif isinstance(other, collections.deque):
53
+ with ResumedTracing():
54
+ return mycontents == list(other)
55
+ return False
56
+
57
+ def __len__(self) -> int:
58
+ return len(self._contents)
59
+
60
+ def __mul__(self, count):
61
+ if not isinstance(count, int):
62
+ raise TypeError
63
+ ret = ListBasedDeque([], self._maxlen)
64
+ for _ in range(count):
65
+ ret.extend(self._contents)
66
+ return ret
67
+
68
+ def __repr__(self) -> str:
69
+ return repr(realize(self))
70
+
71
+ def __getitem__(self, k):
72
+ if isinstance(k, slice): # slicing isn't supported on deque
73
+ raise TypeError
74
+ return self._contents.__getitem__(k)
75
+
76
+ def __setitem__(self, k, v):
77
+ if isinstance(k, slice): # slicing isn't supported on deque
78
+ raise TypeError
79
+ return self._contents.__setitem__(k, v)
80
+
81
+ def __delitem__(self, k):
82
+ if isinstance(k, slice): # slicing isn't supported on deque
83
+ raise TypeError
84
+ return self._contents.__delitem__(k)
85
+
86
+ def _has_room(self) -> bool:
87
+ maxlen = self._maxlen
88
+ return maxlen is None or len(self._contents) < maxlen
89
+
90
+ def appendleft(self, item: T) -> None:
91
+ if self._has_room():
92
+ self._contents = [item] + self._contents
93
+ else:
94
+ del self._contents[-1]
95
+ self._contents = [item] + self._contents
96
+
97
+ def append(self, item: T) -> None:
98
+ if self._has_room():
99
+ self._contents = self._contents + [item]
100
+ else:
101
+ del self._contents[0]
102
+ self._contents = self._contents + [item]
103
+
104
+ def clear(self) -> None:
105
+ self._contents = []
106
+
107
+ def copy(self):
108
+ return ListBasedDeque(self._contents[:], self._maxlen)
109
+
110
+ def count(self, item: T) -> int:
111
+ c = 0
112
+ for i in self._contents:
113
+ if i == item:
114
+ c += 1
115
+ return c
116
+
117
+ def extend(self, items: Iterable[T]) -> None:
118
+ if not is_iterable(items):
119
+ raise TypeError
120
+ self._contents += list(items)
121
+
122
+ def extendleft(self, items: Iterable[T]) -> None:
123
+ if not is_iterable(items):
124
+ raise TypeError
125
+ prefix = list(items)
126
+ prefix.reverse()
127
+ self._contents = prefix + self._contents
128
+
129
+ if sys.version_info >= (3, 14):
130
+
131
+ def index(self, item: T, *bounds) -> int:
132
+ try:
133
+ return self._contents.index(item, *bounds)
134
+ except ValueError as exc:
135
+ exc.args = ("deque.index(x): x not in deque",)
136
+ raise
137
+
138
+ else:
139
+
140
+ def index(self, item: T, *bounds) -> int:
141
+ return self._contents.index(item, *bounds)
142
+
143
+ def insert(self, index: int, item: T) -> None:
144
+ self._contents.insert(index, item)
145
+
146
+ def pop(self) -> T: # type: ignore
147
+ x = self._contents[-1]
148
+ del self._contents[-1]
149
+ return x
150
+
151
+ def popleft(self) -> T:
152
+ x = self._contents[0]
153
+ del self._contents[0]
154
+ return x
155
+
156
+ def remove(self, item: T) -> None:
157
+ self._contents.remove(item)
158
+
159
+ def reverse(self) -> None:
160
+ self._contents.reverse()
161
+
162
+ def rotate(self, n: int = 1) -> None:
163
+ if not self._contents or n % len(self._contents) == 0:
164
+ return
165
+ self._contents = (
166
+ self._contents[-n % len(self._contents) :]
167
+ + self._contents[: -n % len(self._contents)]
168
+ )
169
+
170
+ def maxlen(self) -> Optional[int]:
171
+ return self._maxlen
172
+
173
+
174
+ class PureDefaultDict(collections.abc.MutableMapping, CrossHairValue):
175
+ def __init__(self, factory, internal):
176
+ self.default_factory = factory
177
+ self._internal = internal
178
+
179
+ def __ch_pytype__(self):
180
+ return collections.defaultdict
181
+
182
+ def __ch_realize__(self):
183
+ with ResumedTracing():
184
+ return collections.defaultdict(self.default_factory, self._internal)
185
+
186
+ def __getitem__(self, k):
187
+ try:
188
+ return self._internal.__getitem__(k)
189
+ except KeyError:
190
+ return self.__missing__(k)
191
+
192
+ def __setitem__(self, k, v):
193
+ return self._internal.__setitem__(k, v)
194
+
195
+ def __delitem__(self, k):
196
+ return self._internal.__delitem__(k)
197
+
198
+ def __iter__(self):
199
+ return self._internal.__iter__()
200
+
201
+ def __len__(self):
202
+ return self._internal.__len__()
203
+
204
+ def __repr__(self):
205
+ return "defaultdict({!r}, {!r})".format(self.default_factory, self._internal)
206
+
207
+ def __missing__(self, k):
208
+ if self.default_factory is None:
209
+ raise KeyError(k)
210
+ value = self.default_factory()
211
+ self._internal[k] = value
212
+ return value
213
+
214
+
215
+ def make_registrations():
216
+ register_type(collections.defaultdict, lambda p, kt=Any, vt=Any: PureDefaultDict(p(Optional[Callable[[], vt]], "_initalizer"), p(Dict[kt, vt]))) # type: ignore
217
+ register_type(collections.ChainMap, lambda p, kt=Any, vt=Any: collections.ChainMap(*p(Tuple[Dict[kt, vt], ...]))) # type: ignore
218
+ register_type(collections.abc.Mapping, lambda p, kt=Any, vt=Any: p(Dict[kt, vt])) # type: ignore
219
+ register_type(collections.abc.MutableMapping, lambda p, kt=Any, vt=Any: p(Dict[kt, vt])) # type: ignore
220
+ register_type(collections.OrderedDict, lambda p, kt=Any, vt=Any: collections.OrderedDict(p(Dict[kt, vt]))) # type: ignore
221
+ # TODO: This implementation of Counter probably over-realizes the symbolic map it is given:
222
+ register_type(collections.Counter, lambda p, t=Any: collections.Counter(p(Dict[t, int]))) # type: ignore
223
+ # TODO: MappingView is missing
224
+ register_type(
225
+ collections.abc.ItemsView,
226
+ lambda p, k=Any, v=Any: p(Dict.__getitem__((k, v))).items(),
227
+ )
228
+ register_type(
229
+ collections.abc.MappingView,
230
+ lambda p, t=Any: p(
231
+ Union[
232
+ KeysView.__getitem__((t,)),
233
+ ValuesView.__getitem__((t,)),
234
+ ]
235
+ ),
236
+ )
237
+ register_type(
238
+ collections.abc.KeysView, lambda p, t=Any: p(Dict.__getitem__((t, Any))).keys()
239
+ )
240
+ register_type(
241
+ collections.abc.ValuesView,
242
+ lambda p, t=Any: p(Dict.__getitem__((Any, t))).values(),
243
+ )
244
+
245
+ register_type(collections.abc.Container, lambda p, t=Any: p(Tuple[t, ...]))
246
+ register_type(collections.abc.Collection, lambda p, t=Any: p(Tuple[t, ...]))
247
+
248
+ register_type(collections.deque, lambda p, t=Any: ListBasedDeque(p(List[t]))) # type: ignore
249
+
250
+ register_type(collections.abc.Iterable, lambda p, t=Any: p(Tuple[t, ...]))
251
+ register_type(collections.abc.Iterator, lambda p, t=Any: iter(p(Iterable[t]))) # type: ignore
252
+
253
+ register_type(collections.abc.MutableSequence, lambda p, t=Any: p(List[t])) # type: ignore
254
+ register_type(collections.abc.Reversible, lambda p, t=Any: p(Tuple[t, ...]))
255
+ register_type(collections.abc.Sequence, lambda p, t=Any: p(Tuple[t, ...]))
256
+ register_type(collections.abc.Sized, lambda p, t=Any: p(Tuple[t, ...]))
257
+
258
+ register_type(collections.abc.MutableSet, lambda p, t=Any: p(Set[t])) # type: ignore
259
+
260
+ if sys.version_info < (3, 14):
261
+ register_type(collections.abc.ByteString, lambda p: p(bytes))
262
+ if sys.version_info >= (3, 12):
263
+ register_type(collections.abc.Buffer, lambda p: p(bytes))
264
+ register_type(collections.abc.Hashable, lambda p: p(int))
@@ -0,0 +1,252 @@
1
+ import sys
2
+ from typing import DefaultDict, Deque, Optional, Sequence
3
+
4
+ import pytest # type: ignore
5
+
6
+ from crosshair.core_and_libs import MessageType, analyze_function, run_checkables
7
+ from crosshair.options import AnalysisOptionSet
8
+ from crosshair.test_util import ResultComparison, compare_results
9
+
10
+ # deque
11
+
12
+
13
+ def check_deque_append(queue: Deque[int], item: int):
14
+ """post: _"""
15
+
16
+ def checker(q, i):
17
+ q.append(i)
18
+ return q
19
+
20
+ return compare_results(checker, queue, item)
21
+
22
+
23
+ def check_deque_appendleft(queue: Deque[int], item: int):
24
+ """post: _"""
25
+
26
+ def checker(q, i):
27
+ q.appendleft(i)
28
+ return q
29
+
30
+ return compare_results(checker, queue, item)
31
+
32
+
33
+ def check_deque_copy(queue: Deque[int]):
34
+ """post: _"""
35
+ return compare_results(lambda d: d.copy(), queue)
36
+
37
+
38
+ def check_deque_count(queue: Deque[int], item: int):
39
+ """post: _"""
40
+ return compare_results(lambda d, i: d.count(i), queue, item)
41
+
42
+
43
+ def check_deque_extend(queue: Deque[int], items: Sequence[int]):
44
+ """post: _"""
45
+
46
+ def checker(q, i):
47
+ q.extend(i)
48
+ return q
49
+
50
+ return compare_results(checker, queue, items)
51
+
52
+
53
+ def check_deque_extendleft(queue: Deque[int], items: Sequence[int]):
54
+ """post: _"""
55
+
56
+ def checker(q, i):
57
+ q.extendleft(i)
58
+ return q
59
+
60
+ return compare_results(checker, queue, items)
61
+
62
+
63
+ def check_deque_index(
64
+ queue: Deque[int], item: int, start: Optional[int], end: Optional[int]
65
+ ):
66
+ """post: _"""
67
+ return compare_results(lambda q, i, s, e: q.index(i, s, e), queue, item, start, end)
68
+
69
+
70
+ def check_deque_insert(queue: Deque[int], position: int, item: int):
71
+ """post: _"""
72
+
73
+ def checker(q, p, i):
74
+ q.insert(p, i)
75
+ return q
76
+
77
+ return compare_results(checker, queue, position, item)
78
+
79
+
80
+ def check_deque_pop(queue: Deque[int]):
81
+ """post: _"""
82
+
83
+ def checker(q):
84
+ item = q.pop()
85
+ return (item, q)
86
+
87
+ return compare_results(checker, queue)
88
+
89
+
90
+ def check_deque_popleft(queue: Deque[int]):
91
+ """post: _"""
92
+
93
+ def checker(q):
94
+ item = q.popleft()
95
+ return item
96
+
97
+ return compare_results(checker, queue)
98
+
99
+
100
+ def check_deque_remove(queue: Deque[int], item: int):
101
+ """post: _"""
102
+
103
+ def checker(q, n):
104
+ q.remove(n)
105
+ return q
106
+
107
+ return compare_results(checker, queue, item)
108
+
109
+
110
+ def check_deque_reverse(queue: Deque[int]):
111
+ """post: _"""
112
+
113
+ def checker(q):
114
+ q.reverse()
115
+ return q
116
+
117
+ return compare_results(checker, queue)
118
+
119
+
120
+ def check_deque_rotate(queue: Deque[int], amount: int):
121
+ """post: _"""
122
+
123
+ def checker(q, n):
124
+ q.rotate(n)
125
+ return q
126
+
127
+ return compare_results(checker, queue, amount)
128
+
129
+
130
+ def check_deque_maxlen(queue: Deque[int]):
131
+ return compare_results(lambda q: q.maxlen, queue)
132
+
133
+
134
+ def check_deque_eq(queue: Deque[int]):
135
+ return compare_results(lambda q: q, queue)
136
+
137
+
138
+ def check_deque_getitem(queue: Deque[int], idx: int):
139
+ """post: _"""
140
+ return compare_results(lambda q, i: q[i], queue, idx)
141
+
142
+
143
+ def check_deque_contains(queue: Deque[int], item: int):
144
+ """post: _"""
145
+ return compare_results(lambda q, i: i in q, queue, item)
146
+
147
+
148
+ def check_deque_add(queue: Deque[int], items: Deque[int]):
149
+ """post: _"""
150
+ return compare_results(lambda q, i: q + i, queue, items)
151
+
152
+
153
+ def check_deque_mul(queue: Deque[int], count: int):
154
+ """post: _"""
155
+ return compare_results(lambda q, i: q * i, queue, count)
156
+
157
+
158
+ # defaultdict
159
+
160
+
161
+ def check_defaultdict_getitem(container: DefaultDict[int, int], key: int):
162
+ """post: _"""
163
+ return compare_results(lambda d, k: d[k], container, key)
164
+
165
+
166
+ def check_defaultdict_delitem(container: DefaultDict[int, int], key: int):
167
+ """post: _"""
168
+
169
+ def checker(d, k):
170
+ del d[k]
171
+ return d
172
+
173
+ return compare_results(checker, container, key)
174
+
175
+
176
+ def check_defaultdict_inplace_mutation(container: DefaultDict[int, int]):
177
+ """post: _"""
178
+
179
+ def setter(c):
180
+ if c:
181
+ c[0] &= 42
182
+ return c
183
+
184
+ return compare_results(setter, container)
185
+
186
+
187
+ def check_defaultdict_iter(dictionary: DefaultDict[int, int]) -> ResultComparison:
188
+ """post: _"""
189
+ return compare_results(lambda d: list(d), dictionary)
190
+
191
+
192
+ def check_defaultdict_clear(dictionary: DefaultDict[int, int]) -> ResultComparison:
193
+ """post: _"""
194
+
195
+ def checker(d):
196
+ d.clear()
197
+ return d
198
+
199
+ return compare_results(checker, dictionary)
200
+
201
+
202
+ def check_defaultdict_pop(dictionary: DefaultDict[int, int]) -> ResultComparison:
203
+ """post: _"""
204
+
205
+ def checker(d):
206
+ x = d.pop()
207
+ return (x, d)
208
+
209
+ return compare_results(checker, dictionary)
210
+
211
+
212
+ def check_defaultdict_popitem(
213
+ dictionary: DefaultDict[int, int], key: int
214
+ ) -> ResultComparison:
215
+ """post: _"""
216
+
217
+ def checker(d, k):
218
+ x = d.popitem(k)
219
+ return (x, d)
220
+
221
+ return compare_results(checker, dictionary)
222
+
223
+
224
+ def check_defaultdict_update(
225
+ left: DefaultDict[int, int], right: DefaultDict[int, int]
226
+ ) -> ResultComparison:
227
+ """post: _"""
228
+
229
+ def checker(d1, d2):
230
+ d1.update(d2)
231
+ return d1
232
+
233
+ return compare_results(checker, left, right)
234
+
235
+
236
+ def check_defaultdict_values(dictionary: DefaultDict[int, int]) -> ResultComparison:
237
+ """post: _"""
238
+ # TODO: value views compare false even with new views from the same dict.
239
+ # Ensure we match this behavior.
240
+ return compare_results(lambda d: list(d.values()), dictionary)
241
+
242
+
243
+ # This is the only real test definition.
244
+ # It runs crosshair on each of the "check" functions defined above.
245
+ @pytest.mark.parametrize("fn_name", [fn for fn in dir() if fn.startswith("check_")])
246
+ def test_builtin(fn_name: str) -> None:
247
+ opts = AnalysisOptionSet(max_iterations=7)
248
+ this_module = sys.modules[__name__]
249
+ fn = getattr(this_module, fn_name)
250
+ messages = run_checkables(analyze_function(fn, opts))
251
+ errors = [m for m in messages if m.state > MessageType.PRE_UNSAT]
252
+ assert errors == []