crosshair-tool 0.0.94__tar.gz → 0.0.96__tar.gz

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.

Potentially problematic release.


This version of crosshair-tool might be problematic. Click here for more details.

Files changed (182) hide show
  1. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/PKG-INFO +1 -1
  2. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/__init__.py +1 -1
  3. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/condition_parser_test.py +0 -2
  4. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/core.py +2 -1
  5. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/core_test.py +2 -3
  6. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/diff_behavior_test.py +0 -2
  7. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/builtinslib.py +65 -28
  8. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/builtinslib_ch_test.py +12 -2
  9. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/builtinslib_test.py +36 -0
  10. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/collectionslib_test.py +4 -4
  11. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/functoolslib.py +8 -2
  12. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/functoolslib_test.py +22 -6
  13. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/objectproxy.py +38 -13
  14. crosshair_tool-0.0.96/crosshair/objectproxy_test.py +41 -0
  15. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/opcode_intercept.py +9 -17
  16. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/path_cover.py +5 -1
  17. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/pathing_oracle.py +41 -4
  18. crosshair_tool-0.0.96/crosshair/pathing_oracle_test.py +21 -0
  19. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/statespace.py +73 -18
  20. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/statespace_test.py +16 -0
  21. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair_tool.egg-info/PKG-INFO +1 -1
  22. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair_tool.egg-info/SOURCES.txt +1 -0
  23. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/setup.py +1 -1
  24. crosshair_tool-0.0.94/crosshair/objectproxy_test.py +0 -23
  25. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/LICENSE +0 -0
  26. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/README.md +0 -0
  27. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/__main__.py +0 -0
  28. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/_mark_stacks.h +0 -0
  29. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/_preliminaries_test.py +0 -0
  30. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/_tracers.c +0 -0
  31. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/_tracers.h +0 -0
  32. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/_tracers_pycompat.h +0 -0
  33. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/_tracers_test.py +0 -0
  34. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/abcstring.py +0 -0
  35. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/auditwall.py +0 -0
  36. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/auditwall_test.py +0 -0
  37. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/codeconfig.py +0 -0
  38. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/codeconfig_test.py +0 -0
  39. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/condition_parser.py +0 -0
  40. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/conftest.py +0 -0
  41. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/copyext.py +0 -0
  42. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/copyext_test.py +0 -0
  43. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/core_and_libs.py +0 -0
  44. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/core_regestered_types_test.py +0 -0
  45. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/diff_behavior.py +0 -0
  46. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/dynamic_typing.py +0 -0
  47. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/dynamic_typing_test.py +0 -0
  48. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/enforce.py +0 -0
  49. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/enforce_test.py +0 -0
  50. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/PEP316/__init__.py +0 -0
  51. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/PEP316/bugs_detected/__init__.py +0 -0
  52. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/PEP316/bugs_detected/getattr_magic.py +0 -0
  53. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/PEP316/bugs_detected/hash_consistent_with_equals.py +0 -0
  54. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/PEP316/bugs_detected/shopping_cart.py +0 -0
  55. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/PEP316/bugs_detected/showcase.py +0 -0
  56. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/PEP316/correct_code/__init__.py +0 -0
  57. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/PEP316/correct_code/arith.py +0 -0
  58. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/PEP316/correct_code/chess.py +0 -0
  59. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/PEP316/correct_code/nesting_inference.py +0 -0
  60. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/PEP316/correct_code/numpy_examples.py +0 -0
  61. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/PEP316/correct_code/rolling_average.py +0 -0
  62. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/PEP316/correct_code/showcase.py +0 -0
  63. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/__init__.py +0 -0
  64. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/check_examples_test.py +0 -0
  65. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/deal/__init__.py +0 -0
  66. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/icontract/__init__.py +0 -0
  67. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/icontract/bugs_detected/__init__.py +0 -0
  68. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/icontract/bugs_detected/showcase.py +0 -0
  69. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/icontract/bugs_detected/wrong_sign.py +0 -0
  70. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/icontract/correct_code/__init__.py +0 -0
  71. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/icontract/correct_code/arith.py +0 -0
  72. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/examples/icontract/correct_code/showcase.py +0 -0
  73. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/fnutil.py +0 -0
  74. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/fnutil_test.py +0 -0
  75. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/fuzz_core_test.py +0 -0
  76. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/__init__.py +0 -0
  77. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/arraylib.py +0 -0
  78. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/binascii_ch_test.py +0 -0
  79. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/binascii_test.py +0 -0
  80. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/binasciilib.py +0 -0
  81. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/bisectlib_test.py +0 -0
  82. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/codecslib.py +0 -0
  83. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/codecslib_test.py +0 -0
  84. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/collectionslib.py +0 -0
  85. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/collectionslib_ch_test.py +0 -0
  86. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/copylib.py +0 -0
  87. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/copylib_test.py +0 -0
  88. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/datetimelib.py +0 -0
  89. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/datetimelib_ch_test.py +0 -0
  90. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/datetimelib_test.py +0 -0
  91. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/decimallib.py +0 -0
  92. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/decimallib_ch_test.py +0 -0
  93. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/decimallib_test.py +0 -0
  94. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/encodings/__init__.py +0 -0
  95. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/encodings/_encutil.py +0 -0
  96. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/encodings/ascii.py +0 -0
  97. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/encodings/latin_1.py +0 -0
  98. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/encodings/utf_8.py +0 -0
  99. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/encodings_ch_test.py +0 -0
  100. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/fractionlib.py +0 -0
  101. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/fractionlib_test.py +0 -0
  102. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/hashliblib.py +0 -0
  103. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/hashliblib_test.py +0 -0
  104. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/heapqlib.py +0 -0
  105. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/heapqlib_test.py +0 -0
  106. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/importliblib.py +0 -0
  107. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/importliblib_test.py +0 -0
  108. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/iolib.py +0 -0
  109. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/iolib_ch_test.py +0 -0
  110. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/iolib_test.py +0 -0
  111. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/ipaddresslib.py +0 -0
  112. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/itertoolslib.py +0 -0
  113. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/itertoolslib_test.py +0 -0
  114. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/jsonlib.py +0 -0
  115. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/jsonlib_ch_test.py +0 -0
  116. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/jsonlib_test.py +0 -0
  117. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/mathlib.py +0 -0
  118. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/mathlib_ch_test.py +0 -0
  119. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/mathlib_test.py +0 -0
  120. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/oslib.py +0 -0
  121. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/pathliblib_test.py +0 -0
  122. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/randomlib.py +0 -0
  123. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/randomlib_test.py +0 -0
  124. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/relib.py +0 -0
  125. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/relib_ch_test.py +0 -0
  126. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/relib_test.py +0 -0
  127. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/timelib.py +0 -0
  128. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/timelib_test.py +0 -0
  129. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/typeslib.py +0 -0
  130. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/typeslib_test.py +0 -0
  131. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/unicodedatalib.py +0 -0
  132. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/unicodedatalib_test.py +0 -0
  133. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/urlliblib.py +0 -0
  134. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/urlliblib_test.py +0 -0
  135. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/weakreflib.py +0 -0
  136. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/weakreflib_test.py +0 -0
  137. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/zliblib.py +0 -0
  138. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/libimpl/zliblib_test.py +0 -0
  139. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/lsp_server.py +0 -0
  140. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/lsp_server_test.py +0 -0
  141. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/main.py +0 -0
  142. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/main_test.py +0 -0
  143. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/opcode_intercept_test.py +0 -0
  144. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/options.py +0 -0
  145. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/options_test.py +0 -0
  146. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/patch_equivalence_test.py +0 -0
  147. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/path_cover_test.py +0 -0
  148. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/path_search.py +0 -0
  149. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/path_search_test.py +0 -0
  150. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/pure_importer.py +0 -0
  151. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/pure_importer_test.py +0 -0
  152. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/py.typed +0 -0
  153. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/register_contract.py +0 -0
  154. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/register_contract_test.py +0 -0
  155. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/simplestructs.py +0 -0
  156. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/simplestructs_test.py +0 -0
  157. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/smtlib.py +0 -0
  158. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/smtlib_test.py +0 -0
  159. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/stubs_parser.py +0 -0
  160. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/stubs_parser_test.py +0 -0
  161. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/test_util.py +0 -0
  162. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/test_util_test.py +0 -0
  163. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/tools/__init__.py +0 -0
  164. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/tools/check_help_in_doc.py +0 -0
  165. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/tools/check_init_and_setup_coincide.py +0 -0
  166. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/tools/generate_demo_table.py +0 -0
  167. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/tracers.py +0 -0
  168. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/tracers_test.py +0 -0
  169. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/type_repo.py +0 -0
  170. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/unicode_categories.py +0 -0
  171. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/unicode_categories_test.py +0 -0
  172. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/util.py +0 -0
  173. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/util_test.py +0 -0
  174. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/watcher.py +0 -0
  175. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/watcher_test.py +0 -0
  176. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/z3util.py +0 -0
  177. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair/z3util_test.py +0 -0
  178. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair_tool.egg-info/dependency_links.txt +0 -0
  179. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair_tool.egg-info/entry_points.txt +0 -0
  180. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair_tool.egg-info/requires.txt +0 -0
  181. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/crosshair_tool.egg-info/top_level.txt +0 -0
  182. {crosshair_tool-0.0.94 → crosshair_tool-0.0.96}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: crosshair-tool
3
- Version: 0.0.94
3
+ Version: 0.0.96
4
4
  Summary: Analyze Python code for correctness using symbolic execution.
5
5
  Home-page: https://github.com/pschanely/CrossHair
6
6
  Author: Phillip Schanely
@@ -15,7 +15,7 @@ from crosshair.statespace import StateSpace
15
15
  from crosshair.tracers import NoTracing, ResumedTracing
16
16
  from crosshair.util import IgnoreAttempt, debug
17
17
 
18
- __version__ = "0.0.94" # Do not forget to update in setup.py!
18
+ __version__ = "0.0.96" # Do not forget to update in setup.py!
19
19
  __author__ = "Phillip Schanely"
20
20
  __license__ = "MIT"
21
21
  __status__ = "Alpha"
@@ -1,8 +1,6 @@
1
1
  import inspect
2
2
  import json
3
3
  import sys
4
- import textwrap
5
- import unittest
6
4
  from typing import List
7
5
 
8
6
  import pytest
@@ -377,7 +377,8 @@ def with_symbolic_self(symbolic_cls: Type, fn: Callable):
377
377
  elif any(isinstance(a, CrossHairValue) for a in args) or (
378
378
  kwargs and any(isinstance(a, CrossHairValue) for a in kwargs.values())
379
379
  ):
380
- self = symbolic_cls._smt_promote_literal(self)
380
+ # NOTE: _ch_create_from_literal is suppoerted for very few types right now
381
+ self = symbolic_cls._ch_create_from_literal(self)
381
382
  target_fn = getattr(symbolic_cls, fn.__name__)
382
383
  else:
383
384
  args = map(realize, args)
@@ -5,7 +5,6 @@ import re
5
5
  import sys
6
6
  import time
7
7
  from typing import *
8
- from unittest import skipIf
9
8
 
10
9
  import pytest # type: ignore
11
10
 
@@ -736,7 +735,7 @@ def test_newtype() -> None:
736
735
  assert isinstance(x, SymbolicInt)
737
736
 
738
737
 
739
- @skipIf(sys.version_info < (3, 12), "type statements added in 3.12")
738
+ @pytest.mark.skipif(sys.version_info < (3, 12), reason="type statements added in 3.12")
740
739
  def test_type_statement() -> None:
741
740
  env: dict[str, Any] = {}
742
741
  exec("type MyIntNew = int\n", env)
@@ -747,7 +746,7 @@ def test_type_statement() -> None:
747
746
  assert isinstance(x, SymbolicInt)
748
747
 
749
748
 
750
- @skipIf(sys.version_info < (3, 12), "type statements added in 3.12")
749
+ @pytest.mark.skipif(sys.version_info < (3, 12), reason="type statements added in 3.12")
751
750
  def test_parameterized_type_statement() -> None:
752
751
  env: dict[str, Any] = {}
753
752
  exec("type Pair[A, B] = tuple[B, A]\n", env)
@@ -1,5 +1,3 @@
1
- import sys
2
- import unittest
3
1
  from typing import Callable, List, Optional
4
2
 
5
3
  from crosshair.diff_behavior import (
@@ -346,7 +346,7 @@ class AtomicSymbolicValue(SymbolicValue):
346
346
  raise CrossHairInternal(f"_pytype not implemented in {cls}")
347
347
 
348
348
  @classmethod
349
- def _smt_promote_literal(cls, val: object) -> Optional[z3.SortRef]:
349
+ def _smt_promote_literal(cls, literal: object) -> Optional[z3.ExprRef]:
350
350
  raise CrossHairInternal(f"_smt_promote_literal not implemented in {cls}")
351
351
 
352
352
  @classmethod
@@ -1120,7 +1120,7 @@ class SymbolicBool(SymbolicIntable, AtomicSymbolicValue):
1120
1120
  return bool
1121
1121
 
1122
1122
  @classmethod
1123
- def _smt_promote_literal(cls, literal) -> Optional[z3.SortRef]:
1123
+ def _smt_promote_literal(cls, literal) -> Optional[z3.ExprRef]:
1124
1124
  if isinstance(literal, bool):
1125
1125
  return z3.BoolVal(literal)
1126
1126
  return None
@@ -1189,7 +1189,7 @@ class SymbolicInt(SymbolicIntable, AtomicSymbolicValue):
1189
1189
  return int
1190
1190
 
1191
1191
  @classmethod
1192
- def _smt_promote_literal(cls, literal) -> Optional[z3.SortRef]:
1192
+ def _smt_promote_literal(cls, literal) -> Optional[z3.ExprRef]:
1193
1193
  if isinstance(literal, int):
1194
1194
  return z3IntVal(literal)
1195
1195
  return None
@@ -1410,7 +1410,7 @@ class PreciseIeeeSymbolicFloat(SymbolicFloat):
1410
1410
  return _PRECISE_IEEE_FLOAT_SORT
1411
1411
 
1412
1412
  @classmethod
1413
- def _smt_promote_literal(cls, literal) -> Optional[z3.SortRef]:
1413
+ def _smt_promote_literal(cls, literal) -> Optional[z3.ExprRef]:
1414
1414
  if isinstance(literal, float):
1415
1415
  return z3.FPVal(literal, cls._ch_smt_sort())
1416
1416
  return None
@@ -1533,7 +1533,7 @@ class RealBasedSymbolicFloat(SymbolicFloat):
1533
1533
  return z3.RealSort()
1534
1534
 
1535
1535
  @classmethod
1536
- def _smt_promote_literal(cls, literal) -> Optional[z3.SortRef]:
1536
+ def _smt_promote_literal(cls, literal) -> Optional[z3.ExprRef]:
1537
1537
  if isinstance(literal, float) and isfinite(literal):
1538
1538
  return z3.RealVal(literal)
1539
1539
  return None
@@ -2447,7 +2447,7 @@ class SymbolicType(AtomicSymbolicValue, SymbolicValue, Untracable):
2447
2447
  return type
2448
2448
 
2449
2449
  @classmethod
2450
- def _smt_promote_literal(cls, literal) -> Optional[z3.SortRef]:
2450
+ def _smt_promote_literal(cls, literal) -> Optional[z3.ExprRef]:
2451
2451
  if isinstance(literal, type):
2452
2452
  return context_statespace().extra(SymbolicTypeRepository).get_type(literal)
2453
2453
  return None
@@ -2611,18 +2611,6 @@ class SymbolicObject(ObjectProxy, CrossHairValue, Untracable):
2611
2611
  return object()
2612
2612
  return proxy_for_type(pytype, varname, allow_subtypes=False)
2613
2613
 
2614
- def _wrapped(self):
2615
- with NoTracing():
2616
- inner = _MISSING
2617
- try:
2618
- inner = object.__getattribute__(self, "_inner")
2619
- except AttributeError:
2620
- pass
2621
- if inner is _MISSING:
2622
- inner = self._realize()
2623
- object.__setattr__(self, "_inner", inner)
2624
- return inner
2625
-
2626
2614
  def __ch_realize__(self):
2627
2615
  return realize(self._wrapped())
2628
2616
 
@@ -2680,10 +2668,25 @@ class SymbolicCallable:
2680
2668
  __annotations__: dict = {}
2681
2669
 
2682
2670
  def __init__(self, values: list):
2671
+ """
2672
+ A function that will ignore its arguments and produce return values
2673
+ from the list given.
2674
+ If the given list is exhausted, the function will just repeatedly
2675
+ return the final value in the list.
2676
+
2677
+ If `values` is concrete, it must be non-mepty.
2678
+ If `values` is a symbolic list, it will be forced to be non-empty
2679
+ (the caller must enure that's possible).
2680
+ """
2683
2681
  assert not is_tracing()
2684
2682
  with ResumedTracing():
2685
- if not values:
2686
- raise IgnoreAttempt
2683
+ has_values = len(values) > 0
2684
+ if isinstance(values, CrossHairValue):
2685
+ space = context_statespace()
2686
+ assert space.is_possible(has_values)
2687
+ space.add(has_values)
2688
+ else:
2689
+ assert has_values
2687
2690
  self.values = values
2688
2691
  self.idx = 0
2689
2692
 
@@ -2707,6 +2710,7 @@ class SymbolicCallable:
2707
2710
  if idx >= len(values):
2708
2711
  return values[-1]
2709
2712
  else:
2713
+ self.idx += 1
2710
2714
  return values[idx]
2711
2715
 
2712
2716
  def __bool__(self):
@@ -3418,6 +3422,26 @@ class AnySymbolicStr(AbcString):
3418
3422
  return "0" * fill_length + self
3419
3423
 
3420
3424
 
3425
+ def _unfindable_range(start: Optional[int], end: Optional[int], mylen: int) -> bool:
3426
+ """
3427
+ Emulates some preliminary checks that CPython makes before searching
3428
+ for substrings within some bounds. (in e.g. str.find, str.startswith, etc)
3429
+ """
3430
+ if start is None or start == 0 or start <= -mylen:
3431
+ return False
3432
+
3433
+ # At this point, we know that `start` is defined and points to an index after 0
3434
+ if end is None or end >= mylen:
3435
+ return start > mylen
3436
+
3437
+ # At this point, we know that `end` is defined and points to an index before the end of the string
3438
+ if start < 0:
3439
+ start += mylen
3440
+ if end < 0:
3441
+ end += mylen
3442
+ return end < start
3443
+
3444
+
3421
3445
  class LazyIntSymbolicStr(AnySymbolicStr, CrossHairValue):
3422
3446
  """
3423
3447
  A symbolic string that lazily generates SymbolicInt-based characters as needed.
@@ -3456,10 +3480,8 @@ class LazyIntSymbolicStr(AnySymbolicStr, CrossHairValue):
3456
3480
  codepoints = tuple(self._codepoints)
3457
3481
  return "".join(chr(realize(x)) for x in codepoints)
3458
3482
 
3459
- # This is normally an AtomicSymbolicValue method, but sometimes it's used in a
3460
- # duck-typing way.
3461
3483
  @classmethod
3462
- def _smt_promote_literal(cls, val: object) -> Optional[z3.SortRef]:
3484
+ def _ch_create_from_literal(cls, val: object) -> Optional[CrossHairValue]:
3463
3485
  if isinstance(val, str):
3464
3486
  return LazyIntSymbolicStr(list(map(ord, val)))
3465
3487
  return None
@@ -3493,6 +3515,10 @@ class LazyIntSymbolicStr(AnySymbolicStr, CrossHairValue):
3493
3515
  with NoTracing():
3494
3516
  if not isinstance(i, (Integral, slice)):
3495
3517
  raise TypeError(type(i))
3518
+ # This could/should? be symbolic by naming all the possibilities.
3519
+ # Note the slice case still must realize the return length.
3520
+ # Especially because we no longer explore realization trees except
3521
+ # as a last resort.
3496
3522
  i = deep_realize(i)
3497
3523
  with ResumedTracing():
3498
3524
  newcontents = self._codepoints[i]
@@ -3573,11 +3599,15 @@ class LazyIntSymbolicStr(AnySymbolicStr, CrossHairValue):
3573
3599
  return any(self.endswith(s, start, end) for s in substr)
3574
3600
  if not isinstance(substr, str):
3575
3601
  raise TypeError
3602
+ substrlen = len(substr)
3576
3603
  if start is None and end is None:
3577
3604
  matchable = self
3578
3605
  else:
3579
3606
  matchable = self[start:end]
3580
- return matchable[-len(substr) :] == substr
3607
+ if substrlen == 0:
3608
+ return not _unfindable_range(start, end, len(self))
3609
+ else:
3610
+ return matchable[-substrlen:] == substr
3581
3611
 
3582
3612
  def startswith(self, substr, start=None, end=None):
3583
3613
  if isinstance(substr, tuple):
@@ -3587,6 +3617,10 @@ class LazyIntSymbolicStr(AnySymbolicStr, CrossHairValue):
3587
3617
  if start is None and end is None:
3588
3618
  matchable = self
3589
3619
  else:
3620
+ # Wacky special case: the empty string is findable off the left
3621
+ # side but not the right!
3622
+ if _unfindable_range(start, end, len(self)):
3623
+ return False
3590
3624
  matchable = self[start:end]
3591
3625
  return matchable[: len(substr)] == substr
3592
3626
 
@@ -3627,7 +3661,7 @@ class LazyIntSymbolicStr(AnySymbolicStr, CrossHairValue):
3627
3661
  end += mylen
3628
3662
  matchstr = self[start:end] if start != 0 or end is not mylen else self
3629
3663
  if len(substr) == 0:
3630
- # Add oddity of CPython. We can find the empty string when over-slicing
3664
+ # An oddity of CPython. We can find the empty string when over-slicing
3631
3665
  # off the left side of the string, but not off the right:
3632
3666
  # ''.find('', 3, 4) == -1
3633
3667
  # ''.find('', -4, -3) == 0
@@ -4802,14 +4836,17 @@ def _str_format_map(self, map) -> Union[AnySymbolicStr, str]:
4802
4836
 
4803
4837
 
4804
4838
  def _str_startswith(self, substr, start=None, end=None) -> bool:
4805
- if not isinstance(self, str):
4806
- raise TypeError
4807
4839
  with NoTracing():
4840
+ if isinstance(self, LazyIntSymbolicStr):
4841
+ with ResumedTracing():
4842
+ return self.startswith(substr, start, end)
4843
+ elif not isinstance(self, str):
4844
+ raise TypeError
4808
4845
  # Handle native values with native implementation:
4809
4846
  if type(substr) is str:
4810
4847
  return self.startswith(substr, start, end)
4811
4848
  if type(substr) is tuple:
4812
- if all(type(i) is str for i in substr):
4849
+ if all(type(s) is str for s in substr):
4813
4850
  return self.startswith(substr, start, end)
4814
4851
  symbolic_self = LazyIntSymbolicStr([ord(c) for c in self])
4815
4852
  return symbolic_self.startswith(substr, start, end)
@@ -606,9 +606,14 @@ def check_str_endswith(
606
606
  string: str, suffix: str, start: Optional[int], end: Optional[int]
607
607
  ) -> ResultComparison:
608
608
  """post: _"""
609
+ # crosshair: max_uninteresting_iterations=100
610
+
611
+ for i in (len(string), len(suffix), start, end):
612
+ if i is not None and abs(i) >= 1:
613
+ pass
614
+
609
615
  return compare_results(
610
- lambda s, *a: s.endswith(*a),
611
- string,
616
+ lambda s, *a, **kw: s.endswith(*a, **kw), string, suffix, start, end
612
617
  )
613
618
 
614
619
 
@@ -825,6 +830,11 @@ def check_str_startswith(
825
830
  end: Optional[int],
826
831
  ) -> ResultComparison:
827
832
  """post: _"""
833
+ # crosshair: max_uninteresting_iterations=100
834
+
835
+ for i in (len(string), len(prefix), start, end):
836
+ if i is not None and abs(i) >= 1:
837
+ pass
828
838
  return compare_results(
829
839
  lambda s, *a, **kw: s.startswith(*a, **kw), string, prefix, start, end
830
840
  )
@@ -939,6 +939,31 @@ def test_str_replace_method() -> None:
939
939
  check_states(f, POST_FAIL)
940
940
 
941
941
 
942
+ def test_str_startswith(space) -> None:
943
+ symbolic_char = proxy_for_type(str, "x")
944
+ symbolic_empty = proxy_for_type(str, "y")
945
+ with ResumedTracing():
946
+ space.add(len(symbolic_char) == 1)
947
+ space.add(len(symbolic_empty) == 0)
948
+ assert symbolic_char.startswith(symbolic_empty)
949
+ assert symbolic_char.startswith(symbolic_char)
950
+ assert symbolic_char.startswith(("foo", symbolic_empty))
951
+ assert not symbolic_char.startswith(("foo", "bar"))
952
+ assert symbolic_char.startswith(("", "bar"))
953
+ assert symbolic_char.startswith("")
954
+ assert symbolic_char.startswith(symbolic_empty, 1)
955
+ assert symbolic_char.startswith(symbolic_empty, 1, 1)
956
+ assert str.startswith(symbolic_char, symbolic_empty)
957
+ assert "foo".startswith(symbolic_empty)
958
+ assert not "".startswith(symbolic_char)
959
+
960
+ # Yes, the empty string is findable off the left side but not the right
961
+ assert "x".startswith("", -10, -9)
962
+ assert symbolic_char.startswith(symbolic_empty, -10, -9)
963
+ assert not "x".startswith("", 9, 10)
964
+ assert not symbolic_char.startswith(symbolic_empty, 9, 10)
965
+
966
+
942
967
  @pytest.mark.demo
943
968
  def test_str_index_method() -> None:
944
969
  def f(a: str) -> int:
@@ -3134,6 +3159,17 @@ def test_callable_as_bool() -> None:
3134
3159
  check_states(f, CONFIRMED)
3135
3160
 
3136
3161
 
3162
+ def test_callable_can_return_different_values(space) -> None:
3163
+ fn = proxy_for_type(Callable[[], int], "fn")
3164
+ with ResumedTracing():
3165
+ first_return = fn()
3166
+ second_return = fn()
3167
+ returns_are_equal = first_return == second_return
3168
+ returns_are_not_equal = first_return != second_return
3169
+ assert space.is_possible(returns_are_equal)
3170
+ assert space.is_possible(returns_are_not_equal)
3171
+
3172
+
3137
3173
  @pytest.mark.smoke
3138
3174
  def test_callable_repr() -> None:
3139
3175
  def f(f1: Callable[[int], int]) -> int:
@@ -3,7 +3,7 @@ import sys
3
3
  from collections import Counter, defaultdict, deque, namedtuple
4
4
  from copy import deepcopy
5
5
  from inspect import Parameter, Signature
6
- from typing import Counter, DefaultDict, Deque, NamedTuple, Tuple
6
+ from typing import Callable, Counter, DefaultDict, Deque, Dict, NamedTuple, Tuple
7
7
 
8
8
  import pytest
9
9
 
@@ -14,7 +14,7 @@ from crosshair.core import (
14
14
  realize,
15
15
  standalone_statespace,
16
16
  )
17
- from crosshair.libimpl.collectionslib import ListBasedDeque
17
+ from crosshair.libimpl.collectionslib import ListBasedDeque, PureDefaultDict
18
18
  from crosshair.statespace import CANNOT_CONFIRM, CONFIRMED, POST_FAIL, MessageType
19
19
  from crosshair.test_util import check_states
20
20
  from crosshair.tracers import NoTracing, ResumedTracing
@@ -246,10 +246,10 @@ def test_defaultdict_default_fail(test_list) -> None:
246
246
 
247
247
 
248
248
  def test_defaultdict_default_ok(test_list) -> None:
249
- def f(a: DefaultDict[int, int], k1: int, k2: int) -> DefaultDict[int, int]:
249
+ def f(a: DefaultDict[int, int], k: int) -> DefaultDict[int, int]:
250
250
  """
251
251
  pre: len(a) == 0 and a.default_factory is not None
252
- post: _[k1] == _[k2]
252
+ post: _[k] == _[k]
253
253
  """
254
254
  return a
255
255
 
@@ -1,4 +1,4 @@
1
- from functools import _lru_cache_wrapper, partial, reduce
1
+ from functools import _lru_cache_wrapper, partial, reduce, update_wrapper, wraps
2
2
 
3
3
  from crosshair.core import register_patch
4
4
 
@@ -7,7 +7,13 @@ from crosshair.core import register_patch
7
7
 
8
8
  def _partial(func, *a1, **kw1):
9
9
  if callable(func):
10
- return partial(lambda *a2, **kw2: func(*a2, **kw2), *a1, **kw1)
10
+ # We make a do-nothing wrapper to ensure that the tracer has a crack
11
+ # at this function when it is called.
12
+ def wrapper(*a2, **kw2):
13
+ return func(*a2, **kw2)
14
+
15
+ update_wrapper(wrapper, func)
16
+ return partial(wrapper, *a1, **kw1)
11
17
  else:
12
18
  raise TypeError
13
19
 
@@ -1,20 +1,36 @@
1
1
  import functools
2
+ import inspect
2
3
 
3
4
  from crosshair.core import proxy_for_type, standalone_statespace
4
5
  from crosshair.libimpl.builtinslib import LazyIntSymbolicStr
5
- from crosshair.tracers import NoTracing
6
+ from crosshair.tracers import NoTracing, ResumedTracing
6
7
 
7
8
 
8
- def test_partial():
9
- with standalone_statespace as space:
10
- with NoTracing():
11
- abc = LazyIntSymbolicStr(list(map(ord, "abc")))
12
- xyz = LazyIntSymbolicStr(list(map(ord, "xyz")))
9
+ def test_partial(space):
10
+ abc = LazyIntSymbolicStr(list(map(ord, "abc")))
11
+ xyz = LazyIntSymbolicStr(list(map(ord, "xyz")))
12
+ with ResumedTracing():
13
13
  joiner = functools.partial(str.join, ",")
14
14
  ret = joiner([abc, xyz])
15
15
  assert ret == "abc,xyz"
16
16
 
17
17
 
18
+ def test_partial_is_interceptable(space):
19
+ x = proxy_for_type(str, "x")
20
+ y = proxy_for_type(str, "y")
21
+ with ResumedTracing():
22
+ joiner = functools.partial(str.startswith, x)
23
+ # Ensure we don't explode
24
+ list(map(joiner, ["foo", y]))
25
+
26
+
27
+ def test_partial_arg_is_inspectable(space):
28
+ with ResumedTracing():
29
+ joiner = functools.partial(str.join, ",")
30
+ assert isinstance(joiner, functools.partial)
31
+ assert inspect.getdoc(joiner.func) == inspect.getdoc(str.join)
32
+
33
+
18
34
  def test_reduce():
19
35
  with standalone_statespace as space:
20
36
  with NoTracing():
@@ -10,11 +10,36 @@ from crosshair.tracers import NoTracing
10
10
  # (which is BSD licenced)
11
11
  #
12
12
 
13
+ _MISSING = object()
14
+
15
+
16
+ def proxy_inplace_op(proxy, op, *args):
17
+ my_original_value = proxy._wrapped()
18
+ my_new_value = op(my_original_value, *args)
19
+ # We need to return our own identity if (and only if!) the underlying value does.
20
+ if my_new_value is my_original_value:
21
+ return proxy
22
+ else:
23
+ object.__setattr__(proxy, "_inner", my_new_value)
24
+ return my_new_value
25
+
13
26
 
14
27
  class ObjectProxy:
15
- def _wrapped(self):
28
+ def _realize(self):
16
29
  raise NotImplementedError
17
30
 
31
+ def _wrapped(self):
32
+ with NoTracing():
33
+ inner = _MISSING
34
+ try:
35
+ inner = object.__getattribute__(self, "_inner")
36
+ except AttributeError:
37
+ pass
38
+ if inner is _MISSING:
39
+ inner = self._realize()
40
+ object.__setattr__(self, "_inner", inner)
41
+ return inner
42
+
18
43
  def __get_module__(self) -> str:
19
44
  return self._wrapped().__module__
20
45
 
@@ -233,40 +258,40 @@ class ObjectProxy:
233
258
  return other | self._wrapped()
234
259
 
235
260
  def __iadd__(self, other):
236
- return operator.iadd(self._wrapped(), other)
261
+ return proxy_inplace_op(self, operator.iadd, other)
237
262
 
238
263
  def __isub__(self, other):
239
- return operator.isub(self._wrapped(), other)
264
+ return proxy_inplace_op(self, operator.isub, other)
240
265
 
241
266
  def __imul__(self, other):
242
- return operator.imul(self._wrapped(), other)
267
+ return proxy_inplace_op(self, operator.imul, other)
243
268
 
244
269
  def __itruediv__(self, other):
245
- return operator.itruediv(self._wrapped(), other)
270
+ return proxy_inplace_op(self, operator.itruediv, other)
246
271
 
247
272
  def __ifloordiv__(self, other):
248
- return operator.iflootdiv(self._wrapped(), other)
273
+ return proxy_inplace_op(self, operator.ifloordiv, other)
249
274
 
250
275
  def __imod__(self, other):
251
- return operator.imod(self._wrapped(), other)
276
+ return proxy_inplace_op(self, operator.imod, other)
252
277
 
253
278
  def __ipow__(self, other, *args):
254
- return operator.ipow(self._wrapped(), other, *args)
279
+ return proxy_inplace_op(self, operator.ipow, other, *args)
255
280
 
256
281
  def __ilshift__(self, other):
257
- return operator.ilshift(self._wrapped(), other)
282
+ return proxy_inplace_op(self, operator.ilshift, other)
258
283
 
259
284
  def __irshift__(self, other):
260
- return operator.irshift(self._wrapped(), other)
285
+ return proxy_inplace_op(self, operator.irshift, other)
261
286
 
262
287
  def __iand__(self, other):
263
- return operator.iand(self._wrapped(), other)
288
+ return proxy_inplace_op(self, operator.iand, other)
264
289
 
265
290
  def __ixor__(self, other):
266
- return operator.ixor(self._wrapped(), other)
291
+ return proxy_inplace_op(self, operator.ixor, other)
267
292
 
268
293
  def __ior__(self, other):
269
- return operator.ior(self._wrapped(), other)
294
+ return proxy_inplace_op(self, operator.ior, other)
270
295
 
271
296
  def __neg__(self):
272
297
  return -self._wrapped()
@@ -0,0 +1,41 @@
1
+ import pytest
2
+
3
+ from crosshair.objectproxy import ObjectProxy
4
+
5
+
6
+ class ObjectWrap(ObjectProxy):
7
+ def __init__(self, obj):
8
+ object.__setattr__(self, "_o", obj)
9
+
10
+ def _realize(self):
11
+ return object.__getattribute__(self, "_o")
12
+
13
+
14
+ class TestObjectProxy:
15
+ def test_object_proxy_over_list(self) -> None:
16
+ i = [1, 2, 3]
17
+ proxy = ObjectWrap(i)
18
+ assert i == proxy
19
+ proxy.append(4)
20
+ assert [1, 2, 3, 4] == proxy
21
+ assert [1, 2, 3, 4, 5] == proxy + [5]
22
+ assert [2, 3] == proxy[1:3]
23
+ assert [1, 2, 3, 4] == proxy
24
+
25
+ def test_inplace_identities(self) -> None:
26
+ proxy = ObjectWrap(3.0)
27
+ orig_proxy = proxy
28
+ proxy += 1.0
29
+ assert proxy is not orig_proxy
30
+ proxy = ObjectWrap([1, 2])
31
+ orig_proxy = proxy
32
+ proxy += [3, 4]
33
+ assert proxy is orig_proxy
34
+
35
+ def test_object_proxy_over_float(self) -> None:
36
+ proxy = ObjectWrap(4.5)
37
+ proxy //= 2.0
38
+ assert 2.0 == proxy
39
+ proxy = ObjectWrap(5.0)
40
+ proxy /= 2.0
41
+ assert 2.5 == proxy
@@ -5,7 +5,9 @@ from collections import defaultdict
5
5
  from collections.abc import MutableMapping, Set
6
6
  from sys import version_info
7
7
  from types import CodeType, FrameType
8
- from typing import Any, Callable, Iterable, Mapping, Tuple, Union
8
+ from typing import Any, Callable, Iterable, List, Mapping, Tuple, Union
9
+
10
+ from z3 import ExprRef
9
11
 
10
12
  from crosshair.core import (
11
13
  ATOMIC_IMMUTABLE_TYPES,
@@ -83,13 +85,6 @@ class MultiSubscriptableContainer:
83
85
  if isinstance(container, Mapping):
84
86
  kv_pairs: Iterable[Tuple[Any, Any]] = container.items()
85
87
  else:
86
- in_bounds = space.smt_fork(
87
- z3Or(-len(container) <= key.var, key.var < len(container)),
88
- desc=f"index_in_bounds",
89
- probability_true=0.9,
90
- )
91
- if not in_bounds:
92
- raise IndexError
93
88
  kv_pairs = enumerate(container)
94
89
 
95
90
  values_by_type = defaultdict(list)
@@ -118,7 +113,7 @@ class MultiSubscriptableContainer:
118
113
  keys_by_value_id[id(cur_value)].append(cur_key)
119
114
  for value_type, cur_pairs in values_by_type.items():
120
115
  hypothetical_result = symbolic_for_pytype(value_type)(
121
- "item_at_" + space.uniq(), value_type
116
+ "item_" + space.uniq(), value_type
122
117
  )
123
118
  with ResumedTracing():
124
119
  condition_pairs = []
@@ -139,20 +134,17 @@ class MultiSubscriptableContainer:
139
134
  space.add(any([all(pair) for pair in condition_pairs]))
140
135
  return hypothetical_result
141
136
 
142
- for (value_id, value), probability_true in with_uniform_probabilities(
143
- values_by_id.items()
144
- ):
137
+ exprs_and_values: List[Tuple[ExprRef, object]] = []
138
+ for value_id, value in values_by_id.items():
145
139
  keys_for_value = keys_by_value_id[value_id]
146
140
  with ResumedTracing():
147
141
  is_match = any([key == k for k in keys_for_value])
148
142
  if isinstance(is_match, SymbolicBool):
149
- if space.smt_fork(
150
- is_match.var,
151
- probability_true=probability_true,
152
- ):
153
- return value
143
+ exprs_and_values.append((is_match.var, value))
154
144
  elif is_match:
155
145
  return value
146
+ if exprs_and_values:
147
+ return space.smt_fanout(exprs_and_values, desc="multi_subscript")
156
148
 
157
149
  if type(container) is dict:
158
150
  raise KeyError # ( f"Key {key} not found in dict")
@@ -133,7 +133,11 @@ def path_cover(
133
133
  selected: List[PathSummary] = []
134
134
  while paths:
135
135
  next_best = max(
136
- paths, key=lambda p: len(p.coverage.offsets_covered - opcodes_found)
136
+ paths,
137
+ key=lambda p: (
138
+ len(p.coverage.offsets_covered - opcodes_found), # high coverage
139
+ -len(p.formatted_args), # with small input size
140
+ ),
137
141
  )
138
142
  cur_offsets = next_best.coverage.offsets_covered
139
143
  if coverage_type == CoverageType.OPCODE: