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,113 @@
1
+ """Configure analysis options at different levels."""
2
+
3
+ import importlib.resources
4
+ import inspect
5
+ import re
6
+ import sys
7
+ import tokenize
8
+ from io import StringIO
9
+ from typing import Any, Iterable, Tuple
10
+
11
+ from crosshair.options import AnalysisOptionSet
12
+ from crosshair.util import memo, sourcelines
13
+
14
+ _COMMENT_TOKEN_RE = re.compile(r"^\#\s*crosshair\s*\:\s*(.*?)\s*$")
15
+
16
+
17
+ def get_directives(source_text: str) -> Iterable[Tuple[int, int, str]]:
18
+ r"""
19
+ Extract directive text from source lines.
20
+
21
+ :returns: a list of (line number, column number, directive text) tuples
22
+
23
+ >>> get_directives("pass\n# crosshair: foo=bar")
24
+ [(2, 0, 'foo=bar')]
25
+ """
26
+ ret = []
27
+ tokens = tokenize.generate_tokens(StringIO(source_text).readline)
28
+ # TODO catch tokenize.TokenError ... just in case?
29
+ for toktyp, tokval, begin, _, _ in tokens:
30
+ linenum, colnum = begin
31
+ if toktyp == tokenize.COMMENT:
32
+ directive = _COMMENT_TOKEN_RE.sub(r"\1", tokval)
33
+ if tokval != directive:
34
+ ret.append((linenum, colnum, directive))
35
+ return ret
36
+
37
+
38
+ class InvalidDirective(Exception):
39
+ pass
40
+
41
+
42
+ def parse_directives(
43
+ directive_lines: Iterable[Tuple[int, int, str]],
44
+ ) -> AnalysisOptionSet:
45
+ """
46
+ Parse options from directives in comments.
47
+
48
+ >>> parse_directives([(1, 0, "off")]).enabled
49
+ False
50
+ """
51
+ result = AnalysisOptionSet()
52
+ for lineno, _colno, directive in directive_lines:
53
+ for part in directive.split():
54
+ if part == "on":
55
+ part = "enabled=yes"
56
+ if part == "off":
57
+ part = "enabled=no"
58
+ pair = part.split("=", 2)
59
+ if len(pair) != 2:
60
+ raise InvalidDirective(f'Malformed option: "{part}"', lineno)
61
+ key, strvalue = pair
62
+ if key not in AnalysisOptionSet.directive_fields:
63
+ raise InvalidDirective(f'Unknown option: "{key}"', lineno)
64
+ value = AnalysisOptionSet.parse_field(key, strvalue)
65
+ if value is None:
66
+ raise InvalidDirective(
67
+ f'"{strvalue}" is not a valid "{key}" value', lineno
68
+ )
69
+ if getattr(result, key) is not None:
70
+ raise InvalidDirective(
71
+ f'Option "{key}" is set multiple times at the same scope', lineno
72
+ )
73
+ result = result.overlay(AnalysisOptionSet(**{key: value}))
74
+ return result
75
+
76
+
77
+ @memo
78
+ def collect_options(thing: Any) -> AnalysisOptionSet:
79
+ parent_opts = AnalysisOptionSet()
80
+ is_package = thing.__name__ == getattr(thing, "__package__", None)
81
+ if getattr(thing, "__module__", None):
82
+ parent_opts = collect_options(sys.modules[thing.__module__])
83
+ elif getattr(thing, "__package__", None):
84
+ if is_package:
85
+ parent_pkg, _, _ = thing.__package__.rpartition(".")
86
+ else:
87
+ parent_pkg = thing.__package__
88
+ if parent_pkg:
89
+ parent_opts = collect_options(sys.modules[parent_pkg])
90
+
91
+ source_text: str
92
+ if is_package:
93
+ try:
94
+ if sys.version_info >= (3, 10):
95
+ source_text = (
96
+ importlib.resources.files(thing).joinpath("__init__.py").read_text()
97
+ )
98
+ else:
99
+ source_text = importlib.resources.read_text(thing, "__init__.py")
100
+ except FileNotFoundError:
101
+ source_text = ""
102
+ else:
103
+ _file, _start, lines = sourcelines(thing)
104
+ source_text = "".join(lines)
105
+ directives = get_directives(source_text)
106
+ if inspect.ismodule(thing):
107
+ # Only look at toplevel comments in modules
108
+ # (we don't want to catch directives for functions inside it)
109
+ # TODO: detect directives at other levels like classes etc and warn that they
110
+ # will be ignored.
111
+ directives = [(l, c, t) for (l, c, t) in directives if c == 0]
112
+ my_opts = parse_directives(directives)
113
+ return parent_opts.overlay(my_opts)
@@ -0,0 +1,117 @@
1
+ import importlib
2
+ import inspect
3
+ import sys
4
+ import textwrap
5
+ from pathlib import Path
6
+
7
+ import pytest # type: ignore
8
+
9
+ from crosshair.codeconfig import (
10
+ AnalysisOptionSet,
11
+ InvalidDirective,
12
+ collect_options,
13
+ get_directives,
14
+ parse_directives,
15
+ )
16
+ from crosshair.test_util import simplefs
17
+ from crosshair.util import add_to_pypath
18
+
19
+
20
+ # crosshair: off
21
+ def override_on():
22
+ # crosshair: on
23
+ pass
24
+
25
+
26
+ def timeout_of_10():
27
+ # crosshair: per_condition_timeout=10
28
+ pass
29
+
30
+
31
+ def _example1():
32
+ # crosshair : First comment
33
+ # does not lead with crosshair: not present
34
+ print("# crosshair : this is a string, not a comment")
35
+ pass # crosshair:comment with trailing space
36
+
37
+
38
+ def test_get_directives_example1() -> None:
39
+ lines, _ = inspect.getsourcelines(_example1)
40
+ assert get_directives("".join(lines)) == [
41
+ (2, 4, "First comment"),
42
+ (5, 10, "comment with trailing space"),
43
+ ]
44
+
45
+
46
+ def test_parse_directives() -> None:
47
+ assert parse_directives([(1, 0, "per_condition_timeout=42")]) == AnalysisOptionSet(
48
+ per_condition_timeout=42
49
+ )
50
+ assert parse_directives([(1, 0, "on")]) == AnalysisOptionSet(enabled=True)
51
+ assert parse_directives([(1, 0, "off")]) == AnalysisOptionSet(enabled=False)
52
+ assert parse_directives([(1, 0, "on per_path_timeout=42")]) == AnalysisOptionSet(
53
+ enabled=True, per_path_timeout=42
54
+ )
55
+
56
+
57
+ def test_parse_directive_errors() -> None:
58
+ with pytest.raises(InvalidDirective, match='Malformed option: "noequals"'):
59
+ parse_directives([(1, 0, "noequals")])
60
+ with pytest.raises(InvalidDirective, match='Unknown option: "notafield"'):
61
+ parse_directives([(1, 0, "notafield=42")])
62
+ with pytest.raises(
63
+ InvalidDirective,
64
+ match='"notanumber" is not a valid "per_condition_timeout" value',
65
+ ):
66
+ parse_directives([(1, 0, "per_condition_timeout=notanumber")])
67
+ with pytest.raises(
68
+ InvalidDirective,
69
+ match='Option "enabled" is set multiple times at the same scope',
70
+ ):
71
+ parse_directives([(1, 0, "on off")])
72
+
73
+
74
+ def test_get_directives_multiline_string() -> None:
75
+ # This tests a regression where we'd previously thrown a "EOF in multi-line string"
76
+ # TokenError.
77
+ foo = '''"""
78
+
79
+ """
80
+ '''
81
+ assert list(get_directives(foo)) == []
82
+
83
+
84
+ def test_collection_options() -> None:
85
+ this_module = sys.modules[__name__]
86
+ assert collect_options(this_module) == AnalysisOptionSet(enabled=False)
87
+ assert collect_options(override_on) == AnalysisOptionSet(enabled=True)
88
+ assert collect_options(timeout_of_10) == AnalysisOptionSet(
89
+ enabled=False, per_condition_timeout=10
90
+ )
91
+
92
+
93
+ DIRECTIVES_TREE = {
94
+ "pkg1": {
95
+ "__init__.py": textwrap.dedent(
96
+ """\
97
+ # crosshair: off
98
+ # crosshair: per_condition_timeout=42
99
+ """
100
+ ),
101
+ "pkg2": {
102
+ "pkg3": {
103
+ "__init__.py": "# crosshair: max_iterations=5",
104
+ "mod.py": "# crosshair: on",
105
+ }
106
+ },
107
+ }
108
+ }
109
+
110
+
111
+ def test_package_directives(tmp_path: Path):
112
+ simplefs(tmp_path, DIRECTIVES_TREE)
113
+ with add_to_pypath(tmp_path):
114
+ innermod = importlib.import_module("pkg1.pkg2.pkg3.mod")
115
+ assert collect_options(innermod) == AnalysisOptionSet(
116
+ enabled=True, max_iterations=5, per_condition_timeout=42
117
+ )