superacli 1.1.6 → 1.1.8

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 (1268) hide show
  1. package/CONTRIBUTING.md +270 -0
  2. package/README.md +141 -54
  3. package/__tests__/adapter-schema.test.js +251 -86
  4. package/__tests__/azd-plugin.test.js +109 -0
  5. package/__tests__/config.test.js +4 -3
  6. package/__tests__/discover.test.js +59 -0
  7. package/__tests__/goose-plugin.test.js +149 -0
  8. package/__tests__/help-json.test.js +2 -0
  9. package/__tests__/openhands-plugin.test.js +106 -0
  10. package/__tests__/plugin-cocoindex-code-uninstall.test.js +19 -0
  11. package/__tests__/plugin-cocoindex-code.test.js +37 -0
  12. package/__tests__/plugin-install-guidance.test.js +81 -0
  13. package/__tests__/plugins-registry.test.js +44 -0
  14. package/__tests__/plugins-store.test.js +40 -5
  15. package/__tests__/process-adapter.test.js +50 -1
  16. package/__tests__/resend-plugin.test.js +109 -82
  17. package/__tests__/server-app.test.js +1 -0
  18. package/__tests__/server-routes-commands.test.js +20 -2
  19. package/__tests__/server-routes-plugins.test.js +130 -0
  20. package/__tests__/skills.test.js +26 -0
  21. package/__tests__/squirrelscan-plugin.test.js +129 -0
  22. package/__tests__/uipath-plugin.test.js +104 -0
  23. package/__tests__/uipathcli-plugin.test.js +95 -0
  24. package/cli/adapters/mcp.js +2 -0
  25. package/cli/adapters/process.js +50 -7
  26. package/cli/config.js +240 -3
  27. package/cli/discover.js +157 -0
  28. package/cli/help-json.js +16 -1
  29. package/cli/plugin-install-guidance.js +92 -37
  30. package/cli/plugins-manager.js +4 -3
  31. package/cli/plugins-registry.js +74 -8
  32. package/cli/plugins-store.js +78 -17
  33. package/cli/skills-mcp.js +1 -1
  34. package/cli/skills.js +39 -2
  35. package/cli/supercli.js +255 -63
  36. package/docs/feature-gaps.md +8 -8
  37. package/docs/features/azd-uipath-plugins.md +43 -0
  38. package/docs/features/server-plugins.md +62 -0
  39. package/docs/features/skills.md +9 -5
  40. package/docs/index.html +183 -123
  41. package/docs/{supported-harnesses.md → plugins-available.md} +4 -3
  42. package/docs/{plugin-harness-guide.md → plugins-how-to.md} +1 -1
  43. package/docs/plugins.md +26 -20
  44. package/docs/server-plugins-usage-guide.md +182 -0
  45. package/docs/skills-catalog.md +12 -10
  46. package/index.html +384 -0
  47. package/package.json +2 -2
  48. package/plugins/agent-browser/README.md +69 -0
  49. package/plugins/agent-browser/plugin.json +111 -0
  50. package/plugins/agent-browser/skills/quickstart/SKILL.md +66 -0
  51. package/plugins/aider/README.md +53 -0
  52. package/plugins/aider/plugin.json +105 -0
  53. package/plugins/aider/scripts/aider-wrapper.js +243 -0
  54. package/plugins/aider/scripts/setup-aider.js +37 -0
  55. package/plugins/aider/skills/dry-run-review.md +24 -0
  56. package/plugins/aider/skills/model-and-provider.md +24 -0
  57. package/plugins/aider/skills/one-shot-edits.md +30 -0
  58. package/plugins/aider/skills/quickstart/SKILL.md +51 -0
  59. package/plugins/azd/README.md +28 -0
  60. package/plugins/azd/plugin.json +87 -0
  61. package/plugins/azd/skills/quickstart/SKILL.md +41 -0
  62. package/plugins/blogwatcher/README.md +3 -3
  63. package/plugins/boxlite/Dockerfile +9 -0
  64. package/plugins/boxlite/README.md +62 -0
  65. package/plugins/boxlite/plugin.json +201 -0
  66. package/plugins/boxlite/scripts/run-boxlite.js +106 -0
  67. package/plugins/boxlite/skills/quickstart/SKILL.md +40 -0
  68. package/plugins/cass/plugin.json +150 -0
  69. package/plugins/cass/scripts/setup-cass.js +47 -0
  70. package/plugins/cass/skills/quickstart/SKILL.md +46 -0
  71. package/plugins/clever/README.md +46 -0
  72. package/plugins/clever/plugin.json +119 -0
  73. package/plugins/clever/scripts/setup-clever.js +28 -0
  74. package/plugins/clever/skills/auth-and-profile.md +29 -0
  75. package/plugins/clever/skills/passthrough-safety.md +21 -0
  76. package/plugins/clever/skills/quickstart/SKILL.md +45 -0
  77. package/plugins/clever/skills/resource-inventory.md +24 -0
  78. package/plugins/clix/README.md +4 -4
  79. package/plugins/cocoindex-code/README.md +64 -0
  80. package/plugins/cocoindex-code/plugin.json +81 -0
  81. package/plugins/cocoindex-code/scripts/__pycache__/query.cpython-310.pyc +0 -0
  82. package/plugins/cocoindex-code/scripts/__pycache__/query.cpython-311.pyc +0 -0
  83. package/plugins/cocoindex-code/scripts/post-install.js +61 -0
  84. package/plugins/cocoindex-code/scripts/post-uninstall.js +25 -0
  85. package/plugins/cocoindex-code/scripts/query.py +88 -0
  86. package/plugins/cocoindex-code/scripts/run-query.js +50 -0
  87. package/plugins/cocoindex-code/skills/quickstart/SKILL.md +73 -0
  88. package/plugins/copilot/README.md +24 -0
  89. package/plugins/copilot/plugin.json +80 -0
  90. package/plugins/copilot/skills/quickstart/SKILL.md +44 -0
  91. package/plugins/gemini/README.md +24 -0
  92. package/plugins/gemini/plugin.json +98 -0
  93. package/plugins/gemini/skills/quickstart/SKILL.md +44 -0
  94. package/plugins/gifcap/plugin.json +119 -0
  95. package/plugins/gifcap/scripts/setup-gifcap.js +44 -0
  96. package/plugins/gifcap/skills/quickstart/SKILL.md +34 -0
  97. package/plugins/gifcap/test-record-quiet.gif +0 -0
  98. package/plugins/gifcap/test-record.gif +0 -0
  99. package/plugins/goose/README.md +36 -0
  100. package/plugins/goose/plugin.json +183 -0
  101. package/plugins/goose/skills/quickstart/SKILL.md +44 -0
  102. package/plugins/json-server/README.md +58 -0
  103. package/plugins/json-server/plugin.json +113 -0
  104. package/plugins/json-server/skills/quickstart/SKILL.md +57 -0
  105. package/plugins/lightpanda/README.md +145 -0
  106. package/plugins/lightpanda/package-lock.json +1375 -0
  107. package/plugins/lightpanda/package.json +12 -0
  108. package/plugins/lightpanda/plugin.json +116 -0
  109. package/plugins/lightpanda/scripts/lightpanda-contacts.js +494 -0
  110. package/plugins/lightpanda/scripts/lightpanda-generic-extract.js +403 -0
  111. package/plugins/lightpanda/scripts/lightpanda-wrapper.js +480 -0
  112. package/plugins/lightpanda/scripts/setup-lightpanda.js +39 -0
  113. package/plugins/lightpanda/skills/contact-discovery.md +51 -0
  114. package/plugins/lightpanda/skills/generic-extraction.md +66 -0
  115. package/plugins/lightpanda/skills/quickstart/SKILL.md +103 -0
  116. package/plugins/lightpanda/skills/resilient-navigation.md +42 -0
  117. package/plugins/monty/README.md +2 -2
  118. package/plugins/nullclaw/README.md +3 -3
  119. package/plugins/offline-ai/README.md +23 -0
  120. package/plugins/offline-ai/plugin.json +82 -0
  121. package/plugins/offline-ai/skills/quickstart/SKILL.md +43 -0
  122. package/plugins/openhands/README.md +25 -0
  123. package/plugins/openhands/plugin.json +116 -0
  124. package/plugins/openhands/skills/quickstart/SKILL.md +26 -0
  125. package/plugins/plandex/README.md +25 -0
  126. package/plugins/plandex/plugin.json +130 -0
  127. package/plugins/plandex/skills/quickstart/SKILL.md +50 -0
  128. package/plugins/plugins.json +199 -0
  129. package/plugins/squirrelscan/Dockerfile +5 -0
  130. package/plugins/squirrelscan/README.md +47 -0
  131. package/plugins/squirrelscan/plugin.json +493 -0
  132. package/plugins/squirrelscan/scripts/post-install.js +33 -0
  133. package/plugins/squirrelscan/scripts/post-uninstall.js +25 -0
  134. package/plugins/squirrelscan/scripts/run-squirrel.js +73 -0
  135. package/plugins/squirrelscan/skills/audit-workflow/SKILL.md +33 -0
  136. package/plugins/squirrelscan/skills/publish-report/SKILL.md +33 -0
  137. package/plugins/squirrelscan/skills/quickstart/SKILL.md +41 -0
  138. package/plugins/uipath/README.md +27 -0
  139. package/plugins/uipath/plugin.json +86 -0
  140. package/plugins/uipath/skills/quickstart/SKILL.md +47 -0
  141. package/plugins/uipathcli/README.md +28 -0
  142. package/plugins/uipathcli/plugin.json +120 -0
  143. package/plugins/uipathcli/scripts/run-uipath-cli.js +49 -0
  144. package/plugins/uipathcli/skills/quickstart/SKILL.md +22 -0
  145. package/plugins/xurl/README.md +4 -4
  146. package/server/app.js +5 -2
  147. package/server/public/app.js +3 -0
  148. package/server/routes/commands.js +95 -12
  149. package/server/routes/plugins.js +262 -0
  150. package/server/services/pluginsService.js +303 -0
  151. package/server/views/command-edit.ejs +196 -14
  152. package/server/views/partials/head.ejs +1 -0
  153. package/server/views/plugins.ejs +264 -0
  154. package/tests/test-plugins-registry.js +30 -0
  155. package/.beads/.br_history/issues.20260308_200823_636718328.jsonl +0 -20
  156. package/.beads/.br_history/issues.20260308_200823_636718328.jsonl.meta.json +0 -1
  157. package/.beads/.br_history/issues.20260308_200827_033159453.jsonl +0 -21
  158. package/.beads/.br_history/issues.20260308_200827_033159453.jsonl.meta.json +0 -1
  159. package/.beads/.br_history/issues.20260308_200829_595900053.jsonl +0 -22
  160. package/.beads/.br_history/issues.20260308_200829_595900053.jsonl.meta.json +0 -1
  161. package/.beads/.br_history/issues.20260308_200834_079930100.jsonl +0 -23
  162. package/.beads/.br_history/issues.20260308_200834_079930100.jsonl.meta.json +0 -1
  163. package/.beads/.br_history/issues.20260308_200858_370924996.jsonl +0 -24
  164. package/.beads/.br_history/issues.20260308_200858_370924996.jsonl.meta.json +0 -1
  165. package/.beads/.br_history/issues.20260308_201031_019730855.jsonl +0 -24
  166. package/.beads/.br_history/issues.20260308_201031_019730855.jsonl.meta.json +0 -1
  167. package/.beads/.br_history/issues.20260308_201031_578974884.jsonl +0 -24
  168. package/.beads/.br_history/issues.20260308_201031_578974884.jsonl.meta.json +0 -1
  169. package/.beads/.br_history/issues.20260308_201054_780345548.jsonl +0 -24
  170. package/.beads/.br_history/issues.20260308_201054_780345548.jsonl.meta.json +0 -1
  171. package/.beads/.br_history/issues.20260308_201054_896980019.jsonl +0 -24
  172. package/.beads/.br_history/issues.20260308_201054_896980019.jsonl.meta.json +0 -1
  173. package/.beads/.br_history/issues.20260308_201128_599819688.jsonl +0 -24
  174. package/.beads/.br_history/issues.20260308_201128_599819688.jsonl.meta.json +0 -1
  175. package/.beads/.br_history/issues.20260308_201128_710221699.jsonl +0 -24
  176. package/.beads/.br_history/issues.20260308_201128_710221699.jsonl.meta.json +0 -1
  177. package/.beads/.br_history/issues.20260308_201204_745649213.jsonl +0 -24
  178. package/.beads/.br_history/issues.20260308_201204_745649213.jsonl.meta.json +0 -1
  179. package/.beads/.br_history/issues.20260308_201338_908436144.jsonl +0 -24
  180. package/.beads/.br_history/issues.20260308_201338_908436144.jsonl.meta.json +0 -1
  181. package/.beads/.br_history/issues.20260308_201344_734860714.jsonl +0 -25
  182. package/.beads/.br_history/issues.20260308_201344_734860714.jsonl.meta.json +0 -1
  183. package/.beads/.br_history/issues.20260308_201630_819282295.jsonl +0 -25
  184. package/.beads/.br_history/issues.20260308_201630_819282295.jsonl.meta.json +0 -1
  185. package/.beads/.br_history/issues.20260308_203538_054279699.jsonl +0 -25
  186. package/.beads/.br_history/issues.20260308_203538_054279699.jsonl.meta.json +0 -1
  187. package/.beads/.br_history/issues.20260308_203547_597113070.jsonl +0 -26
  188. package/.beads/.br_history/issues.20260308_203547_597113070.jsonl.meta.json +0 -1
  189. package/.beads/.br_history/issues.20260308_203547_775139216.jsonl +0 -27
  190. package/.beads/.br_history/issues.20260308_203547_775139216.jsonl.meta.json +0 -1
  191. package/.beads/.br_history/issues.20260308_203547_950724773.jsonl +0 -28
  192. package/.beads/.br_history/issues.20260308_203547_950724773.jsonl.meta.json +0 -1
  193. package/.beads/.br_history/issues.20260308_203548_107684523.jsonl +0 -29
  194. package/.beads/.br_history/issues.20260308_203548_107684523.jsonl.meta.json +0 -1
  195. package/.beads/.br_history/issues.20260308_203548_310389993.jsonl +0 -30
  196. package/.beads/.br_history/issues.20260308_203548_310389993.jsonl.meta.json +0 -1
  197. package/.beads/.br_history/issues.20260308_203825_953337320.jsonl +0 -31
  198. package/.beads/.br_history/issues.20260308_203825_953337320.jsonl.meta.json +0 -1
  199. package/.beads/.br_history/issues.20260308_204056_071377736.jsonl +0 -32
  200. package/.beads/.br_history/issues.20260308_204056_071377736.jsonl.meta.json +0 -1
  201. package/.beads/.br_history/issues.20260308_205141_517616844.jsonl +0 -32
  202. package/.beads/.br_history/issues.20260308_205141_517616844.jsonl.meta.json +0 -1
  203. package/.beads/.br_history/issues.20260308_205141_648994024.jsonl +0 -32
  204. package/.beads/.br_history/issues.20260308_205141_648994024.jsonl.meta.json +0 -1
  205. package/.beads/.br_history/issues.20260308_205141_867598036.jsonl +0 -32
  206. package/.beads/.br_history/issues.20260308_205141_867598036.jsonl.meta.json +0 -1
  207. package/.beads/.br_history/issues.20260308_205142_094157355.jsonl +0 -32
  208. package/.beads/.br_history/issues.20260308_205142_094157355.jsonl.meta.json +0 -1
  209. package/.beads/.br_history/issues.20260308_205142_327315677.jsonl +0 -32
  210. package/.beads/.br_history/issues.20260308_205142_327315677.jsonl.meta.json +0 -1
  211. package/.beads/.br_history/issues.20260308_205142_545563822.jsonl +0 -32
  212. package/.beads/.br_history/issues.20260308_205142_545563822.jsonl.meta.json +0 -1
  213. package/.beads/.br_history/issues.20260308_205213_061989333.jsonl +0 -32
  214. package/.beads/.br_history/issues.20260308_205213_061989333.jsonl.meta.json +0 -1
  215. package/.beads/.br_history/issues.20260308_205213_181103364.jsonl +0 -32
  216. package/.beads/.br_history/issues.20260308_205213_181103364.jsonl.meta.json +0 -1
  217. package/.beads/.br_history/issues.20260308_205213_408872234.jsonl +0 -32
  218. package/.beads/.br_history/issues.20260308_205213_408872234.jsonl.meta.json +0 -1
  219. package/.beads/.br_history/issues.20260308_205213_616681652.jsonl +0 -32
  220. package/.beads/.br_history/issues.20260308_205213_616681652.jsonl.meta.json +0 -1
  221. package/.beads/.br_history/issues.20260308_205213_821507069.jsonl +0 -32
  222. package/.beads/.br_history/issues.20260308_205213_821507069.jsonl.meta.json +0 -1
  223. package/.beads/.br_history/issues.20260308_205214_026661112.jsonl +0 -32
  224. package/.beads/.br_history/issues.20260308_205214_026661112.jsonl.meta.json +0 -1
  225. package/.beads/.br_history/issues.20260308_205454_955250554.jsonl +0 -32
  226. package/.beads/.br_history/issues.20260308_205454_955250554.jsonl.meta.json +0 -1
  227. package/.beads/.br_history/issues.20260308_205556_337800392.jsonl +0 -33
  228. package/.beads/.br_history/issues.20260308_205556_337800392.jsonl.meta.json +0 -1
  229. package/.beads/.br_history/issues.20260308_205824_274686694.jsonl +0 -33
  230. package/.beads/.br_history/issues.20260308_205824_274686694.jsonl.meta.json +0 -1
  231. package/.beads/.br_history/issues.20260308_210240_583768328.jsonl +0 -34
  232. package/.beads/.br_history/issues.20260308_210240_583768328.jsonl.meta.json +0 -1
  233. package/.beads/.br_history/issues.20260308_212223_641541494.jsonl +0 -34
  234. package/.beads/.br_history/issues.20260308_212223_641541494.jsonl.meta.json +0 -1
  235. package/.beads/.br_history/issues.20260308_212227_735550996.jsonl +0 -35
  236. package/.beads/.br_history/issues.20260308_212227_735550996.jsonl.meta.json +0 -1
  237. package/.beads/.br_history/issues.20260308_212232_547298548.jsonl +0 -36
  238. package/.beads/.br_history/issues.20260308_212232_547298548.jsonl.meta.json +0 -1
  239. package/.beads/.br_history/issues.20260308_212528_843628125.jsonl +0 -37
  240. package/.beads/.br_history/issues.20260308_212528_843628125.jsonl.meta.json +0 -1
  241. package/.beads/.br_history/issues.20260308_212529_094530502.jsonl +0 -38
  242. package/.beads/.br_history/issues.20260308_212529_094530502.jsonl.meta.json +0 -1
  243. package/.beads/.br_history/issues.20260308_212529_331000853.jsonl +0 -39
  244. package/.beads/.br_history/issues.20260308_212529_331000853.jsonl.meta.json +0 -1
  245. package/.beads/.br_history/issues.20260308_212529_587925652.jsonl +0 -40
  246. package/.beads/.br_history/issues.20260308_212529_587925652.jsonl.meta.json +0 -1
  247. package/.beads/.br_history/issues.20260308_212804_927764103.jsonl +0 -41
  248. package/.beads/.br_history/issues.20260308_212804_927764103.jsonl.meta.json +0 -1
  249. package/.beads/.br_history/issues.20260308_212805_153673453.jsonl +0 -42
  250. package/.beads/.br_history/issues.20260308_212805_153673453.jsonl.meta.json +0 -1
  251. package/.beads/.br_history/issues.20260308_212805_415982363.jsonl +0 -43
  252. package/.beads/.br_history/issues.20260308_212805_415982363.jsonl.meta.json +0 -1
  253. package/.beads/.br_history/issues.20260308_212805_657497741.jsonl +0 -44
  254. package/.beads/.br_history/issues.20260308_212805_657497741.jsonl.meta.json +0 -1
  255. package/.beads/.br_history/issues.20260308_212805_952838724.jsonl +0 -45
  256. package/.beads/.br_history/issues.20260308_212805_952838724.jsonl.meta.json +0 -1
  257. package/.beads/.br_history/issues.20260308_212806_325433779.jsonl +0 -46
  258. package/.beads/.br_history/issues.20260308_212806_325433779.jsonl.meta.json +0 -1
  259. package/.beads/.br_history/issues.20260308_212806_584685598.jsonl +0 -47
  260. package/.beads/.br_history/issues.20260308_212806_584685598.jsonl.meta.json +0 -1
  261. package/.beads/.br_history/issues.20260308_212806_827817208.jsonl +0 -48
  262. package/.beads/.br_history/issues.20260308_212806_827817208.jsonl.meta.json +0 -1
  263. package/.beads/.br_history/issues.20260308_212807_111320451.jsonl +0 -49
  264. package/.beads/.br_history/issues.20260308_212807_111320451.jsonl.meta.json +0 -1
  265. package/.beads/.br_history/issues.20260308_212807_409545536.jsonl +0 -50
  266. package/.beads/.br_history/issues.20260308_212807_409545536.jsonl.meta.json +0 -1
  267. package/.beads/.br_history/issues.20260308_212807_625063294.jsonl +0 -51
  268. package/.beads/.br_history/issues.20260308_212807_625063294.jsonl.meta.json +0 -1
  269. package/.beads/.br_history/issues.20260308_212807_843906551.jsonl +0 -52
  270. package/.beads/.br_history/issues.20260308_212807_843906551.jsonl.meta.json +0 -1
  271. package/.beads/.br_history/issues.20260308_212808_100304073.jsonl +0 -53
  272. package/.beads/.br_history/issues.20260308_212808_100304073.jsonl.meta.json +0 -1
  273. package/.beads/.br_history/issues.20260308_212808_324723976.jsonl +0 -54
  274. package/.beads/.br_history/issues.20260308_212808_324723976.jsonl.meta.json +0 -1
  275. package/.beads/.br_history/issues.20260308_212808_557513104.jsonl +0 -55
  276. package/.beads/.br_history/issues.20260308_212808_557513104.jsonl.meta.json +0 -1
  277. package/.beads/.br_history/issues.20260308_212808_788048322.jsonl +0 -56
  278. package/.beads/.br_history/issues.20260308_212808_788048322.jsonl.meta.json +0 -1
  279. package/.beads/.br_history/issues.20260308_213702_613249728.jsonl +0 -57
  280. package/.beads/.br_history/issues.20260308_213702_613249728.jsonl.meta.json +0 -1
  281. package/.beads/.br_history/issues.20260308_213715_115792063.jsonl +0 -57
  282. package/.beads/.br_history/issues.20260308_213715_115792063.jsonl.meta.json +0 -1
  283. package/.beads/.br_history/issues.20260308_213715_462220666.jsonl +0 -57
  284. package/.beads/.br_history/issues.20260308_213715_462220666.jsonl.meta.json +0 -1
  285. package/.beads/.br_history/issues.20260308_213727_191258923.jsonl +0 -57
  286. package/.beads/.br_history/issues.20260308_213727_191258923.jsonl.meta.json +0 -1
  287. package/.beads/.br_history/issues.20260308_213727_684383652.jsonl +0 -57
  288. package/.beads/.br_history/issues.20260308_213727_684383652.jsonl.meta.json +0 -1
  289. package/.beads/.br_history/issues.20260308_213735_751882991.jsonl +0 -57
  290. package/.beads/.br_history/issues.20260308_213735_751882991.jsonl.meta.json +0 -1
  291. package/.beads/.br_history/issues.20260308_222052_279844960.jsonl +0 -57
  292. package/.beads/.br_history/issues.20260308_222052_279844960.jsonl.meta.json +0 -1
  293. package/.beads/.br_history/issues.20260308_222056_873282114.jsonl +0 -57
  294. package/.beads/.br_history/issues.20260308_222056_873282114.jsonl.meta.json +0 -1
  295. package/.beads/.br_history/issues.20260308_222103_402410761.jsonl +0 -57
  296. package/.beads/.br_history/issues.20260308_222103_402410761.jsonl.meta.json +0 -1
  297. package/.beads/.br_history/issues.20260308_235202_180577215.jsonl +0 -57
  298. package/.beads/.br_history/issues.20260308_235202_180577215.jsonl.meta.json +0 -1
  299. package/.beads/.br_history/issues.20260308_235202_387414163.jsonl +0 -57
  300. package/.beads/.br_history/issues.20260308_235202_387414163.jsonl.meta.json +0 -1
  301. package/.beads/.br_history/issues.20260308_235202_564422794.jsonl +0 -57
  302. package/.beads/.br_history/issues.20260308_235202_564422794.jsonl.meta.json +0 -1
  303. package/.beads/.br_history/issues.20260308_235202_742600597.jsonl +0 -57
  304. package/.beads/.br_history/issues.20260308_235202_742600597.jsonl.meta.json +0 -1
  305. package/.beads/.br_history/issues.20260308_235208_133360069.jsonl +0 -57
  306. package/.beads/.br_history/issues.20260308_235208_133360069.jsonl.meta.json +0 -1
  307. package/.beads/.br_history/issues.20260308_235505_473406307.jsonl +0 -57
  308. package/.beads/.br_history/issues.20260308_235505_473406307.jsonl.meta.json +0 -1
  309. package/.beads/.br_history/issues.20260308_235505_662360489.jsonl +0 -57
  310. package/.beads/.br_history/issues.20260308_235505_662360489.jsonl.meta.json +0 -1
  311. package/.beads/.br_history/issues.20260308_235505_843935624.jsonl +0 -57
  312. package/.beads/.br_history/issues.20260308_235505_843935624.jsonl.meta.json +0 -1
  313. package/.beads/.br_history/issues.20260308_235506_044530221.jsonl +0 -57
  314. package/.beads/.br_history/issues.20260308_235506_044530221.jsonl.meta.json +0 -1
  315. package/.beads/.br_history/issues.20260309_002618_115728731.jsonl +0 -57
  316. package/.beads/.br_history/issues.20260309_002618_115728731.jsonl.meta.json +0 -1
  317. package/.beads/.br_history/issues.20260309_003748_878174586.jsonl +0 -57
  318. package/.beads/.br_history/issues.20260309_003748_878174586.jsonl.meta.json +0 -1
  319. package/.beads/.br_history/issues.20260309_004057_868755623.jsonl +0 -57
  320. package/.beads/.br_history/issues.20260309_004057_868755623.jsonl.meta.json +0 -1
  321. package/.beads/.br_history/issues.20260309_004058_512842163.jsonl +0 -57
  322. package/.beads/.br_history/issues.20260309_004058_512842163.jsonl.meta.json +0 -1
  323. package/.beads/.br_history/issues.20260309_004058_994445226.jsonl +0 -57
  324. package/.beads/.br_history/issues.20260309_004058_994445226.jsonl.meta.json +0 -1
  325. package/.beads/.br_history/issues.20260309_004059_475988596.jsonl +0 -57
  326. package/.beads/.br_history/issues.20260309_004059_475988596.jsonl.meta.json +0 -1
  327. package/.beads/.br_history/issues.20260309_161902_566857851.jsonl +0 -57
  328. package/.beads/.br_history/issues.20260309_161902_566857851.jsonl.meta.json +0 -1
  329. package/.beads/.br_history/issues.20260309_170512_277017739.jsonl +0 -57
  330. package/.beads/.br_history/issues.20260309_170512_277017739.jsonl.meta.json +0 -1
  331. package/.beads/.br_history/issues.20260309_170512_477876921.jsonl +0 -57
  332. package/.beads/.br_history/issues.20260309_170512_477876921.jsonl.meta.json +0 -1
  333. package/.beads/.br_history/issues.20260309_170512_664382701.jsonl +0 -57
  334. package/.beads/.br_history/issues.20260309_170512_664382701.jsonl.meta.json +0 -1
  335. package/.beads/.br_history/issues.20260309_170512_859400333.jsonl +0 -57
  336. package/.beads/.br_history/issues.20260309_170512_859400333.jsonl.meta.json +0 -1
  337. package/.beads/.br_history/issues.20260309_212326_082771164.jsonl +0 -57
  338. package/.beads/.br_history/issues.20260309_212326_082771164.jsonl.meta.json +0 -1
  339. package/.beads/.br_history/issues.20260309_212326_245619716.jsonl +0 -58
  340. package/.beads/.br_history/issues.20260309_212326_245619716.jsonl.meta.json +0 -1
  341. package/.beads/.br_history/issues.20260309_212326_403198317.jsonl +0 -59
  342. package/.beads/.br_history/issues.20260309_212326_403198317.jsonl.meta.json +0 -1
  343. package/.beads/.br_history/issues.20260309_212332_539197678.jsonl +0 -60
  344. package/.beads/.br_history/issues.20260309_212332_539197678.jsonl.meta.json +0 -1
  345. package/.beads/.br_history/issues.20260309_212332_731373599.jsonl +0 -60
  346. package/.beads/.br_history/issues.20260309_212332_731373599.jsonl.meta.json +0 -1
  347. package/.beads/.br_history/issues.20260309_212332_928710953.jsonl +0 -60
  348. package/.beads/.br_history/issues.20260309_212332_928710953.jsonl.meta.json +0 -1
  349. package/.beads/.br_history/issues.20260309_213021_341505240.jsonl +0 -60
  350. package/.beads/.br_history/issues.20260309_213021_341505240.jsonl.meta.json +0 -1
  351. package/.beads/.br_history/issues.20260309_213022_023136934.jsonl +0 -60
  352. package/.beads/.br_history/issues.20260309_213022_023136934.jsonl.meta.json +0 -1
  353. package/.beads/.br_history/issues.20260309_213022_400050719.jsonl +0 -60
  354. package/.beads/.br_history/issues.20260309_213022_400050719.jsonl.meta.json +0 -1
  355. package/.beads/config.yaml +0 -4
  356. package/.beads/issues.jsonl +0 -60
  357. package/.beads/metadata.json +0 -4
  358. package/docs/docs.html +0 -224
  359. package/docs/mcp-cheatsheet.md +0 -324
  360. package/docs/visual-overview.md +0 -21
  361. package/ref-monty/.cargo/config.toml +0 -3
  362. package/ref-monty/.claude/settings.json +0 -60
  363. package/ref-monty/.claude/skills/fastmod/SKILL.md +0 -22
  364. package/ref-monty/.claude/skills/python-playground/SKILL.md +0 -47
  365. package/ref-monty/.codecov.yml +0 -12
  366. package/ref-monty/.github/actions/build-pgo-wheel/action.yml +0 -72
  367. package/ref-monty/.github/workflows/ci.yml +0 -776
  368. package/ref-monty/.github/workflows/codspeed.yml +0 -45
  369. package/ref-monty/.github/workflows/init-npm-packages.yml +0 -82
  370. package/ref-monty/.pre-commit-config.yaml +0 -47
  371. package/ref-monty/.python-version +0 -1
  372. package/ref-monty/.rustfmt.toml +0 -4
  373. package/ref-monty/.zed/settings.json +0 -11
  374. package/ref-monty/CLAUDE.md +0 -535
  375. package/ref-monty/Cargo.lock +0 -3798
  376. package/ref-monty/Cargo.toml +0 -87
  377. package/ref-monty/LICENSE +0 -21
  378. package/ref-monty/Makefile +0 -216
  379. package/ref-monty/README.md +0 -430
  380. package/ref-monty/RELEASING.md +0 -47
  381. package/ref-monty/crates/fuzz/Cargo.toml +0 -30
  382. package/ref-monty/crates/fuzz/fuzz_targets/string_input_panic.rs +0 -37
  383. package/ref-monty/crates/fuzz/fuzz_targets/tokens_input_panic.rs +0 -552
  384. package/ref-monty/crates/monty/Cargo.toml +0 -68
  385. package/ref-monty/crates/monty/benches/main.rs +0 -247
  386. package/ref-monty/crates/monty/build.rs +0 -10
  387. package/ref-monty/crates/monty/src/args.rs +0 -733
  388. package/ref-monty/crates/monty/src/asyncio.rs +0 -179
  389. package/ref-monty/crates/monty/src/builtins/abs.rs +0 -55
  390. package/ref-monty/crates/monty/src/builtins/all.rs +0 -30
  391. package/ref-monty/crates/monty/src/builtins/any.rs +0 -30
  392. package/ref-monty/crates/monty/src/builtins/bin.rs +0 -59
  393. package/ref-monty/crates/monty/src/builtins/chr.rs +0 -46
  394. package/ref-monty/crates/monty/src/builtins/divmod.rs +0 -164
  395. package/ref-monty/crates/monty/src/builtins/enumerate.rs +0 -52
  396. package/ref-monty/crates/monty/src/builtins/filter.rs +0 -67
  397. package/ref-monty/crates/monty/src/builtins/getattr.rs +0 -65
  398. package/ref-monty/crates/monty/src/builtins/hash.rs +0 -28
  399. package/ref-monty/crates/monty/src/builtins/hex.rs +0 -58
  400. package/ref-monty/crates/monty/src/builtins/id.rs +0 -24
  401. package/ref-monty/crates/monty/src/builtins/isinstance.rs +0 -68
  402. package/ref-monty/crates/monty/src/builtins/len.rs +0 -25
  403. package/ref-monty/crates/monty/src/builtins/map.rs +0 -98
  404. package/ref-monty/crates/monty/src/builtins/min_max.rs +0 -113
  405. package/ref-monty/crates/monty/src/builtins/mod.rs +0 -246
  406. package/ref-monty/crates/monty/src/builtins/next.rs +0 -21
  407. package/ref-monty/crates/monty/src/builtins/oct.rs +0 -59
  408. package/ref-monty/crates/monty/src/builtins/ord.rs +0 -67
  409. package/ref-monty/crates/monty/src/builtins/pow.rs +0 -365
  410. package/ref-monty/crates/monty/src/builtins/print.rs +0 -141
  411. package/ref-monty/crates/monty/src/builtins/repr.rs +0 -16
  412. package/ref-monty/crates/monty/src/builtins/reversed.rs +0 -28
  413. package/ref-monty/crates/monty/src/builtins/round.rs +0 -174
  414. package/ref-monty/crates/monty/src/builtins/sorted.rs +0 -151
  415. package/ref-monty/crates/monty/src/builtins/sum.rs +0 -66
  416. package/ref-monty/crates/monty/src/builtins/type_.rs +0 -16
  417. package/ref-monty/crates/monty/src/builtins/zip.rs +0 -77
  418. package/ref-monty/crates/monty/src/bytecode/builder.rs +0 -699
  419. package/ref-monty/crates/monty/src/bytecode/code.rs +0 -310
  420. package/ref-monty/crates/monty/src/bytecode/compiler.rs +0 -3206
  421. package/ref-monty/crates/monty/src/bytecode/mod.rs +0 -24
  422. package/ref-monty/crates/monty/src/bytecode/op.rs +0 -617
  423. package/ref-monty/crates/monty/src/bytecode/vm/async_exec.rs +0 -1058
  424. package/ref-monty/crates/monty/src/bytecode/vm/attr.rs +0 -63
  425. package/ref-monty/crates/monty/src/bytecode/vm/binary.rs +0 -487
  426. package/ref-monty/crates/monty/src/bytecode/vm/call.rs +0 -767
  427. package/ref-monty/crates/monty/src/bytecode/vm/collections.rs +0 -741
  428. package/ref-monty/crates/monty/src/bytecode/vm/compare.rs +0 -147
  429. package/ref-monty/crates/monty/src/bytecode/vm/exceptions.rs +0 -297
  430. package/ref-monty/crates/monty/src/bytecode/vm/format.rs +0 -132
  431. package/ref-monty/crates/monty/src/bytecode/vm/mod.rs +0 -1958
  432. package/ref-monty/crates/monty/src/bytecode/vm/scheduler.rs +0 -620
  433. package/ref-monty/crates/monty/src/exception_private.rs +0 -1513
  434. package/ref-monty/crates/monty/src/exception_public.rs +0 -346
  435. package/ref-monty/crates/monty/src/expressions.rs +0 -694
  436. package/ref-monty/crates/monty/src/fstring.rs +0 -854
  437. package/ref-monty/crates/monty/src/function.rs +0 -119
  438. package/ref-monty/crates/monty/src/heap.rs +0 -1073
  439. package/ref-monty/crates/monty/src/heap_data.rs +0 -985
  440. package/ref-monty/crates/monty/src/heap_traits.rs +0 -312
  441. package/ref-monty/crates/monty/src/intern.rs +0 -837
  442. package/ref-monty/crates/monty/src/io.rs +0 -106
  443. package/ref-monty/crates/monty/src/lib.rs +0 -52
  444. package/ref-monty/crates/monty/src/modules/asyncio.rs +0 -144
  445. package/ref-monty/crates/monty/src/modules/math.rs +0 -1453
  446. package/ref-monty/crates/monty/src/modules/mod.rs +0 -120
  447. package/ref-monty/crates/monty/src/modules/os.rs +0 -116
  448. package/ref-monty/crates/monty/src/modules/pathlib.rs +0 -33
  449. package/ref-monty/crates/monty/src/modules/re.rs +0 -606
  450. package/ref-monty/crates/monty/src/modules/sys.rs +0 -60
  451. package/ref-monty/crates/monty/src/modules/typing.rs +0 -70
  452. package/ref-monty/crates/monty/src/namespace.rs +0 -21
  453. package/ref-monty/crates/monty/src/object.rs +0 -1040
  454. package/ref-monty/crates/monty/src/os.rs +0 -215
  455. package/ref-monty/crates/monty/src/parse.rs +0 -1730
  456. package/ref-monty/crates/monty/src/prepare.rs +0 -3015
  457. package/ref-monty/crates/monty/src/repl.rs +0 -1109
  458. package/ref-monty/crates/monty/src/resource.rs +0 -559
  459. package/ref-monty/crates/monty/src/run.rs +0 -457
  460. package/ref-monty/crates/monty/src/run_progress.rs +0 -821
  461. package/ref-monty/crates/monty/src/signature.rs +0 -651
  462. package/ref-monty/crates/monty/src/sorting.rs +0 -100
  463. package/ref-monty/crates/monty/src/types/bytes.rs +0 -2356
  464. package/ref-monty/crates/monty/src/types/dataclass.rs +0 -345
  465. package/ref-monty/crates/monty/src/types/dict.rs +0 -879
  466. package/ref-monty/crates/monty/src/types/dict_view.rs +0 -619
  467. package/ref-monty/crates/monty/src/types/iter.rs +0 -799
  468. package/ref-monty/crates/monty/src/types/list.rs +0 -929
  469. package/ref-monty/crates/monty/src/types/long_int.rs +0 -211
  470. package/ref-monty/crates/monty/src/types/mod.rs +0 -48
  471. package/ref-monty/crates/monty/src/types/module.rs +0 -146
  472. package/ref-monty/crates/monty/src/types/namedtuple.rs +0 -261
  473. package/ref-monty/crates/monty/src/types/path.rs +0 -596
  474. package/ref-monty/crates/monty/src/types/property.rs +0 -35
  475. package/ref-monty/crates/monty/src/types/py_trait.rs +0 -322
  476. package/ref-monty/crates/monty/src/types/range.rs +0 -285
  477. package/ref-monty/crates/monty/src/types/re_match.rs +0 -522
  478. package/ref-monty/crates/monty/src/types/re_pattern.rs +0 -726
  479. package/ref-monty/crates/monty/src/types/set.rs +0 -1373
  480. package/ref-monty/crates/monty/src/types/slice.rs +0 -257
  481. package/ref-monty/crates/monty/src/types/str.rs +0 -2051
  482. package/ref-monty/crates/monty/src/types/tuple.rs +0 -376
  483. package/ref-monty/crates/monty/src/types/type.rs +0 -407
  484. package/ref-monty/crates/monty/src/value.rs +0 -2558
  485. package/ref-monty/crates/monty/test_cases/args__dict_get_no_args.py +0 -3
  486. package/ref-monty/crates/monty/test_cases/args__dict_get_too_many.py +0 -3
  487. package/ref-monty/crates/monty/test_cases/args__dict_items_with_args.py +0 -3
  488. package/ref-monty/crates/monty/test_cases/args__dict_keys_with_args.py +0 -3
  489. package/ref-monty/crates/monty/test_cases/args__dict_pop_no_args.py +0 -3
  490. package/ref-monty/crates/monty/test_cases/args__dict_pop_too_many.py +0 -3
  491. package/ref-monty/crates/monty/test_cases/args__dict_values_with_args.py +0 -3
  492. package/ref-monty/crates/monty/test_cases/args__id_too_many.py +0 -2
  493. package/ref-monty/crates/monty/test_cases/args__len_no_args.py +0 -2
  494. package/ref-monty/crates/monty/test_cases/args__len_too_many.py +0 -2
  495. package/ref-monty/crates/monty/test_cases/args__len_type_error_int.py +0 -9
  496. package/ref-monty/crates/monty/test_cases/args__len_type_error_none.py +0 -9
  497. package/ref-monty/crates/monty/test_cases/args__list_append_no_args.py +0 -3
  498. package/ref-monty/crates/monty/test_cases/args__list_append_too_many.py +0 -3
  499. package/ref-monty/crates/monty/test_cases/args__list_insert_too_few.py +0 -3
  500. package/ref-monty/crates/monty/test_cases/args__list_insert_too_many.py +0 -3
  501. package/ref-monty/crates/monty/test_cases/args__repr_no_args.py +0 -2
  502. package/ref-monty/crates/monty/test_cases/arith__div_zero_float.py +0 -2
  503. package/ref-monty/crates/monty/test_cases/arith__div_zero_int.py +0 -2
  504. package/ref-monty/crates/monty/test_cases/arith__floordiv_zero_float.py +0 -2
  505. package/ref-monty/crates/monty/test_cases/arith__floordiv_zero_int.py +0 -2
  506. package/ref-monty/crates/monty/test_cases/arith__pow_zero_neg.py +0 -2
  507. package/ref-monty/crates/monty/test_cases/arith__pow_zero_neg_builtin.py +0 -9
  508. package/ref-monty/crates/monty/test_cases/assert__expr_fail.py +0 -2
  509. package/ref-monty/crates/monty/test_cases/assert__fail.py +0 -2
  510. package/ref-monty/crates/monty/test_cases/assert__fail_msg.py +0 -2
  511. package/ref-monty/crates/monty/test_cases/assert__fn_fail.py +0 -3
  512. package/ref-monty/crates/monty/test_cases/assert__ops.py +0 -11
  513. package/ref-monty/crates/monty/test_cases/async__asyncio_run.py +0 -47
  514. package/ref-monty/crates/monty/test_cases/async__basic.py +0 -10
  515. package/ref-monty/crates/monty/test_cases/async__closure.py +0 -14
  516. package/ref-monty/crates/monty/test_cases/async__double_await_coroutine.py +0 -16
  517. package/ref-monty/crates/monty/test_cases/async__exception.py +0 -10
  518. package/ref-monty/crates/monty/test_cases/async__ext_call.py +0 -73
  519. package/ref-monty/crates/monty/test_cases/async__gather_all.py +0 -85
  520. package/ref-monty/crates/monty/test_cases/async__nested_await.py +0 -15
  521. package/ref-monty/crates/monty/test_cases/async__nested_gather_ext.py +0 -37
  522. package/ref-monty/crates/monty/test_cases/async__not_awaitable.py +0 -10
  523. package/ref-monty/crates/monty/test_cases/async__not_imported.py +0 -14
  524. package/ref-monty/crates/monty/test_cases/async__recursion_depth_isolation.py +0 -27
  525. package/ref-monty/crates/monty/test_cases/async__return_types.py +0 -31
  526. package/ref-monty/crates/monty/test_cases/async__sequential.py +0 -16
  527. package/ref-monty/crates/monty/test_cases/async__traceback.py +0 -19
  528. package/ref-monty/crates/monty/test_cases/async__with_args.py +0 -14
  529. package/ref-monty/crates/monty/test_cases/attr__get_int_error.py +0 -9
  530. package/ref-monty/crates/monty/test_cases/attr__get_list_error.py +0 -9
  531. package/ref-monty/crates/monty/test_cases/attr__set_frozen_nonfield.py +0 -12
  532. package/ref-monty/crates/monty/test_cases/attr__set_int_error.py +0 -10
  533. package/ref-monty/crates/monty/test_cases/attr__set_list_error.py +0 -10
  534. package/ref-monty/crates/monty/test_cases/bench__kitchen_sink.py +0 -68
  535. package/ref-monty/crates/monty/test_cases/bool__ops.py +0 -20
  536. package/ref-monty/crates/monty/test_cases/builtin__add_type_error.py +0 -2
  537. package/ref-monty/crates/monty/test_cases/builtin__filter.py +0 -62
  538. package/ref-monty/crates/monty/test_cases/builtin__filter_not_iterable.py +0 -11
  539. package/ref-monty/crates/monty/test_cases/builtin__getattr.py +0 -84
  540. package/ref-monty/crates/monty/test_cases/builtin__iter_funcs.py +0 -42
  541. package/ref-monty/crates/monty/test_cases/builtin__iter_next.py +0 -66
  542. package/ref-monty/crates/monty/test_cases/builtin__map.py +0 -74
  543. package/ref-monty/crates/monty/test_cases/builtin__map_not_iterable.py +0 -11
  544. package/ref-monty/crates/monty/test_cases/builtin__math_funcs.py +0 -154
  545. package/ref-monty/crates/monty/test_cases/builtin__more_iter_funcs.py +0 -148
  546. package/ref-monty/crates/monty/test_cases/builtin__next_stop_iteration.py +0 -10
  547. package/ref-monty/crates/monty/test_cases/builtin__print_invalid_kwarg.py +0 -9
  548. package/ref-monty/crates/monty/test_cases/builtin__print_kwargs.py +0 -12
  549. package/ref-monty/crates/monty/test_cases/builtin__repr.py +0 -3
  550. package/ref-monty/crates/monty/test_cases/builtin__string_funcs.py +0 -73
  551. package/ref-monty/crates/monty/test_cases/bytes__decode_invalid_utf8.py +0 -18
  552. package/ref-monty/crates/monty/test_cases/bytes__endswith_str_error.py +0 -10
  553. package/ref-monty/crates/monty/test_cases/bytes__getitem_index_error.py +0 -10
  554. package/ref-monty/crates/monty/test_cases/bytes__index_start_gt_end.py +0 -10
  555. package/ref-monty/crates/monty/test_cases/bytes__methods.py +0 -394
  556. package/ref-monty/crates/monty/test_cases/bytes__negative_count.py +0 -9
  557. package/ref-monty/crates/monty/test_cases/bytes__ops.py +0 -90
  558. package/ref-monty/crates/monty/test_cases/bytes__startswith_str_error.py +0 -10
  559. package/ref-monty/crates/monty/test_cases/call_object.py +0 -3
  560. package/ref-monty/crates/monty/test_cases/chain_comparison__all.py +0 -79
  561. package/ref-monty/crates/monty/test_cases/closure__param_shadows_outer.py +0 -81
  562. package/ref-monty/crates/monty/test_cases/closure__pep448.py +0 -203
  563. package/ref-monty/crates/monty/test_cases/closure__undefined_nonlocal.py +0 -13
  564. package/ref-monty/crates/monty/test_cases/compare__mixed_types.py +0 -120
  565. package/ref-monty/crates/monty/test_cases/comprehension__all.py +0 -208
  566. package/ref-monty/crates/monty/test_cases/comprehension__scope.py +0 -7
  567. package/ref-monty/crates/monty/test_cases/comprehension__unbound_local.py +0 -14
  568. package/ref-monty/crates/monty/test_cases/dataclass__basic.py +0 -238
  569. package/ref-monty/crates/monty/test_cases/dataclass__call_field_error.py +0 -12
  570. package/ref-monty/crates/monty/test_cases/dataclass__frozen_set_error.py +0 -12
  571. package/ref-monty/crates/monty/test_cases/dataclass__get_missing_attr_error.py +0 -11
  572. package/ref-monty/crates/monty/test_cases/dict__get_unhashable_key.py +0 -3
  573. package/ref-monty/crates/monty/test_cases/dict__literal_unhashable_key.py +0 -2
  574. package/ref-monty/crates/monty/test_cases/dict__method_pop_missing_error.py +0 -3
  575. package/ref-monty/crates/monty/test_cases/dict__methods.py +0 -151
  576. package/ref-monty/crates/monty/test_cases/dict__ops.py +0 -133
  577. package/ref-monty/crates/monty/test_cases/dict__pop_unhashable_key.py +0 -4
  578. package/ref-monty/crates/monty/test_cases/dict__popitem_empty.py +0 -9
  579. package/ref-monty/crates/monty/test_cases/dict__subscript_missing_key.py +0 -3
  580. package/ref-monty/crates/monty/test_cases/dict__unhashable_dict_key.py +0 -2
  581. package/ref-monty/crates/monty/test_cases/dict__unhashable_list_key.py +0 -2
  582. package/ref-monty/crates/monty/test_cases/dict__unpack_type_error.py +0 -2
  583. package/ref-monty/crates/monty/test_cases/dict__views.py +0 -165
  584. package/ref-monty/crates/monty/test_cases/edge__all.py +0 -26
  585. package/ref-monty/crates/monty/test_cases/edge__float_int_mod.py +0 -2
  586. package/ref-monty/crates/monty/test_cases/edge__int_float_mod.py +0 -2
  587. package/ref-monty/crates/monty/test_cases/exc__args.py +0 -16
  588. package/ref-monty/crates/monty/test_cases/exc__str.py +0 -15
  589. package/ref-monty/crates/monty/test_cases/execute_ok__all.py +0 -54
  590. package/ref-monty/crates/monty/test_cases/execute_raise__error_instance_str.py +0 -2
  591. package/ref-monty/crates/monty/test_cases/execute_raise__error_no_args.py +0 -2
  592. package/ref-monty/crates/monty/test_cases/execute_raise__error_string_arg.py +0 -2
  593. package/ref-monty/crates/monty/test_cases/execute_raise__error_string_arg_quotes.py +0 -2
  594. package/ref-monty/crates/monty/test_cases/execute_raise__error_type.py +0 -2
  595. package/ref-monty/crates/monty/test_cases/execute_raise__raise_instance_via_var.py +0 -4
  596. package/ref-monty/crates/monty/test_cases/execute_raise__raise_list.py +0 -2
  597. package/ref-monty/crates/monty/test_cases/execute_raise__raise_number.py +0 -2
  598. package/ref-monty/crates/monty/test_cases/execute_raise__raise_type_call_via_var.py +0 -4
  599. package/ref-monty/crates/monty/test_cases/execute_raise__raise_type_direct.py +0 -3
  600. package/ref-monty/crates/monty/test_cases/execute_raise__raise_type_via_var.py +0 -4
  601. package/ref-monty/crates/monty/test_cases/ext_call__arg_side_effect_bug.py +0 -22
  602. package/ref-monty/crates/monty/test_cases/ext_call__augmented.py +0 -17
  603. package/ref-monty/crates/monty/test_cases/ext_call__augmented_refcount_bug.py +0 -7
  604. package/ref-monty/crates/monty/test_cases/ext_call__bare_raise_after_resume.py +0 -34
  605. package/ref-monty/crates/monty/test_cases/ext_call__basic.py +0 -99
  606. package/ref-monty/crates/monty/test_cases/ext_call__boolean.py +0 -37
  607. package/ref-monty/crates/monty/test_cases/ext_call__boolean_side_effect_hang.py +0 -17
  608. package/ref-monty/crates/monty/test_cases/ext_call__closure_bug.py +0 -16
  609. package/ref-monty/crates/monty/test_cases/ext_call__comparison.py +0 -26
  610. package/ref-monty/crates/monty/test_cases/ext_call__deep_call_stack.py +0 -18
  611. package/ref-monty/crates/monty/test_cases/ext_call__elif.py +0 -171
  612. package/ref-monty/crates/monty/test_cases/ext_call__exc.py +0 -4
  613. package/ref-monty/crates/monty/test_cases/ext_call__exc_deep_stack.py +0 -39
  614. package/ref-monty/crates/monty/test_cases/ext_call__exc_in_function.py +0 -17
  615. package/ref-monty/crates/monty/test_cases/ext_call__exc_nested_functions.py +0 -31
  616. package/ref-monty/crates/monty/test_cases/ext_call__ext_exc.py +0 -171
  617. package/ref-monty/crates/monty/test_cases/ext_call__for.py +0 -114
  618. package/ref-monty/crates/monty/test_cases/ext_call__fstring.py +0 -12
  619. package/ref-monty/crates/monty/test_cases/ext_call__if.py +0 -135
  620. package/ref-monty/crates/monty/test_cases/ext_call__if_condition.py +0 -37
  621. package/ref-monty/crates/monty/test_cases/ext_call__in_closure.py +0 -14
  622. package/ref-monty/crates/monty/test_cases/ext_call__in_function.py +0 -40
  623. package/ref-monty/crates/monty/test_cases/ext_call__in_function_simple.py +0 -7
  624. package/ref-monty/crates/monty/test_cases/ext_call__literals.py +0 -17
  625. package/ref-monty/crates/monty/test_cases/ext_call__multi_in_func.py +0 -32
  626. package/ref-monty/crates/monty/test_cases/ext_call__name_lookup.py +0 -69
  627. package/ref-monty/crates/monty/test_cases/ext_call__name_lookup_undefined.py +0 -4
  628. package/ref-monty/crates/monty/test_cases/ext_call__nested_calls.py +0 -14
  629. package/ref-monty/crates/monty/test_cases/ext_call__recursion_bug.py +0 -19
  630. package/ref-monty/crates/monty/test_cases/ext_call__return.py +0 -28
  631. package/ref-monty/crates/monty/test_cases/ext_call__side_effects.py +0 -25
  632. package/ref-monty/crates/monty/test_cases/ext_call__subscript.py +0 -7
  633. package/ref-monty/crates/monty/test_cases/ext_call__ternary.py +0 -28
  634. package/ref-monty/crates/monty/test_cases/ext_call__try.py +0 -280
  635. package/ref-monty/crates/monty/test_cases/ext_call__try_simple.py +0 -10
  636. package/ref-monty/crates/monty/test_cases/ext_call__unary.py +0 -13
  637. package/ref-monty/crates/monty/test_cases/frozenset__ops.py +0 -178
  638. package/ref-monty/crates/monty/test_cases/fstring__all.py +0 -236
  639. package/ref-monty/crates/monty/test_cases/fstring__error_eq_align_on_str.py +0 -3
  640. package/ref-monty/crates/monty/test_cases/fstring__error_float_f_on_str.py +0 -3
  641. package/ref-monty/crates/monty/test_cases/fstring__error_int_d_on_float.py +0 -3
  642. package/ref-monty/crates/monty/test_cases/fstring__error_int_d_on_str.py +0 -3
  643. package/ref-monty/crates/monty/test_cases/fstring__error_invalid_spec.py +0 -4
  644. package/ref-monty/crates/monty/test_cases/fstring__error_invalid_spec_dynamic.py +0 -4
  645. package/ref-monty/crates/monty/test_cases/fstring__error_invalid_spec_str.py +0 -4
  646. package/ref-monty/crates/monty/test_cases/fstring__error_str_s_on_int.py +0 -3
  647. package/ref-monty/crates/monty/test_cases/function__call_duplicate_kwargs.py +0 -6
  648. package/ref-monty/crates/monty/test_cases/function__call_unpack.py +0 -42
  649. package/ref-monty/crates/monty/test_cases/function__defaults.py +0 -117
  650. package/ref-monty/crates/monty/test_cases/function__err_duplicate_arg.py +0 -7
  651. package/ref-monty/crates/monty/test_cases/function__err_duplicate_first_arg.py +0 -7
  652. package/ref-monty/crates/monty/test_cases/function__err_duplicate_kwarg_cleanup.py +0 -9
  653. package/ref-monty/crates/monty/test_cases/function__err_kwonly_as_positional.py +0 -7
  654. package/ref-monty/crates/monty/test_cases/function__err_missing_all_posonly.py +0 -7
  655. package/ref-monty/crates/monty/test_cases/function__err_missing_heap_cleanup.py +0 -9
  656. package/ref-monty/crates/monty/test_cases/function__err_missing_kwonly.py +0 -7
  657. package/ref-monty/crates/monty/test_cases/function__err_missing_posonly_with_kwarg.py +0 -7
  658. package/ref-monty/crates/monty/test_cases/function__err_missing_with_posonly.py +0 -7
  659. package/ref-monty/crates/monty/test_cases/function__err_posonly_as_kwarg.py +0 -7
  660. package/ref-monty/crates/monty/test_cases/function__err_posonly_first_as_kwarg.py +0 -7
  661. package/ref-monty/crates/monty/test_cases/function__err_too_many_posonly.py +0 -7
  662. package/ref-monty/crates/monty/test_cases/function__err_too_many_with_kwonly.py +0 -7
  663. package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg.py +0 -7
  664. package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg_cleanup.py +0 -9
  665. package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg_quote.py +0 -13
  666. package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg_simple.py +0 -7
  667. package/ref-monty/crates/monty/test_cases/function__err_unpack_duplicate_arg.py +0 -6
  668. package/ref-monty/crates/monty/test_cases/function__err_unpack_duplicate_heap.py +0 -8
  669. package/ref-monty/crates/monty/test_cases/function__err_unpack_int.py +0 -6
  670. package/ref-monty/crates/monty/test_cases/function__err_unpack_nonstring_key.py +0 -6
  671. package/ref-monty/crates/monty/test_cases/function__err_unpack_not_mapping.py +0 -6
  672. package/ref-monty/crates/monty/test_cases/function__kwargs_unpacking.py +0 -173
  673. package/ref-monty/crates/monty/test_cases/function__ops.py +0 -294
  674. package/ref-monty/crates/monty/test_cases/function__return_none.py +0 -42
  675. package/ref-monty/crates/monty/test_cases/function__signatures.py +0 -47
  676. package/ref-monty/crates/monty/test_cases/function__too_few_args_all.py +0 -6
  677. package/ref-monty/crates/monty/test_cases/function__too_few_args_one.py +0 -6
  678. package/ref-monty/crates/monty/test_cases/function__too_few_args_two.py +0 -6
  679. package/ref-monty/crates/monty/test_cases/function__too_many_args_one.py +0 -6
  680. package/ref-monty/crates/monty/test_cases/function__too_many_args_two.py +0 -6
  681. package/ref-monty/crates/monty/test_cases/function__too_many_args_zero.py +0 -6
  682. package/ref-monty/crates/monty/test_cases/global__error_assigned_before.py +0 -7
  683. package/ref-monty/crates/monty/test_cases/global__ops.py +0 -163
  684. package/ref-monty/crates/monty/test_cases/hash__dict_unhashable.py +0 -2
  685. package/ref-monty/crates/monty/test_cases/hash__list_unhashable.py +0 -2
  686. package/ref-monty/crates/monty/test_cases/hash__ops.py +0 -153
  687. package/ref-monty/crates/monty/test_cases/id__bytes_literals_distinct.py +0 -3
  688. package/ref-monty/crates/monty/test_cases/id__int_copy_distinct.py +0 -5
  689. package/ref-monty/crates/monty/test_cases/id__is_number_is_number.py +0 -3
  690. package/ref-monty/crates/monty/test_cases/id__non_overlapping_lifetimes_distinct_types.py +0 -10
  691. package/ref-monty/crates/monty/test_cases/id__non_overlapping_lifetimes_same_types.py +0 -6
  692. package/ref-monty/crates/monty/test_cases/id__ops.py +0 -97
  693. package/ref-monty/crates/monty/test_cases/id__str_literals_same.py +0 -3
  694. package/ref-monty/crates/monty/test_cases/if__elif_else.py +0 -207
  695. package/ref-monty/crates/monty/test_cases/if__raise_elif.py +0 -11
  696. package/ref-monty/crates/monty/test_cases/if__raise_else.py +0 -13
  697. package/ref-monty/crates/monty/test_cases/if__raise_if.py +0 -9
  698. package/ref-monty/crates/monty/test_cases/if__raise_in_elif_condition.py +0 -18
  699. package/ref-monty/crates/monty/test_cases/if__raise_in_if_condition.py +0 -16
  700. package/ref-monty/crates/monty/test_cases/if_else_expr__all.py +0 -55
  701. package/ref-monty/crates/monty/test_cases/import__error_cannot_import.py +0 -9
  702. package/ref-monty/crates/monty/test_cases/import__error_module_not_found.py +0 -9
  703. package/ref-monty/crates/monty/test_cases/import__local_scope.py +0 -68
  704. package/ref-monty/crates/monty/test_cases/import__os.py +0 -25
  705. package/ref-monty/crates/monty/test_cases/import__relative_error.py +0 -9
  706. package/ref-monty/crates/monty/test_cases/import__relative_no_module_error.py +0 -9
  707. package/ref-monty/crates/monty/test_cases/import__runtime_error_when_executed.py +0 -14
  708. package/ref-monty/crates/monty/test_cases/import__star_error.py +0 -11
  709. package/ref-monty/crates/monty/test_cases/import__sys.py +0 -47
  710. package/ref-monty/crates/monty/test_cases/import__sys_monty.py +0 -28
  711. package/ref-monty/crates/monty/test_cases/import__type_checking_guard.py +0 -37
  712. package/ref-monty/crates/monty/test_cases/import__typing.py +0 -25
  713. package/ref-monty/crates/monty/test_cases/import__typing_type_ignore.py +0 -4
  714. package/ref-monty/crates/monty/test_cases/int__bigint.py +0 -467
  715. package/ref-monty/crates/monty/test_cases/int__bigint_errors.py +0 -260
  716. package/ref-monty/crates/monty/test_cases/int__ops.py +0 -219
  717. package/ref-monty/crates/monty/test_cases/int__overflow_division.py +0 -84
  718. package/ref-monty/crates/monty/test_cases/is_variant__all.py +0 -36
  719. package/ref-monty/crates/monty/test_cases/isinstance__arg2_list_error.py +0 -2
  720. package/ref-monty/crates/monty/test_cases/isinstance__arg2_type_error.py +0 -2
  721. package/ref-monty/crates/monty/test_cases/iter__dict_mutation.py +0 -4
  722. package/ref-monty/crates/monty/test_cases/iter__for.py +0 -243
  723. package/ref-monty/crates/monty/test_cases/iter__for_loop_unpacking.py +0 -66
  724. package/ref-monty/crates/monty/test_cases/iter__generator_expr.py +0 -20
  725. package/ref-monty/crates/monty/test_cases/iter__generator_expr_type.py +0 -7
  726. package/ref-monty/crates/monty/test_cases/iter__not_iterable.py +0 -3
  727. package/ref-monty/crates/monty/test_cases/lambda__all.py +0 -145
  728. package/ref-monty/crates/monty/test_cases/list__extend_not_iterable.py +0 -7
  729. package/ref-monty/crates/monty/test_cases/list__getitem_out_of_bounds.py +0 -3
  730. package/ref-monty/crates/monty/test_cases/list__index_not_found.py +0 -9
  731. package/ref-monty/crates/monty/test_cases/list__index_start_gt_end.py +0 -10
  732. package/ref-monty/crates/monty/test_cases/list__ops.py +0 -473
  733. package/ref-monty/crates/monty/test_cases/list__pop_empty.py +0 -9
  734. package/ref-monty/crates/monty/test_cases/list__pop_out_of_range.py +0 -9
  735. package/ref-monty/crates/monty/test_cases/list__pop_type_error.py +0 -9
  736. package/ref-monty/crates/monty/test_cases/list__remove_not_found.py +0 -9
  737. package/ref-monty/crates/monty/test_cases/list__setitem_dict_index.py +0 -13
  738. package/ref-monty/crates/monty/test_cases/list__setitem_huge_int_index.py +0 -13
  739. package/ref-monty/crates/monty/test_cases/list__setitem_index_error.py +0 -10
  740. package/ref-monty/crates/monty/test_cases/list__setitem_type_error.py +0 -10
  741. package/ref-monty/crates/monty/test_cases/list__unpack_type_error.py +0 -2
  742. package/ref-monty/crates/monty/test_cases/longint__index_error.py +0 -3
  743. package/ref-monty/crates/monty/test_cases/longint__repeat_error.py +0 -3
  744. package/ref-monty/crates/monty/test_cases/loop__break_continue.py +0 -113
  745. package/ref-monty/crates/monty/test_cases/loop__break_finally.py +0 -69
  746. package/ref-monty/crates/monty/test_cases/loop__break_in_function_error.py +0 -13
  747. package/ref-monty/crates/monty/test_cases/loop__break_in_if_error.py +0 -11
  748. package/ref-monty/crates/monty/test_cases/loop__break_nested_except_clears.py +0 -55
  749. package/ref-monty/crates/monty/test_cases/loop__break_outside_error.py +0 -9
  750. package/ref-monty/crates/monty/test_cases/loop__continue_finally.py +0 -81
  751. package/ref-monty/crates/monty/test_cases/loop__continue_in_function_error.py +0 -13
  752. package/ref-monty/crates/monty/test_cases/loop__continue_in_if_error.py +0 -11
  753. package/ref-monty/crates/monty/test_cases/loop__continue_nested_except_clears.py +0 -60
  754. package/ref-monty/crates/monty/test_cases/loop__continue_outside_error.py +0 -9
  755. package/ref-monty/crates/monty/test_cases/math__acos_domain_error.py +0 -11
  756. package/ref-monty/crates/monty/test_cases/math__acosh_domain_error.py +0 -11
  757. package/ref-monty/crates/monty/test_cases/math__asin_domain_error.py +0 -11
  758. package/ref-monty/crates/monty/test_cases/math__atanh_domain_error.py +0 -11
  759. package/ref-monty/crates/monty/test_cases/math__cos_inf_error.py +0 -11
  760. package/ref-monty/crates/monty/test_cases/math__cosh_overflow_error.py +0 -11
  761. package/ref-monty/crates/monty/test_cases/math__exp_overflow_error.py +0 -11
  762. package/ref-monty/crates/monty/test_cases/math__factorial_float_error.py +0 -11
  763. package/ref-monty/crates/monty/test_cases/math__factorial_negative_error.py +0 -11
  764. package/ref-monty/crates/monty/test_cases/math__floor_inf_error.py +0 -11
  765. package/ref-monty/crates/monty/test_cases/math__floor_nan_error.py +0 -11
  766. package/ref-monty/crates/monty/test_cases/math__floor_str_error.py +0 -11
  767. package/ref-monty/crates/monty/test_cases/math__fmod_inf_error.py +0 -11
  768. package/ref-monty/crates/monty/test_cases/math__gamma_neg_int_error.py +0 -11
  769. package/ref-monty/crates/monty/test_cases/math__gcd_float_error.py +0 -11
  770. package/ref-monty/crates/monty/test_cases/math__isqrt_negative_error.py +0 -11
  771. package/ref-monty/crates/monty/test_cases/math__ldexp_overflow_error.py +0 -11
  772. package/ref-monty/crates/monty/test_cases/math__log1p_domain_error.py +0 -11
  773. package/ref-monty/crates/monty/test_cases/math__log_base1_error.py +0 -11
  774. package/ref-monty/crates/monty/test_cases/math__log_zero_error.py +0 -11
  775. package/ref-monty/crates/monty/test_cases/math__module.py +0 -1432
  776. package/ref-monty/crates/monty/test_cases/math__pow_domain_error.py +0 -11
  777. package/ref-monty/crates/monty/test_cases/math__sin_inf_error.py +0 -11
  778. package/ref-monty/crates/monty/test_cases/math__sqrt_negative_error.py +0 -11
  779. package/ref-monty/crates/monty/test_cases/math__tan_inf_error.py +0 -11
  780. package/ref-monty/crates/monty/test_cases/math__trunc_str_error.py +0 -11
  781. package/ref-monty/crates/monty/test_cases/method__args_kwargs_unpacking.py +0 -259
  782. package/ref-monty/crates/monty/test_cases/name_error__unbound_local_func.py +0 -19
  783. package/ref-monty/crates/monty/test_cases/name_error__unbound_local_module.py +0 -12
  784. package/ref-monty/crates/monty/test_cases/name_error__undefined_call_chained.py +0 -9
  785. package/ref-monty/crates/monty/test_cases/name_error__undefined_call_in_expr.py +0 -9
  786. package/ref-monty/crates/monty/test_cases/name_error__undefined_call_in_function.py +0 -16
  787. package/ref-monty/crates/monty/test_cases/name_error__undefined_call_with_args.py +0 -9
  788. package/ref-monty/crates/monty/test_cases/name_error__undefined_global.py +0 -10
  789. package/ref-monty/crates/monty/test_cases/namedtuple__missing_attr.py +0 -11
  790. package/ref-monty/crates/monty/test_cases/namedtuple__ops.py +0 -34
  791. package/ref-monty/crates/monty/test_cases/nonlocal__error_module_level.py +0 -3
  792. package/ref-monty/crates/monty/test_cases/nonlocal__ops.py +0 -353
  793. package/ref-monty/crates/monty/test_cases/os__environ.py +0 -40
  794. package/ref-monty/crates/monty/test_cases/os__getenv_key_list_error.py +0 -5
  795. package/ref-monty/crates/monty/test_cases/os__getenv_key_type_error.py +0 -5
  796. package/ref-monty/crates/monty/test_cases/parse_error__complex.py +0 -3
  797. package/ref-monty/crates/monty/test_cases/pathlib__import.py +0 -11
  798. package/ref-monty/crates/monty/test_cases/pathlib__os.py +0 -136
  799. package/ref-monty/crates/monty/test_cases/pathlib__os_read_error.py +0 -12
  800. package/ref-monty/crates/monty/test_cases/pathlib__pure.py +0 -81
  801. package/ref-monty/crates/monty/test_cases/pyobject__cycle_dict_self.py +0 -5
  802. package/ref-monty/crates/monty/test_cases/pyobject__cycle_list_dict.py +0 -6
  803. package/ref-monty/crates/monty/test_cases/pyobject__cycle_list_self.py +0 -5
  804. package/ref-monty/crates/monty/test_cases/pyobject__cycle_multiple_refs.py +0 -6
  805. package/ref-monty/crates/monty/test_cases/range__error_no_args.py +0 -2
  806. package/ref-monty/crates/monty/test_cases/range__error_step_zero.py +0 -2
  807. package/ref-monty/crates/monty/test_cases/range__error_too_many_args.py +0 -2
  808. package/ref-monty/crates/monty/test_cases/range__getitem_index_error.py +0 -10
  809. package/ref-monty/crates/monty/test_cases/range__ops.py +0 -236
  810. package/ref-monty/crates/monty/test_cases/re__basic.py +0 -756
  811. package/ref-monty/crates/monty/test_cases/re__grouping.py +0 -241
  812. package/ref-monty/crates/monty/test_cases/re__match.py +0 -148
  813. package/ref-monty/crates/monty/test_cases/recursion__deep_drop.py +0 -26
  814. package/ref-monty/crates/monty/test_cases/recursion__deep_eq.py +0 -23
  815. package/ref-monty/crates/monty/test_cases/recursion__deep_hash.py +0 -46
  816. package/ref-monty/crates/monty/test_cases/recursion__deep_repr.py +0 -12
  817. package/ref-monty/crates/monty/test_cases/recursion__function_depth.py +0 -13
  818. package/ref-monty/crates/monty/test_cases/refcount__cycle_mutual_reference.py +0 -18
  819. package/ref-monty/crates/monty/test_cases/refcount__cycle_self_reference.py +0 -12
  820. package/ref-monty/crates/monty/test_cases/refcount__dict_basic.py +0 -5
  821. package/ref-monty/crates/monty/test_cases/refcount__dict_get.py +0 -5
  822. package/ref-monty/crates/monty/test_cases/refcount__dict_keys_and.py +0 -14
  823. package/ref-monty/crates/monty/test_cases/refcount__dict_overwrite.py +0 -6
  824. package/ref-monty/crates/monty/test_cases/refcount__gather_cleanup.py +0 -16
  825. package/ref-monty/crates/monty/test_cases/refcount__gather_exception.py +0 -18
  826. package/ref-monty/crates/monty/test_cases/refcount__gather_nested_cancel.py +0 -25
  827. package/ref-monty/crates/monty/test_cases/refcount__immediate_skipped.py +0 -4
  828. package/ref-monty/crates/monty/test_cases/refcount__kwargs_unpacking.py +0 -27
  829. package/ref-monty/crates/monty/test_cases/refcount__list_append_multiple.py +0 -6
  830. package/ref-monty/crates/monty/test_cases/refcount__list_append_ref.py +0 -5
  831. package/ref-monty/crates/monty/test_cases/refcount__list_concat.py +0 -5
  832. package/ref-monty/crates/monty/test_cases/refcount__list_getitem.py +0 -5
  833. package/ref-monty/crates/monty/test_cases/refcount__list_iadd.py +0 -5
  834. package/ref-monty/crates/monty/test_cases/refcount__nested_list.py +0 -4
  835. package/ref-monty/crates/monty/test_cases/refcount__re_pattern_sub_error_paths.py +0 -37
  836. package/ref-monty/crates/monty/test_cases/refcount__re_search_match.py +0 -34
  837. package/ref-monty/crates/monty/test_cases/refcount__re_sub_error_paths.py +0 -31
  838. package/ref-monty/crates/monty/test_cases/refcount__shared_reference.py +0 -4
  839. package/ref-monty/crates/monty/test_cases/refcount__single_list.py +0 -3
  840. package/ref-monty/crates/monty/test_cases/repr__cycle_detection.py +0 -24
  841. package/ref-monty/crates/monty/test_cases/set__ops.py +0 -191
  842. package/ref-monty/crates/monty/test_cases/set__review_bugs.py +0 -35
  843. package/ref-monty/crates/monty/test_cases/set__unpack_type_error.py +0 -2
  844. package/ref-monty/crates/monty/test_cases/slice__invalid_indices.py +0 -2
  845. package/ref-monty/crates/monty/test_cases/slice__kwargs.py +0 -9
  846. package/ref-monty/crates/monty/test_cases/slice__no_args.py +0 -9
  847. package/ref-monty/crates/monty/test_cases/slice__ops.py +0 -149
  848. package/ref-monty/crates/monty/test_cases/slice__step_zero.py +0 -9
  849. package/ref-monty/crates/monty/test_cases/slice__step_zero_bytes.py +0 -9
  850. package/ref-monty/crates/monty/test_cases/slice__step_zero_range.py +0 -9
  851. package/ref-monty/crates/monty/test_cases/slice__step_zero_str.py +0 -9
  852. package/ref-monty/crates/monty/test_cases/slice__step_zero_tuple.py +0 -9
  853. package/ref-monty/crates/monty/test_cases/slice__too_many_args.py +0 -9
  854. package/ref-monty/crates/monty/test_cases/str__getitem_index_error.py +0 -10
  855. package/ref-monty/crates/monty/test_cases/str__index_not_found.py +0 -9
  856. package/ref-monty/crates/monty/test_cases/str__join_no_args.py +0 -9
  857. package/ref-monty/crates/monty/test_cases/str__join_non_string.py +0 -9
  858. package/ref-monty/crates/monty/test_cases/str__join_not_iterable.py +0 -9
  859. package/ref-monty/crates/monty/test_cases/str__join_too_many_args.py +0 -9
  860. package/ref-monty/crates/monty/test_cases/str__methods.py +0 -327
  861. package/ref-monty/crates/monty/test_cases/str__ops.py +0 -162
  862. package/ref-monty/crates/monty/test_cases/str__partition_empty.py +0 -9
  863. package/ref-monty/crates/monty/test_cases/str__rsplit_empty_sep.py +0 -9
  864. package/ref-monty/crates/monty/test_cases/str__split_empty_sep.py +0 -9
  865. package/ref-monty/crates/monty/test_cases/sys__types.py +0 -7
  866. package/ref-monty/crates/monty/test_cases/traceback__division_error.py +0 -30
  867. package/ref-monty/crates/monty/test_cases/traceback__index_error.py +0 -17
  868. package/ref-monty/crates/monty/test_cases/traceback__insert_as_int.py +0 -10
  869. package/ref-monty/crates/monty/test_cases/traceback__nested_call.py +0 -29
  870. package/ref-monty/crates/monty/test_cases/traceback__nonlocal_module_scope.py +0 -10
  871. package/ref-monty/crates/monty/test_cases/traceback__nonlocal_unbound.py +0 -24
  872. package/ref-monty/crates/monty/test_cases/traceback__range_as_int.py +0 -9
  873. package/ref-monty/crates/monty/test_cases/traceback__recursion_error.py +0 -23
  874. package/ref-monty/crates/monty/test_cases/traceback__set_mutation.py +0 -11
  875. package/ref-monty/crates/monty/test_cases/traceback__undefined_attr_call.py +0 -16
  876. package/ref-monty/crates/monty/test_cases/traceback__undefined_call.py +0 -16
  877. package/ref-monty/crates/monty/test_cases/traceback__undefined_raise.py +0 -16
  878. package/ref-monty/crates/monty/test_cases/try_except__all.py +0 -472
  879. package/ref-monty/crates/monty/test_cases/try_except__bare_raise_no_context.py +0 -2
  880. package/ref-monty/crates/monty/test_cases/try_except__invalid_type.py +0 -5
  881. package/ref-monty/crates/monty/test_cases/tuple__getitem_out_of_bounds.py +0 -3
  882. package/ref-monty/crates/monty/test_cases/tuple__index_not_found.py +0 -9
  883. package/ref-monty/crates/monty/test_cases/tuple__index_start_gt_end.py +0 -10
  884. package/ref-monty/crates/monty/test_cases/tuple__methods.py +0 -19
  885. package/ref-monty/crates/monty/test_cases/tuple__ops.py +0 -133
  886. package/ref-monty/crates/monty/test_cases/tuple__unpack_type_error.py +0 -2
  887. package/ref-monty/crates/monty/test_cases/type__builtin_attr_error.py +0 -9
  888. package/ref-monty/crates/monty/test_cases/type__bytes_negative.py +0 -2
  889. package/ref-monty/crates/monty/test_cases/type__cell_not_builtin.py +0 -9
  890. package/ref-monty/crates/monty/test_cases/type__exception_attr_error.py +0 -11
  891. package/ref-monty/crates/monty/test_cases/type__float_conversion_error.py +0 -2
  892. package/ref-monty/crates/monty/test_cases/type__float_repr_both_quotes.py +0 -9
  893. package/ref-monty/crates/monty/test_cases/type__float_repr_newline.py +0 -9
  894. package/ref-monty/crates/monty/test_cases/type__float_repr_single_quote.py +0 -9
  895. package/ref-monty/crates/monty/test_cases/type__int_conversion_error.py +0 -2
  896. package/ref-monty/crates/monty/test_cases/type__list_not_iterable.py +0 -2
  897. package/ref-monty/crates/monty/test_cases/type__non_builtin_name_error.py +0 -9
  898. package/ref-monty/crates/monty/test_cases/type__ops.py +0 -200
  899. package/ref-monty/crates/monty/test_cases/type__shadow_exc.py +0 -3
  900. package/ref-monty/crates/monty/test_cases/type__shadow_int.py +0 -9
  901. package/ref-monty/crates/monty/test_cases/type__shadow_len.py +0 -3
  902. package/ref-monty/crates/monty/test_cases/type__tuple_not_iterable.py +0 -2
  903. package/ref-monty/crates/monty/test_cases/type_error__int_add_list.py +0 -2
  904. package/ref-monty/crates/monty/test_cases/type_error__int_div_str.py +0 -2
  905. package/ref-monty/crates/monty/test_cases/type_error__int_floordiv_str.py +0 -2
  906. package/ref-monty/crates/monty/test_cases/type_error__int_iadd_str.py +0 -3
  907. package/ref-monty/crates/monty/test_cases/type_error__int_mod_str.py +0 -2
  908. package/ref-monty/crates/monty/test_cases/type_error__int_pow_str.py +0 -2
  909. package/ref-monty/crates/monty/test_cases/type_error__int_sub_str.py +0 -2
  910. package/ref-monty/crates/monty/test_cases/type_error__list_add_int.py +0 -2
  911. package/ref-monty/crates/monty/test_cases/type_error__list_add_str.py +0 -2
  912. package/ref-monty/crates/monty/test_cases/type_error__list_iadd_int.py +0 -6
  913. package/ref-monty/crates/monty/test_cases/type_error__str_add_int.py +0 -2
  914. package/ref-monty/crates/monty/test_cases/type_error__str_iadd_int.py +0 -3
  915. package/ref-monty/crates/monty/test_cases/type_error__unary_invert_str.py +0 -3
  916. package/ref-monty/crates/monty/test_cases/type_error__unary_minus_str.py +0 -4
  917. package/ref-monty/crates/monty/test_cases/type_error__unary_neg_str.py +0 -3
  918. package/ref-monty/crates/monty/test_cases/type_error__unary_plus_str.py +0 -4
  919. package/ref-monty/crates/monty/test_cases/typing__types.py +0 -24
  920. package/ref-monty/crates/monty/test_cases/unpack__nested.py +0 -48
  921. package/ref-monty/crates/monty/test_cases/unpack__non_sequence.py +0 -9
  922. package/ref-monty/crates/monty/test_cases/unpack__not_enough.py +0 -9
  923. package/ref-monty/crates/monty/test_cases/unpack__ops.py +0 -153
  924. package/ref-monty/crates/monty/test_cases/unpack__star_not_enough.py +0 -9
  925. package/ref-monty/crates/monty/test_cases/unpack__too_many.py +0 -9
  926. package/ref-monty/crates/monty/test_cases/version__cpython.py +0 -4
  927. package/ref-monty/crates/monty/test_cases/walrus__all.py +0 -178
  928. package/ref-monty/crates/monty/test_cases/while__all.py +0 -206
  929. package/ref-monty/crates/monty/tests/asyncio.rs +0 -764
  930. package/ref-monty/crates/monty/tests/binary_serde.rs +0 -185
  931. package/ref-monty/crates/monty/tests/bytecode_limits.rs +0 -248
  932. package/ref-monty/crates/monty/tests/datatest_runner.rs +0 -2029
  933. package/ref-monty/crates/monty/tests/inputs.rs +0 -420
  934. package/ref-monty/crates/monty/tests/json_serde.rs +0 -250
  935. package/ref-monty/crates/monty/tests/main.rs +0 -71
  936. package/ref-monty/crates/monty/tests/math_module.rs +0 -114
  937. package/ref-monty/crates/monty/tests/name_lookup.rs +0 -482
  938. package/ref-monty/crates/monty/tests/os_tests.rs +0 -459
  939. package/ref-monty/crates/monty/tests/parse_errors.rs +0 -441
  940. package/ref-monty/crates/monty/tests/print_writer.rs +0 -238
  941. package/ref-monty/crates/monty/tests/py_object.rs +0 -121
  942. package/ref-monty/crates/monty/tests/regex.rs +0 -90
  943. package/ref-monty/crates/monty/tests/repl.rs +0 -344
  944. package/ref-monty/crates/monty/tests/resource_limits.rs +0 -1826
  945. package/ref-monty/crates/monty/tests/try_from.rs +0 -167
  946. package/ref-monty/crates/monty-cli/Cargo.toml +0 -25
  947. package/ref-monty/crates/monty-cli/src/main.rs +0 -541
  948. package/ref-monty/crates/monty-js/.cargo/config.toml +0 -2
  949. package/ref-monty/crates/monty-js/.prettierignore +0 -8
  950. package/ref-monty/crates/monty-js/Cargo.toml +0 -32
  951. package/ref-monty/crates/monty-js/README.md +0 -207
  952. package/ref-monty/crates/monty-js/__test__/async.spec.ts +0 -350
  953. package/ref-monty/crates/monty-js/__test__/basic.spec.ts +0 -114
  954. package/ref-monty/crates/monty-js/__test__/exceptions.spec.ts +0 -427
  955. package/ref-monty/crates/monty-js/__test__/external.spec.ts +0 -354
  956. package/ref-monty/crates/monty-js/__test__/inputs.spec.ts +0 -143
  957. package/ref-monty/crates/monty-js/__test__/limits.spec.ts +0 -162
  958. package/ref-monty/crates/monty-js/__test__/package.json +0 -3
  959. package/ref-monty/crates/monty-js/__test__/print.spec.ts +0 -229
  960. package/ref-monty/crates/monty-js/__test__/repl.spec.ts +0 -34
  961. package/ref-monty/crates/monty-js/__test__/serialize.spec.ts +0 -205
  962. package/ref-monty/crates/monty-js/__test__/start.spec.ts +0 -443
  963. package/ref-monty/crates/monty-js/__test__/type_check.spec.ts +0 -147
  964. package/ref-monty/crates/monty-js/__test__/types.spec.ts +0 -319
  965. package/ref-monty/crates/monty-js/build.rs +0 -61
  966. package/ref-monty/crates/monty-js/index-header.d.ts +0 -3
  967. package/ref-monty/crates/monty-js/package-lock.json +0 -4694
  968. package/ref-monty/crates/monty-js/package.json +0 -100
  969. package/ref-monty/crates/monty-js/scripts/smoke-test.sh +0 -69
  970. package/ref-monty/crates/monty-js/smoke-test/package.json +0 -17
  971. package/ref-monty/crates/monty-js/smoke-test/test.ts +0 -171
  972. package/ref-monty/crates/monty-js/smoke-test/tsconfig.json +0 -11
  973. package/ref-monty/crates/monty-js/src/convert.rs +0 -648
  974. package/ref-monty/crates/monty-js/src/exceptions.rs +0 -293
  975. package/ref-monty/crates/monty-js/src/lib.rs +0 -41
  976. package/ref-monty/crates/monty-js/src/limits.rs +0 -53
  977. package/ref-monty/crates/monty-js/src/monty_cls.rs +0 -1407
  978. package/ref-monty/crates/monty-js/tsconfig.json +0 -17
  979. package/ref-monty/crates/monty-js/wrapper.ts +0 -701
  980. package/ref-monty/crates/monty-python/Cargo.toml +0 -38
  981. package/ref-monty/crates/monty-python/README.md +0 -134
  982. package/ref-monty/crates/monty-python/build.rs +0 -4
  983. package/ref-monty/crates/monty-python/example.py +0 -40
  984. package/ref-monty/crates/monty-python/exercise.py +0 -46
  985. package/ref-monty/crates/monty-python/pyproject.toml +0 -57
  986. package/ref-monty/crates/monty-python/python/pydantic_monty/__init__.py +0 -281
  987. package/ref-monty/crates/monty-python/python/pydantic_monty/_monty.pyi +0 -677
  988. package/ref-monty/crates/monty-python/python/pydantic_monty/os_access.py +0 -933
  989. package/ref-monty/crates/monty-python/python/pydantic_monty/py.typed +0 -0
  990. package/ref-monty/crates/monty-python/src/convert.rs +0 -273
  991. package/ref-monty/crates/monty-python/src/dataclass.rs +0 -461
  992. package/ref-monty/crates/monty-python/src/exceptions.rs +0 -557
  993. package/ref-monty/crates/monty-python/src/external.rs +0 -165
  994. package/ref-monty/crates/monty-python/src/lib.rs +0 -77
  995. package/ref-monty/crates/monty-python/src/limits.rs +0 -142
  996. package/ref-monty/crates/monty-python/src/monty_cls.rs +0 -1650
  997. package/ref-monty/crates/monty-python/src/repl.rs +0 -470
  998. package/ref-monty/crates/monty-python/src/serialization.rs +0 -761
  999. package/ref-monty/crates/monty-python/tests/test_async.py +0 -1201
  1000. package/ref-monty/crates/monty-python/tests/test_basic.py +0 -66
  1001. package/ref-monty/crates/monty-python/tests/test_dataclasses.py +0 -971
  1002. package/ref-monty/crates/monty-python/tests/test_exceptions.py +0 -361
  1003. package/ref-monty/crates/monty-python/tests/test_external.py +0 -367
  1004. package/ref-monty/crates/monty-python/tests/test_inputs.py +0 -126
  1005. package/ref-monty/crates/monty-python/tests/test_limits.py +0 -257
  1006. package/ref-monty/crates/monty-python/tests/test_os_access.py +0 -1286
  1007. package/ref-monty/crates/monty-python/tests/test_os_access_compat.py +0 -731
  1008. package/ref-monty/crates/monty-python/tests/test_os_access_raw.py +0 -483
  1009. package/ref-monty/crates/monty-python/tests/test_os_calls.py +0 -819
  1010. package/ref-monty/crates/monty-python/tests/test_print.py +0 -208
  1011. package/ref-monty/crates/monty-python/tests/test_re.py +0 -170
  1012. package/ref-monty/crates/monty-python/tests/test_readme_examples.py +0 -20
  1013. package/ref-monty/crates/monty-python/tests/test_repl.py +0 -749
  1014. package/ref-monty/crates/monty-python/tests/test_serialize.py +0 -284
  1015. package/ref-monty/crates/monty-python/tests/test_start.py +0 -346
  1016. package/ref-monty/crates/monty-python/tests/test_threading.py +0 -163
  1017. package/ref-monty/crates/monty-python/tests/test_type_check.py +0 -344
  1018. package/ref-monty/crates/monty-python/tests/test_types.py +0 -553
  1019. package/ref-monty/crates/monty-type-checking/Cargo.toml +0 -32
  1020. package/ref-monty/crates/monty-type-checking/src/db.rs +0 -116
  1021. package/ref-monty/crates/monty-type-checking/src/lib.rs +0 -4
  1022. package/ref-monty/crates/monty-type-checking/src/type_check.rs +0 -280
  1023. package/ref-monty/crates/monty-type-checking/tests/bad_types.py +0 -109
  1024. package/ref-monty/crates/monty-type-checking/tests/bad_types_output.txt +0 -21
  1025. package/ref-monty/crates/monty-type-checking/tests/good_types.py +0 -475
  1026. package/ref-monty/crates/monty-type-checking/tests/main.rs +0 -205
  1027. package/ref-monty/crates/monty-type-checking/tests/reveal_types.py +0 -56
  1028. package/ref-monty/crates/monty-type-checking/tests/reveal_types_output.txt +0 -41
  1029. package/ref-monty/crates/monty-typeshed/Cargo.toml +0 -29
  1030. package/ref-monty/crates/monty-typeshed/README.md +0 -11
  1031. package/ref-monty/crates/monty-typeshed/build.rs +0 -101
  1032. package/ref-monty/crates/monty-typeshed/custom/README.md +0 -1
  1033. package/ref-monty/crates/monty-typeshed/custom/asyncio.pyi +0 -138
  1034. package/ref-monty/crates/monty-typeshed/custom/os.pyi +0 -87
  1035. package/ref-monty/crates/monty-typeshed/custom/sys.pyi +0 -33
  1036. package/ref-monty/crates/monty-typeshed/src/lib.rs +0 -56
  1037. package/ref-monty/crates/monty-typeshed/update.py +0 -321
  1038. package/ref-monty/crates/monty-typeshed/vendor/typeshed/source_commit.txt +0 -1
  1039. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/VERSIONS +0 -20
  1040. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/_collections_abc.pyi +0 -105
  1041. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/_typeshed/__init__.pyi +0 -394
  1042. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/asyncio.pyi +0 -138
  1043. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/builtins.pyi +0 -1434
  1044. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/collections/__init__.pyi +0 -527
  1045. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/collections/abc.pyi +0 -2
  1046. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/dataclasses.pyi +0 -502
  1047. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/enum.pyi +0 -376
  1048. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/math.pyi +0 -149
  1049. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/os.pyi +0 -87
  1050. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/pathlib/__init__.pyi +0 -395
  1051. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/pathlib/types.pyi +0 -8
  1052. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/re.pyi +0 -337
  1053. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/sys.pyi +0 -33
  1054. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/types.pyi +0 -741
  1055. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/typing.pyi +0 -1217
  1056. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/typing_extensions.pyi +0 -716
  1057. package/ref-monty/docs/usage-guide.md +0 -117
  1058. package/ref-monty/examples/README.md +0 -3
  1059. package/ref-monty/examples/expense_analysis/README.md +0 -3
  1060. package/ref-monty/examples/expense_analysis/data.py +0 -124
  1061. package/ref-monty/examples/expense_analysis/main.py +0 -115
  1062. package/ref-monty/examples/sql_playground/README.md +0 -20
  1063. package/ref-monty/examples/sql_playground/external_functions.py +0 -129
  1064. package/ref-monty/examples/sql_playground/main.py +0 -81
  1065. package/ref-monty/examples/sql_playground/sandbox_code.py +0 -82
  1066. package/ref-monty/examples/sql_playground/type_stubs.pyi +0 -14
  1067. package/ref-monty/examples/web_scraper/README.md +0 -15
  1068. package/ref-monty/examples/web_scraper/browser.py +0 -56
  1069. package/ref-monty/examples/web_scraper/example_code.py +0 -59
  1070. package/ref-monty/examples/web_scraper/external_functions.py +0 -324
  1071. package/ref-monty/examples/web_scraper/main.py +0 -193
  1072. package/ref-monty/examples/web_scraper/sub_agent.py +0 -79
  1073. package/ref-monty/monty-npm.md +0 -235
  1074. package/ref-monty/pyproject.toml +0 -162
  1075. package/ref-monty/scripts/check_imports.py +0 -91
  1076. package/ref-monty/scripts/codecov_diff.py +0 -412
  1077. package/ref-monty/scripts/complete_tests.py +0 -146
  1078. package/ref-monty/scripts/flamegraph_to_text.py +0 -208
  1079. package/ref-monty/scripts/iter_test_methods.py +0 -540
  1080. package/ref-monty/scripts/run_traceback.py +0 -180
  1081. package/ref-monty/scripts/startup_performance.py +0 -130
  1082. package/ref-monty/uv.lock +0 -1779
  1083. package/temp_resend_cli/repo/.github/scripts/pr-title-check.js +0 -34
  1084. package/temp_resend_cli/repo/.github/workflows/ci.yml +0 -67
  1085. package/temp_resend_cli/repo/.github/workflows/post-release.yml +0 -51
  1086. package/temp_resend_cli/repo/.github/workflows/pr-title-check.yml +0 -13
  1087. package/temp_resend_cli/repo/.github/workflows/release.yml +0 -175
  1088. package/temp_resend_cli/repo/.github/workflows/test-install-unix.yml +0 -34
  1089. package/temp_resend_cli/repo/.github/workflows/test-install-windows.yml +0 -48
  1090. package/temp_resend_cli/repo/CHANGELOG.md +0 -31
  1091. package/temp_resend_cli/repo/LICENSE +0 -21
  1092. package/temp_resend_cli/repo/README.md +0 -450
  1093. package/temp_resend_cli/repo/biome.json +0 -36
  1094. package/temp_resend_cli/repo/install.ps1 +0 -141
  1095. package/temp_resend_cli/repo/install.sh +0 -301
  1096. package/temp_resend_cli/repo/package.json +0 -61
  1097. package/temp_resend_cli/repo/pnpm-lock.yaml +0 -2439
  1098. package/temp_resend_cli/repo/renovate.json +0 -4
  1099. package/temp_resend_cli/repo/src/cli.ts +0 -98
  1100. package/temp_resend_cli/repo/src/commands/api-keys/create.ts +0 -114
  1101. package/temp_resend_cli/repo/src/commands/api-keys/delete.ts +0 -47
  1102. package/temp_resend_cli/repo/src/commands/api-keys/index.ts +0 -26
  1103. package/temp_resend_cli/repo/src/commands/api-keys/list.ts +0 -35
  1104. package/temp_resend_cli/repo/src/commands/api-keys/utils.ts +0 -8
  1105. package/temp_resend_cli/repo/src/commands/auth/index.ts +0 -20
  1106. package/temp_resend_cli/repo/src/commands/auth/login.ts +0 -234
  1107. package/temp_resend_cli/repo/src/commands/auth/logout.ts +0 -105
  1108. package/temp_resend_cli/repo/src/commands/broadcasts/create.ts +0 -196
  1109. package/temp_resend_cli/repo/src/commands/broadcasts/delete.ts +0 -46
  1110. package/temp_resend_cli/repo/src/commands/broadcasts/get.ts +0 -59
  1111. package/temp_resend_cli/repo/src/commands/broadcasts/index.ts +0 -43
  1112. package/temp_resend_cli/repo/src/commands/broadcasts/list.ts +0 -60
  1113. package/temp_resend_cli/repo/src/commands/broadcasts/send.ts +0 -56
  1114. package/temp_resend_cli/repo/src/commands/broadcasts/update.ts +0 -95
  1115. package/temp_resend_cli/repo/src/commands/broadcasts/utils.ts +0 -35
  1116. package/temp_resend_cli/repo/src/commands/contact-properties/create.ts +0 -118
  1117. package/temp_resend_cli/repo/src/commands/contact-properties/delete.ts +0 -48
  1118. package/temp_resend_cli/repo/src/commands/contact-properties/get.ts +0 -46
  1119. package/temp_resend_cli/repo/src/commands/contact-properties/index.ts +0 -48
  1120. package/temp_resend_cli/repo/src/commands/contact-properties/list.ts +0 -68
  1121. package/temp_resend_cli/repo/src/commands/contact-properties/update.ts +0 -88
  1122. package/temp_resend_cli/repo/src/commands/contact-properties/utils.ts +0 -17
  1123. package/temp_resend_cli/repo/src/commands/contacts/add-segment.ts +0 -78
  1124. package/temp_resend_cli/repo/src/commands/contacts/create.ts +0 -122
  1125. package/temp_resend_cli/repo/src/commands/contacts/delete.ts +0 -49
  1126. package/temp_resend_cli/repo/src/commands/contacts/get.ts +0 -53
  1127. package/temp_resend_cli/repo/src/commands/contacts/index.ts +0 -58
  1128. package/temp_resend_cli/repo/src/commands/contacts/list.ts +0 -57
  1129. package/temp_resend_cli/repo/src/commands/contacts/remove-segment.ts +0 -48
  1130. package/temp_resend_cli/repo/src/commands/contacts/segments.ts +0 -39
  1131. package/temp_resend_cli/repo/src/commands/contacts/topics.ts +0 -45
  1132. package/temp_resend_cli/repo/src/commands/contacts/update-topics.ts +0 -90
  1133. package/temp_resend_cli/repo/src/commands/contacts/update.ts +0 -77
  1134. package/temp_resend_cli/repo/src/commands/contacts/utils.ts +0 -119
  1135. package/temp_resend_cli/repo/src/commands/doctor.ts +0 -216
  1136. package/temp_resend_cli/repo/src/commands/domains/create.ts +0 -83
  1137. package/temp_resend_cli/repo/src/commands/domains/delete.ts +0 -42
  1138. package/temp_resend_cli/repo/src/commands/domains/get.ts +0 -47
  1139. package/temp_resend_cli/repo/src/commands/domains/index.ts +0 -35
  1140. package/temp_resend_cli/repo/src/commands/domains/list.ts +0 -53
  1141. package/temp_resend_cli/repo/src/commands/domains/update.ts +0 -75
  1142. package/temp_resend_cli/repo/src/commands/domains/utils.ts +0 -44
  1143. package/temp_resend_cli/repo/src/commands/domains/verify.ts +0 -38
  1144. package/temp_resend_cli/repo/src/commands/emails/batch.ts +0 -140
  1145. package/temp_resend_cli/repo/src/commands/emails/get.ts +0 -44
  1146. package/temp_resend_cli/repo/src/commands/emails/index.ts +0 -30
  1147. package/temp_resend_cli/repo/src/commands/emails/list.ts +0 -84
  1148. package/temp_resend_cli/repo/src/commands/emails/receiving/attachment.ts +0 -55
  1149. package/temp_resend_cli/repo/src/commands/emails/receiving/attachments.ts +0 -68
  1150. package/temp_resend_cli/repo/src/commands/emails/receiving/get.ts +0 -58
  1151. package/temp_resend_cli/repo/src/commands/emails/receiving/index.ts +0 -28
  1152. package/temp_resend_cli/repo/src/commands/emails/receiving/list.ts +0 -59
  1153. package/temp_resend_cli/repo/src/commands/emails/receiving/utils.ts +0 -38
  1154. package/temp_resend_cli/repo/src/commands/emails/send.ts +0 -189
  1155. package/temp_resend_cli/repo/src/commands/open.ts +0 -27
  1156. package/temp_resend_cli/repo/src/commands/segments/create.ts +0 -50
  1157. package/temp_resend_cli/repo/src/commands/segments/delete.ts +0 -47
  1158. package/temp_resend_cli/repo/src/commands/segments/get.ts +0 -38
  1159. package/temp_resend_cli/repo/src/commands/segments/index.ts +0 -36
  1160. package/temp_resend_cli/repo/src/commands/segments/list.ts +0 -58
  1161. package/temp_resend_cli/repo/src/commands/segments/utils.ts +0 -7
  1162. package/temp_resend_cli/repo/src/commands/teams/index.ts +0 -10
  1163. package/temp_resend_cli/repo/src/commands/teams/list.ts +0 -35
  1164. package/temp_resend_cli/repo/src/commands/teams/remove.ts +0 -86
  1165. package/temp_resend_cli/repo/src/commands/teams/switch.ts +0 -76
  1166. package/temp_resend_cli/repo/src/commands/topics/create.ts +0 -73
  1167. package/temp_resend_cli/repo/src/commands/topics/delete.ts +0 -47
  1168. package/temp_resend_cli/repo/src/commands/topics/get.ts +0 -42
  1169. package/temp_resend_cli/repo/src/commands/topics/index.ts +0 -42
  1170. package/temp_resend_cli/repo/src/commands/topics/list.ts +0 -34
  1171. package/temp_resend_cli/repo/src/commands/topics/update.ts +0 -59
  1172. package/temp_resend_cli/repo/src/commands/topics/utils.ts +0 -16
  1173. package/temp_resend_cli/repo/src/commands/webhooks/create.ts +0 -128
  1174. package/temp_resend_cli/repo/src/commands/webhooks/delete.ts +0 -49
  1175. package/temp_resend_cli/repo/src/commands/webhooks/get.ts +0 -42
  1176. package/temp_resend_cli/repo/src/commands/webhooks/index.ts +0 -42
  1177. package/temp_resend_cli/repo/src/commands/webhooks/list.ts +0 -55
  1178. package/temp_resend_cli/repo/src/commands/webhooks/listen.ts +0 -379
  1179. package/temp_resend_cli/repo/src/commands/webhooks/update.ts +0 -83
  1180. package/temp_resend_cli/repo/src/commands/webhooks/utils.ts +0 -36
  1181. package/temp_resend_cli/repo/src/commands/whoami.ts +0 -71
  1182. package/temp_resend_cli/repo/src/lib/actions.ts +0 -157
  1183. package/temp_resend_cli/repo/src/lib/client.ts +0 -37
  1184. package/temp_resend_cli/repo/src/lib/config.ts +0 -217
  1185. package/temp_resend_cli/repo/src/lib/files.ts +0 -15
  1186. package/temp_resend_cli/repo/src/lib/help-text.ts +0 -38
  1187. package/temp_resend_cli/repo/src/lib/output.ts +0 -56
  1188. package/temp_resend_cli/repo/src/lib/pagination.ts +0 -36
  1189. package/temp_resend_cli/repo/src/lib/prompts.ts +0 -149
  1190. package/temp_resend_cli/repo/src/lib/spinner.ts +0 -100
  1191. package/temp_resend_cli/repo/src/lib/table.ts +0 -57
  1192. package/temp_resend_cli/repo/src/lib/tty.ts +0 -28
  1193. package/temp_resend_cli/repo/src/lib/update-check.ts +0 -169
  1194. package/temp_resend_cli/repo/src/lib/version.ts +0 -4
  1195. package/temp_resend_cli/repo/tests/commands/api-keys/create.test.ts +0 -196
  1196. package/temp_resend_cli/repo/tests/commands/api-keys/delete.test.ts +0 -157
  1197. package/temp_resend_cli/repo/tests/commands/api-keys/list.test.ts +0 -134
  1198. package/temp_resend_cli/repo/tests/commands/auth/login.test.ts +0 -153
  1199. package/temp_resend_cli/repo/tests/commands/auth/logout.test.ts +0 -153
  1200. package/temp_resend_cli/repo/tests/commands/broadcasts/create.test.ts +0 -454
  1201. package/temp_resend_cli/repo/tests/commands/broadcasts/delete.test.ts +0 -183
  1202. package/temp_resend_cli/repo/tests/commands/broadcasts/get.test.ts +0 -147
  1203. package/temp_resend_cli/repo/tests/commands/broadcasts/list.test.ts +0 -199
  1204. package/temp_resend_cli/repo/tests/commands/broadcasts/send.test.ts +0 -162
  1205. package/temp_resend_cli/repo/tests/commands/broadcasts/update.test.ts +0 -288
  1206. package/temp_resend_cli/repo/tests/commands/contact-properties/create.test.ts +0 -251
  1207. package/temp_resend_cli/repo/tests/commands/contact-properties/delete.test.ts +0 -184
  1208. package/temp_resend_cli/repo/tests/commands/contact-properties/get.test.ts +0 -145
  1209. package/temp_resend_cli/repo/tests/commands/contact-properties/list.test.ts +0 -181
  1210. package/temp_resend_cli/repo/tests/commands/contact-properties/update.test.ts +0 -217
  1211. package/temp_resend_cli/repo/tests/commands/contacts/add-segment.test.ts +0 -189
  1212. package/temp_resend_cli/repo/tests/commands/contacts/create.test.ts +0 -271
  1213. package/temp_resend_cli/repo/tests/commands/contacts/delete.test.ts +0 -193
  1214. package/temp_resend_cli/repo/tests/commands/contacts/get.test.ts +0 -149
  1215. package/temp_resend_cli/repo/tests/commands/contacts/list.test.ts +0 -176
  1216. package/temp_resend_cli/repo/tests/commands/contacts/remove-segment.test.ts +0 -167
  1217. package/temp_resend_cli/repo/tests/commands/contacts/segments.test.ts +0 -168
  1218. package/temp_resend_cli/repo/tests/commands/contacts/topics.test.ts +0 -164
  1219. package/temp_resend_cli/repo/tests/commands/contacts/update-topics.test.ts +0 -248
  1220. package/temp_resend_cli/repo/tests/commands/contacts/update.test.ts +0 -206
  1221. package/temp_resend_cli/repo/tests/commands/doctor.test.ts +0 -164
  1222. package/temp_resend_cli/repo/tests/commands/domains/create.test.ts +0 -193
  1223. package/temp_resend_cli/repo/tests/commands/domains/delete.test.ts +0 -157
  1224. package/temp_resend_cli/repo/tests/commands/domains/get.test.ts +0 -138
  1225. package/temp_resend_cli/repo/tests/commands/domains/list.test.ts +0 -165
  1226. package/temp_resend_cli/repo/tests/commands/domains/update.test.ts +0 -224
  1227. package/temp_resend_cli/repo/tests/commands/domains/verify.test.ts +0 -118
  1228. package/temp_resend_cli/repo/tests/commands/emails/batch.test.ts +0 -324
  1229. package/temp_resend_cli/repo/tests/commands/emails/get.test.ts +0 -132
  1230. package/temp_resend_cli/repo/tests/commands/emails/receiving/attachment.test.ts +0 -141
  1231. package/temp_resend_cli/repo/tests/commands/emails/receiving/attachments.test.ts +0 -169
  1232. package/temp_resend_cli/repo/tests/commands/emails/receiving/get.test.ts +0 -141
  1233. package/temp_resend_cli/repo/tests/commands/emails/receiving/list.test.ts +0 -182
  1234. package/temp_resend_cli/repo/tests/commands/emails/send.test.ts +0 -312
  1235. package/temp_resend_cli/repo/tests/commands/segments/create.test.ts +0 -164
  1236. package/temp_resend_cli/repo/tests/commands/segments/delete.test.ts +0 -183
  1237. package/temp_resend_cli/repo/tests/commands/segments/get.test.ts +0 -138
  1238. package/temp_resend_cli/repo/tests/commands/segments/list.test.ts +0 -174
  1239. package/temp_resend_cli/repo/tests/commands/teams/list.test.ts +0 -62
  1240. package/temp_resend_cli/repo/tests/commands/teams/remove.test.ts +0 -110
  1241. package/temp_resend_cli/repo/tests/commands/teams/switch.test.ts +0 -103
  1242. package/temp_resend_cli/repo/tests/commands/topics/create.test.ts +0 -192
  1243. package/temp_resend_cli/repo/tests/commands/topics/delete.test.ts +0 -157
  1244. package/temp_resend_cli/repo/tests/commands/topics/get.test.ts +0 -126
  1245. package/temp_resend_cli/repo/tests/commands/topics/list.test.ts +0 -125
  1246. package/temp_resend_cli/repo/tests/commands/topics/update.test.ts +0 -178
  1247. package/temp_resend_cli/repo/tests/commands/webhooks/create.test.ts +0 -225
  1248. package/temp_resend_cli/repo/tests/commands/webhooks/delete.test.ts +0 -157
  1249. package/temp_resend_cli/repo/tests/commands/webhooks/get.test.ts +0 -126
  1250. package/temp_resend_cli/repo/tests/commands/webhooks/list.test.ts +0 -178
  1251. package/temp_resend_cli/repo/tests/commands/webhooks/update.test.ts +0 -207
  1252. package/temp_resend_cli/repo/tests/commands/whoami.test.ts +0 -98
  1253. package/temp_resend_cli/repo/tests/e2e/smoke.test.ts +0 -93
  1254. package/temp_resend_cli/repo/tests/helpers.ts +0 -86
  1255. package/temp_resend_cli/repo/tests/lib/client.test.ts +0 -71
  1256. package/temp_resend_cli/repo/tests/lib/config.test.ts +0 -451
  1257. package/temp_resend_cli/repo/tests/lib/files.test.ts +0 -73
  1258. package/temp_resend_cli/repo/tests/lib/help-text.test.ts +0 -97
  1259. package/temp_resend_cli/repo/tests/lib/output.test.ts +0 -136
  1260. package/temp_resend_cli/repo/tests/lib/prompts.test.ts +0 -185
  1261. package/temp_resend_cli/repo/tests/lib/spinner.test.ts +0 -166
  1262. package/temp_resend_cli/repo/tests/lib/table.test.ts +0 -63
  1263. package/temp_resend_cli/repo/tests/lib/tty.test.ts +0 -89
  1264. package/temp_resend_cli/repo/tests/lib/update-check.test.ts +0 -179
  1265. package/temp_resend_cli/repo/tsconfig.json +0 -14
  1266. package/temp_resend_cli/repo/vitest.config.e2e.ts +0 -8
  1267. package/temp_resend_cli/repo/vitest.config.ts +0 -10
  1268. /package/docs/{plugin-examples.md → plugins-examples.md} +0 -0
@@ -1,2029 +0,0 @@
1
- use std::{
2
- cell::RefCell,
3
- collections::{HashMap, HashSet},
4
- error::Error,
5
- ffi::CString,
6
- fs,
7
- panic::{self, AssertUnwindSafe},
8
- path::Path,
9
- sync::{
10
- OnceLock,
11
- mpsc::{self, RecvTimeoutError},
12
- },
13
- thread,
14
- time::Duration,
15
- };
16
-
17
- use ahash::AHashMap;
18
- use monty::{
19
- ExcType, ExtFunctionResult, LimitedTracker, MontyException, MontyObject, MontyRun, NameLookupResult, OsFunction,
20
- PrintWriter, ResourceLimits, RunProgress, dir_stat, file_stat,
21
- };
22
- use pyo3::{prelude::*, types::PyDict};
23
- use similar::TextDiff;
24
-
25
- /// Recursion limit for test execution.
26
- ///
27
- /// Used for both Monty and CPython tests. CPython needs ~5 extra frames
28
- /// for runpy overhead, which is added in run_file_and_get_traceback.
29
- ///
30
- /// NOTE this value is chosen to avoid both:
31
- /// * other recursion errors in python (if it's too low)
32
- /// * and, stack overflows in debug rust (if it's too high)
33
- const TEST_RECURSION_LIMIT: usize = 50;
34
-
35
- /// Test configuration parsed from directive comments.
36
- ///
37
- /// Parsed from an optional first-line comment like `# xfail=monty,cpython` or `# call-external`.
38
- /// If not present, defaults to running on both interpreters in standard mode.
39
- ///
40
- /// ## Xfail Semantics (Strict)
41
- /// - `xfail=monty` - Test is expected to fail on Monty; if it passes, that's an error
42
- /// - `xfail=cpython` - Test is expected to fail on CPython; if it passes, that's an error
43
- /// - `xfail=monty,cpython` - Expected to fail on both interpreters
44
- #[derive(Debug, Clone, Default)]
45
- #[expect(clippy::struct_excessive_bools)]
46
- struct TestConfig {
47
- /// When true, test is expected to fail on Monty (strict xfail).
48
- xfail_monty: bool,
49
- /// When true, test is expected to fail on CPython (strict xfail).
50
- xfail_cpython: bool,
51
- /// When true, use MontyRun with external function support instead of MontyRun.
52
- iter_mode: bool,
53
- /// When true, wrap code in async context for CPython execution.
54
- /// Used for tests with top-level await which Monty supports but CPython doesn't.
55
- async_mode: bool,
56
- }
57
-
58
- /// Represents the expected outcome of a test fixture
59
- #[derive(Debug, Clone)]
60
- enum Expectation {
61
- /// Expect exception (parse-time or runtime) with specific message
62
- Raise(String),
63
- /// Expect successful execution, check py_str() output
64
- ReturnStr(String),
65
- /// Expect successful execution, check py_repr() output
66
- Return(String),
67
- /// Expect successful execution, check py_type() output
68
- ReturnType(String),
69
- /// Expect successful execution, check ref counts of named variables.
70
- /// Only used when `ref-count-return` feature is enabled; skipped otherwise.
71
- RefCounts(#[cfg_attr(not(feature = "ref-count-return"), expect(dead_code))] AHashMap<String, usize>),
72
- /// Expect exception with full traceback comparison.
73
- /// The expected traceback string should match exactly between Monty and CPython.
74
- Traceback(String),
75
- /// Expect successful execution without raising an exception (no return value check).
76
- /// Used for tests that rely on asserts or just verify code runs.
77
- NoException,
78
- }
79
-
80
- impl Expectation {
81
- /// Returns the expected value string
82
- fn expected_value(&self) -> &str {
83
- match self {
84
- Self::Raise(s) | Self::ReturnStr(s) | Self::Return(s) | Self::ReturnType(s) | Self::Traceback(s) => s,
85
- Self::RefCounts(_) | Self::NoException => "",
86
- }
87
- }
88
- }
89
-
90
- /// Parse a Python fixture file into code, expected outcome, and test configuration.
91
- ///
92
- /// The file may optionally contain a `# xfail=monty,cpython` comment to specify
93
- /// which interpreters the test is expected to fail on. If not present, defaults to
94
- /// running on both and expecting success.
95
- ///
96
- /// The file may have an expectation comment as the LAST line:
97
- /// - `# Raise=ExceptionType('message')` - Exception (parse-time or runtime)
98
- /// - `# Return.str=value` - Check py_str() output
99
- /// - `# Return=value` - Check py_repr() output
100
- /// - `# Return.type=typename` - Check py_type() output
101
- /// - `# ref-counts={'var': count, ...}` - Check ref counts of named heap variables
102
- ///
103
- /// Or a traceback expectation as a triple-quoted string at the end (uses actual test filename):
104
- /// ```text
105
- /// """TRACEBACK:
106
- /// Traceback (most recent call last):
107
- /// File "my_test.py", line 4, in <module>
108
- /// foo()
109
- /// ValueError: message
110
- /// """
111
- /// ```
112
- ///
113
- /// If no expectation comment is present, the test just verifies the code runs without exception.
114
- fn parse_fixture(content: &str) -> (String, Expectation, TestConfig) {
115
- let lines: Vec<&str> = content.lines().collect();
116
-
117
- assert!(!lines.is_empty(), "Empty fixture file");
118
-
119
- // comment lines with leading # and spaces stripped
120
- let comment_lines = lines
121
- .iter()
122
- .filter(|line| line.starts_with('#'))
123
- .map(|line| line.trim_start_matches('#').trim())
124
- .collect::<Vec<_>>();
125
-
126
- let mut config = TestConfig {
127
- iter_mode: comment_lines.iter().any(|line| line.starts_with("call-external")),
128
- async_mode: comment_lines.iter().any(|line| line.starts_with("run-async")),
129
- ..Default::default()
130
- };
131
- // Check for "xfail=" directive
132
- if let Some(&xfail_line) = comment_lines.iter().find(|line| line.starts_with("xfail=")) {
133
- // Parse until whitespace or end of line
134
- let xfail_end = xfail_line.find(|c: char| c.is_whitespace()).unwrap_or(xfail_line.len());
135
- let xfail_str = &xfail_line[..xfail_end];
136
- config.xfail_monty = xfail_str.contains("monty");
137
- config.xfail_cpython = xfail_str.contains("cpython");
138
- }
139
-
140
- // Check for TRACEBACK expectation (triple-quoted string at end of file)
141
- // Format: """TRACEBACK:\n...\n"""
142
- if let Some((code, traceback)) = parse_traceback_expectation(content) {
143
- return (code, Expectation::Traceback(traceback), config);
144
- }
145
-
146
- // Get the last line and check if it's an expectation comment
147
- let last_line = lines.last().unwrap();
148
-
149
- // Parse expectation from comment line if present
150
- // Note: Check more specific patterns first (Return.str, Return.type, ref-counts) before general Return
151
- let (expectation, code_lines) = if let Some(expected) = last_line.strip_prefix("# ref-counts=") {
152
- (
153
- Expectation::RefCounts(parse_ref_counts(expected)),
154
- &lines[..lines.len() - 1],
155
- )
156
- } else if let Some(expected) = last_line.strip_prefix("# Return.str=") {
157
- (Expectation::ReturnStr(expected.to_string()), &lines[..lines.len() - 1])
158
- } else if let Some(expected) = last_line.strip_prefix("# Return.type=") {
159
- (Expectation::ReturnType(expected.to_string()), &lines[..lines.len() - 1])
160
- } else if let Some(expected) = last_line.strip_prefix("# Return=") {
161
- (Expectation::Return(expected.to_string()), &lines[..lines.len() - 1])
162
- } else if let Some(expected) = last_line.strip_prefix("# Raise=") {
163
- (Expectation::Raise(expected.to_string()), &lines[..lines.len() - 1])
164
- } else {
165
- // No expectation comment - just run and check it doesn't raise
166
- (Expectation::NoException, &lines[..])
167
- };
168
-
169
- // Code is everything except the directive comment (and expectation comment if present)
170
- let code = code_lines.join("\n");
171
-
172
- (code, expectation, config)
173
- }
174
-
175
- /// Parses a TRACEBACK expectation from the end of a fixture file.
176
- ///
177
- /// Looks for a triple-quoted string starting with `"""TRACEBACK:` at the end of the file.
178
- /// Returns `Some((code, expected_traceback))` if found, `None` otherwise.
179
- ///
180
- /// The traceback string should contain the full expected output including the
181
- /// "Traceback (most recent call last):" header and the exception line.
182
- fn parse_traceback_expectation(content: &str) -> Option<(String, String)> {
183
- // Format: """\nTRACEBACK:\n...\n"""
184
- const MARKER: &str = "\"\"\"\nTRACEBACK:\n";
185
-
186
- // Find the TRACEBACK marker
187
- let marker_pos = content.find(MARKER)?;
188
-
189
- // Extract the code before the marker
190
- let code_part = &content[..marker_pos];
191
- let lines: Vec<&str> = code_part.lines().collect();
192
- let code = lines.join("\n").trim_end().to_string();
193
-
194
- // Extract the traceback content between the markers
195
- let after_marker = &content[marker_pos + MARKER.len()..];
196
-
197
- // Find the closing triple quotes (preceded by newline)
198
- let end_pos = after_marker.find("\n\"\"\"")?;
199
- let traceback_content = &after_marker[..end_pos];
200
-
201
- Some((code, traceback_content.to_string()))
202
- }
203
-
204
- /// Parses the ref-counts format: {'var': count, 'var2': count2}
205
- ///
206
- /// Supports both single and double quotes for variable names.
207
- /// Example: {'x': 2, 'y': 1} or {"x": 2, "y": 1}
208
- fn parse_ref_counts(s: &str) -> AHashMap<String, usize> {
209
- let mut counts = AHashMap::new();
210
- let trimmed = s.trim().trim_start_matches('{').trim_end_matches('}');
211
- for pair in trimmed.split(',') {
212
- let pair = pair.trim();
213
- if pair.is_empty() {
214
- continue;
215
- }
216
- let parts: Vec<&str> = pair.split(':').collect();
217
- assert!(
218
- parts.len() == 2,
219
- "Invalid ref-counts pair format: {pair}. Expected 'name': count"
220
- );
221
- let name = parts[0].trim().trim_matches('\'').trim_matches('"');
222
- let count: usize = parts[1]
223
- .trim()
224
- .parse()
225
- .unwrap_or_else(|_| panic!("Invalid ref count value: {}", parts[1]));
226
- counts.insert(name.to_string(), count);
227
- }
228
- counts
229
- }
230
-
231
- /// Python implementations of external functions for running iter mode tests in CPython.
232
- ///
233
- /// These implementations mirror the behavior of `dispatch_external_call` so that
234
- /// iter mode tests produce identical results in both Monty and CPython.
235
- ///
236
- /// This is loaded from `scripts/iter_test_methods.py` which is also imported by
237
- /// `scripts/run_traceback.py` to ensure consistency.
238
- const ITER_EXT_FUNCTIONS_PYTHON: &str = include_str!("../../../scripts/iter_test_methods.py");
239
-
240
- /// Pre-imports Python modules that can cause race conditions during parallel test execution.
241
- ///
242
- /// Python's import machinery isn't fully thread-safe during module initialization.
243
- /// When multiple tests try to import modules like `typing` or `dataclasses` simultaneously,
244
- /// one thread may see a partially initialized module, causing `AttributeError`.
245
- ///
246
- /// This function must be called once before any parallel test execution to ensure
247
- /// all relevant modules are fully initialized.
248
- fn ensure_python_modules_imported() {
249
- static INIT: OnceLock<()> = OnceLock::new();
250
- INIT.get_or_init(|| {
251
- Python::attach(|py| {
252
- // Import modules that are used by iter_test_methods.py and can cause race conditions.
253
- // The order matters: import dependencies first.
254
- py.import("typing").expect("Failed to import typing");
255
- py.import("dataclasses").expect("Failed to import dataclasses");
256
- py.import("pathlib").expect("Failed to import pathlib");
257
- py.import("stat").expect("Failed to import stat");
258
- py.import("asyncio").expect("Failed to import asyncio");
259
- py.import("traceback").expect("Failed to import traceback");
260
-
261
- // Also pre-execute the iter_test_methods code once to ensure all its
262
- // module-level code (dataclass definitions, monkey-patches) is initialized
263
- let ext_funcs_cstr = CString::new(ITER_EXT_FUNCTIONS_PYTHON).expect("Invalid C string");
264
- py.run(&ext_funcs_cstr, None, None)
265
- .expect("Failed to pre-initialize iter_test_methods");
266
- });
267
- });
268
- }
269
-
270
- /// Result from dispatching an external function call.
271
- ///
272
- /// Distinguishes between synchronous calls (return immediately) and
273
- /// asynchronous calls (return a future that needs later resolution).
274
- enum DispatchResult {
275
- /// Synchronous result - pass directly to `state.run()`.
276
- Sync(ExtFunctionResult),
277
- /// Asynchronous call - use `state.run_pending()` and resolve later.
278
- /// Contains the value to resolve the future with.
279
- Async(MontyObject),
280
- }
281
-
282
- /// Dispatches an external function call to the appropriate test implementation.
283
- ///
284
- /// Returns `DispatchResult::Sync` for synchronous calls or `DispatchResult::Async`
285
- /// for coroutine calls that should use `run_pending()`.
286
- ///
287
- /// # Panics
288
- /// Panics if the function name is unknown or arguments are invalid types.
289
- fn dispatch_external_call(name: &str, args: Vec<MontyObject>) -> DispatchResult {
290
- match name {
291
- "add_ints" => {
292
- assert!(args.len() == 2, "add_ints requires 2 arguments");
293
- let a = i64::try_from(&args[0]).expect("add_ints: first arg must be int");
294
- let b = i64::try_from(&args[1]).expect("add_ints: second arg must be int");
295
- DispatchResult::Sync(MontyObject::Int(a + b).into())
296
- }
297
- "concat_strings" => {
298
- assert!(args.len() == 2, "concat_strings requires 2 arguments");
299
- let a = String::try_from(&args[0]).expect("concat_strings: first arg must be str");
300
- let b = String::try_from(&args[1]).expect("concat_strings: second arg must be str");
301
- DispatchResult::Sync(MontyObject::String(a + &b).into())
302
- }
303
- "return_value" => {
304
- assert!(args.len() == 1, "return_value requires 1 argument");
305
- DispatchResult::Sync(args.into_iter().next().unwrap().into())
306
- }
307
- "get_list" => {
308
- assert!(args.is_empty(), "get_list requires no arguments");
309
- DispatchResult::Sync(
310
- MontyObject::List(vec![MontyObject::Int(1), MontyObject::Int(2), MontyObject::Int(3)]).into(),
311
- )
312
- }
313
- "raise_error" => {
314
- // raise_error(exc_type: str, message: str) -> raises exception
315
- assert!(args.len() == 2, "raise_error requires 2 arguments");
316
- let exc_type_str = String::try_from(&args[0]).expect("raise_error: first arg must be str");
317
- let message = String::try_from(&args[1]).expect("raise_error: second arg must be str");
318
- let exc_type = match exc_type_str.as_str() {
319
- "ValueError" => ExcType::ValueError,
320
- "TypeError" => ExcType::TypeError,
321
- "KeyError" => ExcType::KeyError,
322
- "RuntimeError" => ExcType::RuntimeError,
323
- _ => panic!("raise_error: unsupported exception type: {exc_type_str}"),
324
- };
325
- DispatchResult::Sync(MontyException::new(exc_type, Some(message)).into())
326
- }
327
- "make_point" => {
328
- assert!(args.is_empty(), "make_point requires no arguments");
329
- // Return an immutable Point(x=1, y=2) dataclass
330
- DispatchResult::Sync(
331
- MontyObject::Dataclass {
332
- name: "Point".to_string(),
333
- type_id: 0, // Test fixture has no real Python type
334
- field_names: vec!["x".to_string(), "y".to_string()],
335
- attrs: vec![
336
- (MontyObject::String("x".to_string()), MontyObject::Int(1)),
337
- (MontyObject::String("y".to_string()), MontyObject::Int(2)),
338
- ]
339
- .into(),
340
-
341
- frozen: true,
342
- }
343
- .into(),
344
- )
345
- }
346
- "make_mutable_point" => {
347
- assert!(args.is_empty(), "make_mutable_point requires no arguments");
348
- // Return a mutable Point(x=1, y=2) dataclass
349
- DispatchResult::Sync(
350
- MontyObject::Dataclass {
351
- name: "MutablePoint".to_string(),
352
- type_id: 0, // Test fixture has no real Python type
353
- field_names: vec!["x".to_string(), "y".to_string()],
354
- attrs: vec![
355
- (MontyObject::String("x".to_string()), MontyObject::Int(1)),
356
- (MontyObject::String("y".to_string()), MontyObject::Int(2)),
357
- ]
358
- .into(),
359
-
360
- frozen: false,
361
- }
362
- .into(),
363
- )
364
- }
365
- "make_user" => {
366
- assert!(args.len() == 1, "make_user requires 1 argument");
367
- let name = String::try_from(&args[0]).expect("make_user: first arg must be str");
368
- // Return an immutable User(name=name, active=True) dataclass
369
- DispatchResult::Sync(
370
- MontyObject::Dataclass {
371
- name: "User".to_string(),
372
- type_id: 0, // Test fixture has no real Python type
373
- field_names: vec!["name".to_string(), "active".to_string()],
374
- attrs: vec![
375
- (MontyObject::String("name".to_string()), MontyObject::String(name)),
376
- (MontyObject::String("active".to_string()), MontyObject::Bool(true)),
377
- ]
378
- .into(),
379
-
380
- frozen: true,
381
- }
382
- .into(),
383
- )
384
- }
385
- "make_empty" => {
386
- assert!(args.is_empty(), "make_empty requires no arguments");
387
- // Return an immutable empty dataclass with no fields
388
- DispatchResult::Sync(
389
- MontyObject::Dataclass {
390
- name: "Empty".to_string(),
391
- type_id: 0, // Test fixture has no real Python type
392
- field_names: vec![],
393
- attrs: vec![].into(),
394
-
395
- frozen: true,
396
- }
397
- .into(),
398
- )
399
- }
400
- "async_call" => {
401
- // async_call(x) -> coroutine that returns x
402
- // This is an async function - use run_pending() and resolve later
403
- assert!(args.len() == 1, "async_call requires 1 argument");
404
- DispatchResult::Async(args.into_iter().next().unwrap())
405
- }
406
- _ => panic!("Unknown external function: {name}"),
407
- }
408
- }
409
-
410
- /// Dispatches a dataclass method call to the appropriate test implementation.
411
- ///
412
- /// The first argument is always the dataclass instance (`self`). Known methods
413
- /// are implemented to mirror the Python dataclass methods in `iter_test_methods.py`.
414
- /// Unknown methods return `AttributeError`.
415
- fn dispatch_method_call(
416
- method_name: &str,
417
- args: &[MontyObject],
418
- kwargs: &[(MontyObject, MontyObject)],
419
- ) -> ExtFunctionResult {
420
- let class_name = match args.first() {
421
- Some(MontyObject::Dataclass { name, .. }) => name.as_str(),
422
- _ => "<unknown>",
423
- };
424
-
425
- match (class_name, method_name) {
426
- // Point.sum(self) -> int
427
- ("Point" | "MutablePoint", "sum") => {
428
- let (x, y) = extract_point_fields(&args[0]);
429
- MontyObject::Int(x + y).into()
430
- }
431
- // Point.add(self, dx, dy) -> Point
432
- ("Point", "add") => {
433
- assert!(args.len() == 3, "Point.add requires self, dx, dy");
434
- let (x, y) = extract_point_fields(&args[0]);
435
- let dx = i64::try_from(&args[1]).expect("dx must be int");
436
- let dy = i64::try_from(&args[2]).expect("dy must be int");
437
- MontyObject::Dataclass {
438
- name: "Point".to_string(),
439
- type_id: 0,
440
- field_names: vec!["x".to_string(), "y".to_string()],
441
- attrs: vec![
442
- (MontyObject::String("x".to_string()), MontyObject::Int(x + dx)),
443
- (MontyObject::String("y".to_string()), MontyObject::Int(y + dy)),
444
- ]
445
- .into(),
446
- frozen: true,
447
- }
448
- .into()
449
- }
450
- // Point.scale(self, factor) -> Point
451
- ("Point", "scale") => {
452
- assert!(args.len() == 2, "Point.scale requires self, factor");
453
- let (x, y) = extract_point_fields(&args[0]);
454
- let factor = i64::try_from(&args[1]).expect("factor must be int");
455
- MontyObject::Dataclass {
456
- name: "Point".to_string(),
457
- type_id: 0,
458
- field_names: vec!["x".to_string(), "y".to_string()],
459
- attrs: vec![
460
- (MontyObject::String("x".to_string()), MontyObject::Int(x * factor)),
461
- (MontyObject::String("y".to_string()), MontyObject::Int(y * factor)),
462
- ]
463
- .into(),
464
- frozen: true,
465
- }
466
- .into()
467
- }
468
- // Point.describe(self, label='point') -> str
469
- ("Point", "describe") => {
470
- let (x, y) = extract_point_fields(&args[0]);
471
- // Check positional arg first, then kwargs, then default
472
- let label = if args.len() > 1 {
473
- String::try_from(&args[1]).expect("label must be str")
474
- } else if let Some(kw_label) = get_kwarg_str(kwargs, "label") {
475
- kw_label
476
- } else {
477
- "point".to_string()
478
- };
479
- MontyObject::String(format!("{label}({x}, {y})")).into()
480
- }
481
- // MutablePoint.shift(self, dx, dy) -> None (mutates in-place via host)
482
- // Note: In the test runner, we can't actually mutate the dataclass in-place
483
- // since the host doesn't have direct heap access. Return None as the method
484
- // would in Python (the mutation happens inside Python's method body).
485
- // For test coverage purposes, we just return None.
486
- ("MutablePoint", "shift") => MontyObject::None.into(),
487
- // User.greeting(self) -> str
488
- ("User", "greeting") => {
489
- let name = extract_user_name(&args[0]);
490
- MontyObject::String(format!("Hello, {name}!")).into()
491
- }
492
- // Unknown method — return AttributeError
493
- _ => {
494
- let message = format!("'{class_name}' object has no attribute '{method_name}'");
495
- MontyException::new(ExcType::AttributeError, Some(message)).into()
496
- }
497
- }
498
- }
499
-
500
- /// Extracts (x, y) fields from a Point or MutablePoint `MontyObject::Dataclass`.
501
- fn extract_point_fields(obj: &MontyObject) -> (i64, i64) {
502
- match obj {
503
- MontyObject::Dataclass { attrs, .. } => {
504
- let mut x = 0i64;
505
- let mut y = 0i64;
506
- for (key, value) in attrs {
507
- if let MontyObject::String(k) = key {
508
- match k.as_str() {
509
- "x" => x = i64::try_from(value).expect("x must be int"),
510
- "y" => y = i64::try_from(value).expect("y must be int"),
511
- _ => {}
512
- }
513
- }
514
- }
515
- (x, y)
516
- }
517
- other => panic!("Expected Dataclass, got {other:?}"),
518
- }
519
- }
520
-
521
- /// Extracts a string kwarg value by key name.
522
- fn get_kwarg_str(kwargs: &[(MontyObject, MontyObject)], name: &str) -> Option<String> {
523
- for (key, value) in kwargs {
524
- if let MontyObject::String(key_str) = key
525
- && key_str == name
526
- {
527
- return Some(String::try_from(value).expect("kwarg value must be str"));
528
- }
529
- }
530
- None
531
- }
532
-
533
- /// Extracts the `name` field from a User `MontyObject::Dataclass`.
534
- fn extract_user_name(obj: &MontyObject) -> String {
535
- match obj {
536
- MontyObject::Dataclass { attrs, .. } => {
537
- for (key, value) in attrs {
538
- if let MontyObject::String(k) = key
539
- && k == "name"
540
- {
541
- return String::try_from(value).expect("name must be str");
542
- }
543
- }
544
- panic!("User dataclass has no 'name' field");
545
- }
546
- other => panic!("Expected Dataclass, got {other:?}"),
547
- }
548
- }
549
-
550
- // =============================================================================
551
- // Virtual Filesystem for OS Call Tests
552
- // =============================================================================
553
-
554
- /// Virtual file entry for OS call tests (static VFS).
555
- struct StaticVirtualFile {
556
- content: &'static [u8],
557
- mode: i64,
558
- }
559
-
560
- /// Virtual file entry (owned, for unified VFS lookups).
561
- struct VirtualFile {
562
- content: Vec<u8>,
563
- mode: i64,
564
- }
565
-
566
- /// Virtual filesystem modification time (arbitrary fixed timestamp).
567
- const VFS_MTIME: f64 = 1_700_000_000.0;
568
-
569
- /// Virtual filesystem for testing Path methods.
570
- ///
571
- /// Structure:
572
- /// ```text
573
- /// /virtual/
574
- /// ├── file.txt (file, 644, "hello world\n")
575
- /// ├── data.bin (file, 644, b"\x00\x01\x02\x03")
576
- /// ├── empty.txt (file, 644, "")
577
- /// ├── subdir/
578
- /// │ ├── nested.txt (file, 644, "nested content")
579
- /// │ └── deep/
580
- /// │ └── file.txt (file, 644, "deep")
581
- /// └── readonly.txt (file, 444, "readonly")
582
- ///
583
- /// /nonexistent (does not exist)
584
- /// ```
585
- fn get_static_virtual_file(path: &str) -> Option<StaticVirtualFile> {
586
- match path {
587
- "/virtual/file.txt" => Some(StaticVirtualFile {
588
- content: b"hello world\n",
589
- mode: 0o644,
590
- }),
591
- "/virtual/data.bin" => Some(StaticVirtualFile {
592
- content: b"\x00\x01\x02\x03",
593
- mode: 0o644,
594
- }),
595
- "/virtual/empty.txt" => Some(StaticVirtualFile {
596
- content: b"",
597
- mode: 0o644,
598
- }),
599
- "/virtual/subdir/nested.txt" => Some(StaticVirtualFile {
600
- content: b"nested content",
601
- mode: 0o644,
602
- }),
603
- "/virtual/subdir/deep/file.txt" => Some(StaticVirtualFile {
604
- content: b"deep",
605
- mode: 0o644,
606
- }),
607
- "/virtual/readonly.txt" => Some(StaticVirtualFile {
608
- content: b"readonly",
609
- mode: 0o444,
610
- }),
611
- _ => None,
612
- }
613
- }
614
-
615
- /// Gets a virtual file, checking the mutable layer first, then falling back to static.
616
- fn get_virtual_file(path: &str) -> Option<VirtualFile> {
617
- // Check mutable layer first
618
- let mutable_result = MUTABLE_VFS.with(|vfs| {
619
- let vfs = vfs.borrow();
620
- // Check if deleted
621
- if vfs.deleted_files.contains(path) {
622
- return Some(None);
623
- }
624
- // Check if exists in mutable layer
625
- if let Some((content, mode)) = vfs.files.get(path) {
626
- return Some(Some(VirtualFile {
627
- content: content.clone(),
628
- mode: *mode,
629
- }));
630
- }
631
- None
632
- });
633
-
634
- match mutable_result {
635
- Some(Some(file)) => Some(file),
636
- Some(None) => None, // File was deleted
637
- None => {
638
- // Fall back to static VFS
639
- get_static_virtual_file(path).map(|f| VirtualFile {
640
- content: f.content.to_vec(),
641
- mode: f.mode,
642
- })
643
- }
644
- }
645
- }
646
-
647
- // =============================================================================
648
- // Mutable VFS Layer (Thread-Local Storage for Write Operations)
649
- // =============================================================================
650
-
651
- /// Mutable state for the virtual filesystem, supporting write operations.
652
- ///
653
- /// This layer sits on top of the static VFS and allows tests to create, modify, and
654
- /// delete files and directories. The state is thread-local so tests don't interfere
655
- /// with each other.
656
- #[derive(Default)]
657
- struct MutableVfs {
658
- /// Files created or modified during test execution.
659
- files: HashMap<String, (Vec<u8>, i64)>, // path -> (content, mode)
660
- /// Directories created during test execution.
661
- dirs: HashSet<String>,
662
- /// Files deleted during test execution (shadows static VFS entries).
663
- deleted_files: HashSet<String>,
664
- /// Directories deleted during test execution.
665
- deleted_dirs: HashSet<String>,
666
- }
667
-
668
- thread_local! {
669
- /// Thread-local mutable VFS state.
670
- static MUTABLE_VFS: RefCell<MutableVfs> = RefCell::new(MutableVfs::default());
671
- }
672
-
673
- /// Resets the mutable VFS state for a new test.
674
- fn reset_mutable_vfs() {
675
- MUTABLE_VFS.with(|vfs| {
676
- *vfs.borrow_mut() = MutableVfs::default();
677
- });
678
- }
679
-
680
- /// Check if the given path is a directory in the virtual filesystem.
681
- fn is_virtual_dir(path: &str) -> bool {
682
- // Check mutable layer first
683
- let result = MUTABLE_VFS.with(|vfs| {
684
- let vfs = vfs.borrow();
685
- if vfs.deleted_dirs.contains(path) {
686
- return Some(false);
687
- }
688
- if vfs.dirs.contains(path) {
689
- return Some(true);
690
- }
691
- None
692
- });
693
- if let Some(is_dir) = result {
694
- return is_dir;
695
- }
696
- // Fall back to static VFS
697
- matches!(path, "/virtual" | "/virtual/subdir" | "/virtual/subdir/deep")
698
- }
699
-
700
- /// Get directory entries for a virtual directory.
701
- fn get_virtual_dir_entries(path: &str) -> Option<Vec<String>> {
702
- // First check if the directory exists
703
- if !is_virtual_dir(path) {
704
- return None;
705
- }
706
-
707
- // Get static entries (if any)
708
- let static_entries: Vec<&'static str> = match path {
709
- "/virtual" => vec![
710
- "/virtual/file.txt",
711
- "/virtual/data.bin",
712
- "/virtual/empty.txt",
713
- "/virtual/subdir",
714
- "/virtual/readonly.txt",
715
- ],
716
- "/virtual/subdir" => vec!["/virtual/subdir/nested.txt", "/virtual/subdir/deep"],
717
- "/virtual/subdir/deep" => vec!["/virtual/subdir/deep/file.txt"],
718
- _ => vec![],
719
- };
720
-
721
- // Combine with mutable layer
722
- MUTABLE_VFS.with(|vfs| {
723
- let vfs = vfs.borrow();
724
- let mut entries: HashSet<String> = static_entries
725
- .iter()
726
- .filter(|e| {
727
- let s: &str = e;
728
- !vfs.deleted_files.contains(s) && !vfs.deleted_dirs.contains(s)
729
- })
730
- .map(|e| (*e).to_owned())
731
- .collect();
732
-
733
- // Add mutable files and dirs in this directory
734
- let prefix = if path.ends_with('/') {
735
- path.to_owned()
736
- } else {
737
- format!("{path}/")
738
- };
739
- for file_path in vfs.files.keys() {
740
- if file_path.starts_with(&prefix) {
741
- // Only include direct children (not nested)
742
- let rest = &file_path[prefix.len()..];
743
- if !rest.contains('/') {
744
- entries.insert(file_path.clone());
745
- }
746
- }
747
- }
748
- for dir_path in &vfs.dirs {
749
- if dir_path.starts_with(&prefix) {
750
- let rest = &dir_path[prefix.len()..];
751
- if !rest.contains('/') {
752
- entries.insert(dir_path.clone());
753
- }
754
- }
755
- }
756
-
757
- Some(entries.into_iter().collect())
758
- })
759
- }
760
-
761
- /// Helper to get a boolean kwarg by name.
762
- fn get_kwarg_bool(kwargs: &[(MontyObject, MontyObject)], name: &str) -> bool {
763
- for (key, value) in kwargs {
764
- if let MontyObject::String(key_str) = key
765
- && key_str == name
766
- {
767
- return matches!(value, MontyObject::Bool(true));
768
- }
769
- }
770
- false
771
- }
772
-
773
- /// Dispatches an OS function call using the virtual filesystem.
774
- ///
775
- /// Returns an `ExternalResult` to pass back to the Monty interpreter.
776
- /// Raises `FileNotFoundError` for missing files/directories.
777
- #[expect(clippy::cast_possible_wrap)] // Virtual file sizes are tiny, no wrap possible
778
- fn dispatch_os_call(
779
- function: OsFunction,
780
- args: &[MontyObject],
781
- kwargs: &[(MontyObject, MontyObject)],
782
- ) -> ExtFunctionResult {
783
- // Handle GetEnviron first as it takes no path argument
784
- if function == OsFunction::GetEnviron {
785
- // Return the virtual environment as a dict
786
- let env_dict = vec![
787
- (
788
- MontyObject::String("VIRTUAL_HOME".to_owned()),
789
- MontyObject::String("/virtual/home".to_owned()),
790
- ),
791
- (
792
- MontyObject::String("VIRTUAL_USER".to_owned()),
793
- MontyObject::String("testuser".to_owned()),
794
- ),
795
- (
796
- MontyObject::String("VIRTUAL_EMPTY".to_owned()),
797
- MontyObject::String(String::new()),
798
- ),
799
- ];
800
- return MontyObject::Dict(env_dict.into()).into();
801
- }
802
-
803
- // Extract path from MontyObject::Path (or String for backwards compatibility)
804
- let path = match &args[0] {
805
- MontyObject::Path(p) => p.clone(),
806
- MontyObject::String(s) => s.clone(),
807
- other => panic!("OS call: first arg must be path, got {other:?}"),
808
- };
809
-
810
- match function {
811
- OsFunction::GetEnviron => unreachable!("handled above"),
812
- OsFunction::Exists => {
813
- let exists = get_virtual_file(&path).is_some() || is_virtual_dir(&path);
814
- MontyObject::Bool(exists).into()
815
- }
816
- OsFunction::IsFile => {
817
- let is_file = get_virtual_file(&path).is_some();
818
- MontyObject::Bool(is_file).into()
819
- }
820
- OsFunction::IsDir => {
821
- let is_dir = is_virtual_dir(&path);
822
- MontyObject::Bool(is_dir).into()
823
- }
824
- OsFunction::IsSymlink => {
825
- // Virtual filesystem doesn't have symlinks
826
- MontyObject::Bool(false).into()
827
- }
828
- OsFunction::ReadText => {
829
- if let Some(file) = get_virtual_file(&path) {
830
- match std::str::from_utf8(&file.content) {
831
- Ok(text) => MontyObject::String(text.to_owned()).into(),
832
- Err(_) => MontyException::new(
833
- ExcType::UnicodeDecodeError,
834
- Some("'utf-8' codec can't decode bytes".to_owned()),
835
- )
836
- .into(),
837
- }
838
- } else {
839
- MontyException::new(
840
- ExcType::FileNotFoundError,
841
- Some(format!("[Errno 2] No such file or directory: '{path}'")),
842
- )
843
- .into()
844
- }
845
- }
846
- OsFunction::ReadBytes => {
847
- if let Some(file) = get_virtual_file(&path) {
848
- MontyObject::Bytes(file.content).into()
849
- } else {
850
- MontyException::new(
851
- ExcType::FileNotFoundError,
852
- Some(format!("[Errno 2] No such file or directory: '{path}'")),
853
- )
854
- .into()
855
- }
856
- }
857
- OsFunction::Stat => {
858
- if let Some(file) = get_virtual_file(&path) {
859
- file_stat(file.mode, file.content.len() as i64, VFS_MTIME).into()
860
- } else if is_virtual_dir(&path) {
861
- dir_stat(0o755, VFS_MTIME).into()
862
- } else {
863
- MontyException::new(
864
- ExcType::FileNotFoundError,
865
- Some(format!("[Errno 2] No such file or directory: '{path}'")),
866
- )
867
- .into()
868
- }
869
- }
870
- OsFunction::Iterdir => {
871
- if let Some(entries) = get_virtual_dir_entries(&path) {
872
- // Return Path objects, not strings
873
- let list: Vec<MontyObject> = entries.into_iter().map(MontyObject::Path).collect();
874
- MontyObject::List(list).into()
875
- } else {
876
- MontyException::new(
877
- ExcType::FileNotFoundError,
878
- Some(format!("[Errno 2] No such file or directory: '{path}'")),
879
- )
880
- .into()
881
- }
882
- }
883
- OsFunction::Resolve | OsFunction::Absolute => {
884
- // For virtual paths, return as-is (they're already absolute)
885
- MontyObject::String(path).into()
886
- }
887
- OsFunction::Getenv => {
888
- // Virtual environment for testing os.getenv()
889
- // args[0] is key, args[1] is default (may be None)
890
- let key = String::try_from(&args[0]).expect("getenv: first arg must be key string");
891
- let default = &args[1];
892
-
893
- // Provide a few test environment variables
894
- let value = match key.as_str() {
895
- "VIRTUAL_HOME" => Some("/virtual/home"),
896
- "VIRTUAL_USER" => Some("testuser"),
897
- "VIRTUAL_EMPTY" => Some(""),
898
- _ => None,
899
- };
900
-
901
- if let Some(v) = value {
902
- MontyObject::String(v.to_owned()).into()
903
- } else if matches!(default, MontyObject::None) {
904
- MontyObject::None.into()
905
- } else {
906
- // Return the default value
907
- default.clone().into()
908
- }
909
- }
910
- OsFunction::WriteText => {
911
- // args[0] is path, args[1] is text content
912
- let text = String::try_from(&args[1]).expect("write_text: second arg must be string");
913
- MUTABLE_VFS.with(|vfs| {
914
- let mut vfs = vfs.borrow_mut();
915
- vfs.files.insert(path.clone(), (text.into_bytes(), 0o644));
916
- vfs.deleted_files.remove(&path);
917
- });
918
- // write_text returns the number of bytes written
919
- let byte_count = MUTABLE_VFS.with(|vfs| vfs.borrow().files.get(&path).map_or(0, |(c, _)| c.len()));
920
- MontyObject::Int(byte_count as i64).into()
921
- }
922
- OsFunction::WriteBytes => {
923
- // args[0] is path, args[1] is bytes content
924
- let bytes = match &args[1] {
925
- MontyObject::Bytes(b) => b.clone(),
926
- other => panic!("write_bytes: second arg must be bytes, got {other:?}"),
927
- };
928
- let byte_count = bytes.len();
929
- MUTABLE_VFS.with(|vfs| {
930
- let mut vfs = vfs.borrow_mut();
931
- vfs.files.insert(path.clone(), (bytes, 0o644));
932
- vfs.deleted_files.remove(&path);
933
- });
934
- // write_bytes returns the number of bytes written
935
- MontyObject::Int(byte_count as i64).into()
936
- }
937
- OsFunction::Mkdir => {
938
- // Check for parents and exist_ok in kwargs (e.g., mkdir(parents=True, exist_ok=True))
939
- let parents = get_kwarg_bool(kwargs, "parents");
940
- let exist_ok = get_kwarg_bool(kwargs, "exist_ok");
941
-
942
- // Check if already exists
943
- if is_virtual_dir(&path) {
944
- if exist_ok {
945
- return MontyObject::None.into();
946
- }
947
- return MontyException::new(ExcType::OSError, Some(format!("[Errno 17] File exists: '{path}'"))).into();
948
- }
949
-
950
- // Check parent directory
951
- let parent = std::path::Path::new(&path)
952
- .parent()
953
- .map(|p| p.to_string_lossy().to_string())
954
- .unwrap_or_default();
955
- if !parent.is_empty() && !is_virtual_dir(&parent) {
956
- if parents {
957
- // Create parent directories recursively
958
- create_parent_dirs(&parent);
959
- } else {
960
- return MontyException::new(
961
- ExcType::FileNotFoundError,
962
- Some(format!("[Errno 2] No such file or directory: '{path}'")),
963
- )
964
- .into();
965
- }
966
- }
967
-
968
- MUTABLE_VFS.with(|vfs| {
969
- let mut vfs = vfs.borrow_mut();
970
- vfs.deleted_dirs.remove(&path);
971
- vfs.dirs.insert(path);
972
- });
973
- MontyObject::None.into()
974
- }
975
- OsFunction::Unlink => {
976
- // args[0] is path
977
- if get_virtual_file(&path).is_some() {
978
- MUTABLE_VFS.with(|vfs| {
979
- let mut vfs = vfs.borrow_mut();
980
- vfs.files.remove(&path);
981
- vfs.deleted_files.insert(path);
982
- });
983
- MontyObject::None.into()
984
- } else {
985
- MontyException::new(
986
- ExcType::FileNotFoundError,
987
- Some(format!("[Errno 2] No such file or directory: '{path}'")),
988
- )
989
- .into()
990
- }
991
- }
992
- OsFunction::Rmdir => {
993
- // args[0] is path
994
- if is_virtual_dir(&path) {
995
- MUTABLE_VFS.with(|vfs| {
996
- let mut vfs = vfs.borrow_mut();
997
- vfs.dirs.remove(&path);
998
- vfs.deleted_dirs.insert(path);
999
- });
1000
- MontyObject::None.into()
1001
- } else {
1002
- MontyException::new(
1003
- ExcType::FileNotFoundError,
1004
- Some(format!("[Errno 2] No such file or directory: '{path}'")),
1005
- )
1006
- .into()
1007
- }
1008
- }
1009
- OsFunction::Rename => {
1010
- // args[0] is src path, args[1] is dest path
1011
- let dest = match &args[1] {
1012
- MontyObject::Path(p) => p.clone(),
1013
- MontyObject::String(s) => s.clone(),
1014
- other => panic!("rename: second arg must be path, got {other:?}"),
1015
- };
1016
-
1017
- if let Some(file) = get_virtual_file(&path) {
1018
- MUTABLE_VFS.with(|vfs| {
1019
- let mut vfs = vfs.borrow_mut();
1020
- // Remove from old location
1021
- vfs.files.remove(&path);
1022
- vfs.deleted_files.insert(path);
1023
- // Add to new location
1024
- vfs.files.insert(dest, (file.content, file.mode));
1025
- });
1026
- MontyObject::None.into()
1027
- } else if is_virtual_dir(&path) {
1028
- MUTABLE_VFS.with(|vfs| {
1029
- let mut vfs = vfs.borrow_mut();
1030
- vfs.dirs.remove(&path);
1031
- vfs.deleted_dirs.insert(path);
1032
- vfs.dirs.insert(dest);
1033
- });
1034
- MontyObject::None.into()
1035
- } else {
1036
- MontyException::new(
1037
- ExcType::FileNotFoundError,
1038
- Some(format!("[Errno 2] No such file or directory: '{path}'")),
1039
- )
1040
- .into()
1041
- }
1042
- }
1043
- }
1044
- }
1045
-
1046
- /// Helper to create parent directories recursively.
1047
- fn create_parent_dirs(path: &str) {
1048
- if is_virtual_dir(path) {
1049
- return;
1050
- }
1051
- // Create parent first
1052
- if let Some(parent) = std::path::Path::new(path).parent() {
1053
- let parent_str = parent.to_string_lossy().to_string();
1054
- if !parent_str.is_empty() {
1055
- create_parent_dirs(&parent_str);
1056
- }
1057
- }
1058
- // Create this directory
1059
- MUTABLE_VFS.with(|vfs| {
1060
- let mut vfs = vfs.borrow_mut();
1061
- vfs.dirs.insert(path.to_owned());
1062
- });
1063
- }
1064
-
1065
- /// Represents a test failure with details about expected vs actual values.
1066
- #[derive(Debug)]
1067
- struct TestFailure {
1068
- test_name: String,
1069
- kind: String,
1070
- expected: String,
1071
- actual: String,
1072
- }
1073
-
1074
- impl std::fmt::Display for TestFailure {
1075
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1076
- writeln!(
1077
- f,
1078
- "[{}] {} mismatch\ngot {:?}\ndiff:",
1079
- self.test_name, self.kind, self.actual
1080
- )?;
1081
-
1082
- for change in TextDiff::from_lines(&self.expected, &self.actual).iter_all_changes() {
1083
- write!(f, "{}{}", change.tag(), change)?;
1084
- }
1085
- Ok(())
1086
- }
1087
- }
1088
-
1089
- /// Try to run a test, returning Ok(()) on success or Err with failure details.
1090
- ///
1091
- /// This function executes Python code via the MontyRun and validates the result
1092
- /// against the expected outcome specified in the fixture.
1093
- fn try_run_test(path: &Path, code: &str, expectation: &Expectation) -> Result<(), TestFailure> {
1094
- let test_name = path.strip_prefix("test_cases/").unwrap_or(path).display().to_string();
1095
-
1096
- // Reset the mutable VFS for each test
1097
- reset_mutable_vfs();
1098
-
1099
- // Handle ref-count-return tests separately since they need run_ref_counts()
1100
- #[cfg(feature = "ref-count-return")]
1101
- if let Expectation::RefCounts(expected) = expectation {
1102
- match MontyRun::new(code.to_owned(), &test_name, vec![]) {
1103
- Ok(ex) => {
1104
- let result = ex.run_ref_counts(vec![]);
1105
- match result {
1106
- Ok(monty::RefCountOutput {
1107
- counts,
1108
- unique_refs,
1109
- heap_count,
1110
- ..
1111
- }) => {
1112
- // Strict matching: verify all heap objects are accounted for by variables
1113
- if unique_refs != heap_count {
1114
- return Err(TestFailure {
1115
- test_name,
1116
- kind: "Strict matching".to_string(),
1117
- expected: format!("{heap_count} heap objects"),
1118
- actual: format!("{unique_refs} referenced by variables, counts: {counts:?}"),
1119
- });
1120
- }
1121
- if &counts != expected {
1122
- return Err(TestFailure {
1123
- test_name,
1124
- kind: "ref-counts".to_string(),
1125
- expected: format!("{expected:?}"),
1126
- actual: format!("{counts:?}"),
1127
- });
1128
- }
1129
- return Ok(());
1130
- }
1131
- Err(e) => {
1132
- return Err(TestFailure {
1133
- test_name,
1134
- kind: "Runtime".to_string(),
1135
- expected: "success".to_string(),
1136
- actual: e.to_string(),
1137
- });
1138
- }
1139
- }
1140
- }
1141
- Err(parse_err) => {
1142
- return Err(TestFailure {
1143
- test_name,
1144
- kind: "Parse".to_string(),
1145
- expected: "success".to_string(),
1146
- actual: parse_err.to_string(),
1147
- });
1148
- }
1149
- }
1150
- }
1151
-
1152
- match MontyRun::new(code.to_owned(), &test_name, vec![]) {
1153
- Ok(ex) => {
1154
- let limits = ResourceLimits::new().max_recursion_depth(Some(TEST_RECURSION_LIMIT));
1155
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
1156
- match result {
1157
- Ok(obj) => match expectation {
1158
- Expectation::ReturnStr(expected) => {
1159
- let output = obj.to_string();
1160
- if output != *expected {
1161
- return Err(TestFailure {
1162
- test_name,
1163
- kind: "str()".to_string(),
1164
- expected: expected.clone(),
1165
- actual: output,
1166
- });
1167
- }
1168
- }
1169
- Expectation::Return(expected) => {
1170
- let output = obj.py_repr();
1171
- if output != *expected {
1172
- return Err(TestFailure {
1173
- test_name,
1174
- kind: "py_repr()".to_string(),
1175
- expected: expected.clone(),
1176
- actual: output,
1177
- });
1178
- }
1179
- }
1180
- Expectation::ReturnType(expected) => {
1181
- let output = obj.type_name();
1182
- if output != expected {
1183
- return Err(TestFailure {
1184
- test_name,
1185
- kind: "type_name()".to_string(),
1186
- expected: expected.clone(),
1187
- actual: output.to_string(),
1188
- });
1189
- }
1190
- }
1191
- #[cfg(not(feature = "ref-count-return"))]
1192
- Expectation::RefCounts(_) => {
1193
- // Skip ref-count tests when feature is disabled
1194
- }
1195
- Expectation::NoException => {
1196
- // Success - code ran without exception as expected
1197
- }
1198
- Expectation::Raise(expected) | Expectation::Traceback(expected) => {
1199
- return Err(TestFailure {
1200
- test_name,
1201
- kind: "Exception".to_string(),
1202
- expected: expected.clone(),
1203
- actual: "no exception raised".to_string(),
1204
- });
1205
- }
1206
- #[cfg(feature = "ref-count-return")]
1207
- Expectation::RefCounts(_) => unreachable!(),
1208
- },
1209
- Err(e) => {
1210
- if let Expectation::Raise(expected) = expectation {
1211
- let output = e.py_repr();
1212
- if output != *expected {
1213
- return Err(TestFailure {
1214
- test_name,
1215
- kind: "Exception".to_string(),
1216
- expected: expected.clone(),
1217
- actual: output,
1218
- });
1219
- }
1220
- } else if let Expectation::Traceback(expected) = expectation {
1221
- let output = e.to_string();
1222
- if output != *expected {
1223
- return Err(TestFailure {
1224
- test_name,
1225
- kind: "Traceback".to_string(),
1226
- expected: expected.clone(),
1227
- actual: output,
1228
- });
1229
- }
1230
- } else {
1231
- return Err(TestFailure {
1232
- test_name,
1233
- kind: "Unexpected error".to_string(),
1234
- expected: "success".to_string(),
1235
- actual: e.to_string(),
1236
- });
1237
- }
1238
- }
1239
- }
1240
- }
1241
- Err(parse_err) => {
1242
- if let Expectation::Raise(expected) = expectation {
1243
- let output = parse_err.py_repr();
1244
- if output != *expected {
1245
- return Err(TestFailure {
1246
- test_name,
1247
- kind: "Parse error".to_string(),
1248
- expected: expected.clone(),
1249
- actual: output,
1250
- });
1251
- }
1252
- } else if let Expectation::Traceback(expected) = expectation {
1253
- let output = parse_err.to_string();
1254
- if output != *expected {
1255
- return Err(TestFailure {
1256
- test_name,
1257
- kind: "Traceback".to_string(),
1258
- expected: expected.clone(),
1259
- actual: output,
1260
- });
1261
- }
1262
- } else {
1263
- return Err(TestFailure {
1264
- test_name,
1265
- kind: "Unexpected parse error".to_string(),
1266
- expected: "success".to_string(),
1267
- actual: parse_err.to_string(),
1268
- });
1269
- }
1270
- }
1271
- }
1272
- Ok(())
1273
- }
1274
-
1275
- /// Try to run a test using MontyRun with external function support.
1276
- ///
1277
- /// This function handles tests marked with `# call-external` directive by using the
1278
- /// iterative executor API and providing implementations for predefined external functions.
1279
- fn try_run_iter_test(path: &Path, code: &str, expectation: &Expectation) -> Result<(), TestFailure> {
1280
- let test_name = path.strip_prefix("test_cases/").unwrap_or(path).display().to_string();
1281
-
1282
- // Reset the mutable VFS for each test
1283
- reset_mutable_vfs();
1284
-
1285
- // Ref-counting tests not supported in iter mode
1286
- #[cfg(feature = "ref-count-return")]
1287
- if matches!(expectation, Expectation::RefCounts(_)) {
1288
- return Err(TestFailure {
1289
- test_name,
1290
- kind: "Configuration".to_string(),
1291
- expected: "non-refcount test".to_string(),
1292
- actual: "ref-counts tests are not supported in iter mode".to_string(),
1293
- });
1294
- }
1295
-
1296
- let exec = match MontyRun::new(code.to_owned(), &test_name, vec![]) {
1297
- Ok(e) => e,
1298
- Err(parse_err) => {
1299
- if let Expectation::Raise(expected) = expectation {
1300
- let output = parse_err.py_repr();
1301
- if output != *expected {
1302
- return Err(TestFailure {
1303
- test_name,
1304
- kind: "Parse error".to_string(),
1305
- expected: expected.clone(),
1306
- actual: output,
1307
- });
1308
- }
1309
- return Ok(());
1310
- } else if let Expectation::Traceback(expected) = expectation {
1311
- let output = parse_err.to_string();
1312
- if output != *expected {
1313
- return Err(TestFailure {
1314
- test_name,
1315
- kind: "Traceback".to_string(),
1316
- expected: expected.clone(),
1317
- actual: output,
1318
- });
1319
- }
1320
- return Ok(());
1321
- }
1322
- return Err(TestFailure {
1323
- test_name,
1324
- kind: "Unexpected parse error".to_string(),
1325
- expected: "success".to_string(),
1326
- actual: parse_err.to_string(),
1327
- });
1328
- }
1329
- };
1330
-
1331
- // Run execution loop, handling external function calls until complete
1332
- let result = run_iter_loop(exec);
1333
-
1334
- match result {
1335
- Ok(obj) => match expectation {
1336
- Expectation::ReturnStr(expected) => {
1337
- let output = obj.to_string();
1338
- if output != *expected {
1339
- return Err(TestFailure {
1340
- test_name,
1341
- kind: "str()".to_string(),
1342
- expected: expected.clone(),
1343
- actual: output,
1344
- });
1345
- }
1346
- }
1347
- Expectation::Return(expected) => {
1348
- let output = obj.py_repr();
1349
- if output != *expected {
1350
- return Err(TestFailure {
1351
- test_name,
1352
- kind: "py_repr()".to_string(),
1353
- expected: expected.clone(),
1354
- actual: output,
1355
- });
1356
- }
1357
- }
1358
- Expectation::ReturnType(expected) => {
1359
- let output = obj.type_name();
1360
- if output != expected {
1361
- return Err(TestFailure {
1362
- test_name,
1363
- kind: "type_name()".to_string(),
1364
- expected: expected.clone(),
1365
- actual: output.to_string(),
1366
- });
1367
- }
1368
- }
1369
- #[cfg(not(feature = "ref-count-return"))]
1370
- Expectation::RefCounts(_) => {}
1371
- Expectation::NoException => {}
1372
- Expectation::Raise(expected) | Expectation::Traceback(expected) => {
1373
- return Err(TestFailure {
1374
- test_name,
1375
- kind: "Exception".to_string(),
1376
- expected: expected.clone(),
1377
- actual: "no exception raised".to_string(),
1378
- });
1379
- }
1380
- #[cfg(feature = "ref-count-return")]
1381
- Expectation::RefCounts(_) => unreachable!(),
1382
- },
1383
- Err(e) => {
1384
- if let Expectation::Raise(expected) = expectation {
1385
- let output = e.py_repr();
1386
- if output != *expected {
1387
- return Err(TestFailure {
1388
- test_name,
1389
- kind: "Exception".to_string(),
1390
- expected: expected.clone(),
1391
- actual: output,
1392
- });
1393
- }
1394
- } else if let Expectation::Traceback(expected) = expectation {
1395
- let output = e.to_string();
1396
- if output != *expected {
1397
- return Err(TestFailure {
1398
- test_name,
1399
- kind: "Traceback".to_string(),
1400
- expected: expected.clone(),
1401
- actual: output,
1402
- });
1403
- }
1404
- } else {
1405
- return Err(TestFailure {
1406
- test_name,
1407
- kind: "Unexpected error".to_string(),
1408
- expected: "success".to_string(),
1409
- actual: e.to_string(),
1410
- });
1411
- }
1412
- }
1413
- }
1414
- Ok(())
1415
- }
1416
-
1417
- /// Execute the iter loop, dispatching external function calls until complete.
1418
- ///
1419
- /// When `ref-count-panic` feature is NOT enabled, this function also tests
1420
- /// serialization round-trips by dumping and loading the execution state at
1421
- /// each external function call boundary.
1422
- ///
1423
- /// Supports both synchronous and asynchronous external functions:
1424
- /// - Sync functions: result is passed immediately via `state.run()`
1425
- /// - Async functions: `state.run_pending()` creates a future, resolved via `ResolveFutures`
1426
- fn run_iter_loop(exec: MontyRun) -> Result<MontyObject, MontyException> {
1427
- let limits = ResourceLimits::new().max_recursion_depth(Some(TEST_RECURSION_LIMIT));
1428
- let mut progress = exec.start(vec![], LimitedTracker::new(limits), PrintWriter::Stdout)?;
1429
-
1430
- // Track pending async calls: (call_id, result_value)
1431
- let mut pending_results: Vec<(u32, MontyObject)> = Vec::new();
1432
-
1433
- loop {
1434
- // Test serialization round-trip at each step (skip when ref-count-panic is enabled
1435
- // since the old RunProgress would panic on drop without proper cleanup)
1436
- #[cfg(not(feature = "ref-count-panic"))]
1437
- {
1438
- let bytes = progress.dump().expect("failed to dump RunProgress");
1439
- progress = RunProgress::load(&bytes).expect("failed to load RunProgress");
1440
- }
1441
-
1442
- match progress {
1443
- RunProgress::Complete(result) => return Ok(result),
1444
- RunProgress::FunctionCall(call) => {
1445
- // Method calls on dataclasses are dispatched to the host.
1446
- // Dispatch known methods; return AttributeError for unknown ones.
1447
- if call.method_call {
1448
- let result = dispatch_method_call(&call.function_name, &call.args, &call.kwargs);
1449
- progress = call.resume(result, PrintWriter::Stdout)?;
1450
- continue;
1451
- }
1452
- let dispatch_result = dispatch_external_call(&call.function_name, call.args.clone());
1453
- match dispatch_result {
1454
- DispatchResult::Sync(return_value) => {
1455
- progress = call.resume(return_value, PrintWriter::Stdout)?;
1456
- }
1457
- DispatchResult::Async(result_value) => {
1458
- // Store the result for later resolution
1459
- pending_results.push((call.call_id, result_value));
1460
- // Continue execution with a pending future
1461
- progress = call.resume_pending(PrintWriter::Stdout)?;
1462
- }
1463
- }
1464
- }
1465
- RunProgress::ResolveFutures(state) => {
1466
- // Resolve all pending futures that we have results for
1467
- let results: Vec<(u32, ExtFunctionResult)> = state
1468
- .pending_call_ids()
1469
- .iter()
1470
- .filter_map(|p| {
1471
- pending_results.iter().position(|(id, _)| id == p).map(|idx| {
1472
- let (call_id, value) = pending_results.remove(idx);
1473
- (call_id, ExtFunctionResult::Return(value))
1474
- })
1475
- })
1476
- .collect();
1477
-
1478
- assert!(
1479
- !results.is_empty(),
1480
- "ResolveFutures: no results available for pending calls: {:?}",
1481
- state.pending_call_ids().iter().collect::<Vec<_>>()
1482
- );
1483
-
1484
- progress = state.resume(results, PrintWriter::Stdout)?;
1485
- }
1486
- RunProgress::NameLookup(lookup) => {
1487
- let result = match lookup.name.as_str() {
1488
- // External functions — resolved as callable Function objects
1489
- "add_ints" | "concat_strings" | "return_value" | "get_list" | "raise_error" | "make_point"
1490
- | "make_mutable_point" | "make_user" | "make_empty" | "async_call" => {
1491
- NameLookupResult::Value(MontyObject::Function {
1492
- name: lookup.name.clone(),
1493
- docstring: None,
1494
- })
1495
- }
1496
- // Non-function constants — resolved as plain values
1497
- "CONST_INT" => NameLookupResult::Value(MontyObject::Int(42)),
1498
- "CONST_STR" => NameLookupResult::Value(MontyObject::String("hello".to_string())),
1499
- #[expect(clippy::approx_constant, reason = "3.14 is the intended test value")]
1500
- "CONST_FLOAT" => NameLookupResult::Value(MontyObject::Float(3.14)),
1501
- "CONST_BOOL" => NameLookupResult::Value(MontyObject::Bool(true)),
1502
- "CONST_LIST" => NameLookupResult::Value(MontyObject::List(vec![
1503
- MontyObject::Int(1),
1504
- MontyObject::Int(2),
1505
- MontyObject::Int(3),
1506
- ])),
1507
- "CONST_NONE" => NameLookupResult::Value(MontyObject::None),
1508
- // Unknown names → NameError
1509
- _ => NameLookupResult::Undefined,
1510
- };
1511
- progress = lookup.resume(result, PrintWriter::Stdout)?;
1512
- }
1513
- RunProgress::OsCall(call) => {
1514
- let result = dispatch_os_call(call.function, &call.args, &call.kwargs);
1515
- progress = call.resume(result, PrintWriter::Stdout)?;
1516
- }
1517
- }
1518
- }
1519
- }
1520
-
1521
- /// Split Python code into statements and a final expression to evaluate.
1522
- ///
1523
- /// For Return expectations, the last non-empty line is the expression to evaluate.
1524
- /// For Raise/NoException, the entire code is statements (returns None for expression).
1525
- ///
1526
- /// Returns (statements_code, optional_final_expression).
1527
- fn split_code_for_module(code: &str, need_return_value: bool) -> (String, Option<String>) {
1528
- let lines: Vec<&str> = code.lines().collect();
1529
-
1530
- // Find the last non-empty line
1531
- let last_idx = lines
1532
- .iter()
1533
- .rposition(|line| !line.trim().is_empty())
1534
- .expect("Empty code");
1535
-
1536
- if need_return_value {
1537
- let last_line = lines[last_idx].trim();
1538
-
1539
- // Check if the last line is a statement (can't be evaluated as an expression)
1540
- // Matches both `assert expr` and `assert(expr)` forms
1541
- if last_line.starts_with("assert ") || last_line.starts_with("assert(") {
1542
- // All code is statements, no expression to evaluate
1543
- (lines[..=last_idx].join("\n"), None)
1544
- } else {
1545
- // Everything except last line is statements, last line is the expression
1546
- let statements = lines[..last_idx].join("\n");
1547
- let expr = last_line.to_string();
1548
- (statements, Some(expr))
1549
- }
1550
- } else {
1551
- // All code is statements (for exception tests or NoException)
1552
- (lines[..=last_idx].join("\n"), None)
1553
- }
1554
- }
1555
-
1556
- /// Wraps code in an async context for CPython execution.
1557
- ///
1558
- /// Monty supports top-level `await`, but CPython does not. This function transforms code
1559
- /// like:
1560
- ///
1561
- /// ```python
1562
- /// async def foo():
1563
- /// return 1
1564
- /// result = await foo()
1565
- /// ```
1566
- ///
1567
- /// Into:
1568
- ///
1569
- /// ```python
1570
- /// import asyncio
1571
- /// async def __test_main():
1572
- /// async def foo():
1573
- /// return 1
1574
- /// result = await foo()
1575
- /// return result # if need_return_value
1576
- /// __test_result__ = asyncio.run(__test_main())
1577
- /// ```
1578
- fn wrap_code_for_async(code: &str, need_return_value: bool) -> (String, Option<String>) {
1579
- let lines: Vec<&str> = code.lines().collect();
1580
-
1581
- // Find the last non-empty, non-comment line
1582
- let last_idx = lines
1583
- .iter()
1584
- .rposition(|line| {
1585
- let trimmed = line.trim();
1586
- !trimmed.is_empty() && !trimmed.starts_with('#')
1587
- })
1588
- .expect("Empty code");
1589
-
1590
- // Indent all code by 4 spaces for the function body
1591
- let indented: String = lines
1592
- .iter()
1593
- .map(|line| {
1594
- if line.is_empty() {
1595
- String::new()
1596
- } else {
1597
- format!(" {line}")
1598
- }
1599
- })
1600
- .collect::<Vec<_>>()
1601
- .join("\n");
1602
-
1603
- let return_stmt = if need_return_value {
1604
- // The last non-empty, non-comment line is the expression to return
1605
- let last_line = lines[last_idx].trim();
1606
- format!("\n return {last_line}")
1607
- } else {
1608
- String::new()
1609
- };
1610
-
1611
- let wrapped = format!(
1612
- "import asyncio\nasync def __test_main():\n{indented}{return_stmt}\n__test_result__ = asyncio.run(__test_main())"
1613
- );
1614
-
1615
- if need_return_value {
1616
- (wrapped, Some("__test_result__".to_string()))
1617
- } else {
1618
- (wrapped, None)
1619
- }
1620
- }
1621
-
1622
- /// Run the traceback script to get CPython's traceback output for a test file.
1623
- ///
1624
- /// This imports scripts/run_traceback.py via pyo3 and calls `run_file_and_get_traceback()`
1625
- /// which executes the file via runpy.run_path() to ensure full traceback information
1626
- /// (including caret lines) is preserved.
1627
- ///
1628
- /// When `iter_mode` is true, external function implementations are injected into the
1629
- /// file's globals before execution.
1630
- ///
1631
- /// When `async_mode` is true, code is wrapped in an async context before execution.
1632
- fn run_traceback_script(path: &Path, iter_mode: bool, async_mode: bool) -> String {
1633
- Python::attach(|py| {
1634
- let run_traceback = import_run_traceback(py);
1635
-
1636
- // Get absolute path for the test file
1637
- let abs_path = path.canonicalize().expect("Failed to get absolute path");
1638
- let path_str = abs_path.to_str().expect("Invalid UTF-8 in path");
1639
-
1640
- // Call run_file_and_get_traceback with the recursion limit, iter_mode, and async_mode flags
1641
- let result = run_traceback
1642
- .call_method1(
1643
- "run_file_and_get_traceback",
1644
- (path_str, TEST_RECURSION_LIMIT, iter_mode, async_mode),
1645
- )
1646
- .expect("Failed to call run_file_and_get_traceback");
1647
-
1648
- // Handle None return (no exception raised)
1649
- if result.is_none() {
1650
- String::new()
1651
- } else {
1652
- result
1653
- .extract()
1654
- .expect("Failed to extract string from return value of run_file_and_get_traceback")
1655
- }
1656
- })
1657
- }
1658
-
1659
- fn format_traceback(py: Python<'_>, exc: &PyErr) -> String {
1660
- let run_traceback = import_run_traceback(py);
1661
- let exc_value = exc.value(py);
1662
- let return_value = run_traceback
1663
- .call_method1("format_full_traceback", (exc_value,))
1664
- .expect("Failed to call format_full_traceback");
1665
- return_value
1666
- .extract()
1667
- .expect("failed to extract string from return value of format_full_traceback")
1668
- }
1669
-
1670
- /// Import the run_traceback module
1671
- fn import_run_traceback(py: Python<'_>) -> Bound<'_, PyModule> {
1672
- // Add scripts directory to sys.path (tests run from crates/monty/)
1673
- let sys = py.import("sys").expect("Failed to import sys");
1674
- let sys_path = sys.getattr("path").expect("Failed to get sys.path");
1675
- sys_path
1676
- .call_method1("insert", (0, "../../scripts"))
1677
- .expect("Failed to add scripts to sys.path");
1678
-
1679
- // Import the run_traceback module
1680
- py.import("run_traceback").expect("Failed to import run_traceback")
1681
- }
1682
-
1683
- /// Result from CPython execution - either a value to compare, or an early return.
1684
- enum CpythonResult {
1685
- /// Value to compare against expectation
1686
- Value(String),
1687
- /// No value to compare (NoException test succeeded)
1688
- NoValue,
1689
- /// Test failed with this error
1690
- Failed(TestFailure),
1691
- }
1692
-
1693
- /// Try to run a test through CPython, returning Ok(()) on success or Err with failure details.
1694
- ///
1695
- /// This function executes the same Python code via CPython (using pyo3) and
1696
- /// compares the result with the expected value. This ensures Monty behaves
1697
- /// identically to CPython.
1698
- ///
1699
- /// Code is executed at module level (not wrapped in a function) so that
1700
- /// `global` keyword semantics work correctly.
1701
- ///
1702
- /// RefCounts tests are skipped as they're Monty-specific.
1703
- /// Traceback tests use scripts/run_traceback.py for reliable caret line support.
1704
- fn try_run_cpython_test(
1705
- path: &Path,
1706
- code: &str,
1707
- expectation: &Expectation,
1708
- iter_mode: bool,
1709
- async_mode: bool,
1710
- ) -> Result<(), TestFailure> {
1711
- // Ensure Python modules are imported before parallel tests access them.
1712
- // This prevents race conditions during module initialization.
1713
- ensure_python_modules_imported();
1714
-
1715
- // Skip RefCounts tests - only relevant for Monty
1716
- if matches!(expectation, Expectation::RefCounts(_)) {
1717
- return Ok(());
1718
- }
1719
-
1720
- let test_name = path.strip_prefix("test_cases/").unwrap_or(path).display().to_string();
1721
-
1722
- // Traceback tests use the external script for reliable caret line support
1723
- if let Expectation::Traceback(expected) = expectation {
1724
- let result = run_traceback_script(path, iter_mode, async_mode);
1725
- if result != *expected {
1726
- return Err(TestFailure {
1727
- test_name,
1728
- kind: "CPython traceback".to_string(),
1729
- expected: expected.clone(),
1730
- actual: result,
1731
- });
1732
- }
1733
- return Ok(());
1734
- }
1735
-
1736
- let need_return_value = matches!(
1737
- expectation,
1738
- Expectation::Return(_) | Expectation::ReturnStr(_) | Expectation::ReturnType(_)
1739
- );
1740
-
1741
- // Use async wrapper for tests with top-level await
1742
- let (statements, maybe_expr) = if async_mode {
1743
- wrap_code_for_async(code, need_return_value)
1744
- } else {
1745
- split_code_for_module(code, need_return_value)
1746
- };
1747
-
1748
- let result: CpythonResult = Python::attach(|py| {
1749
- // Execute statements at module level
1750
- let globals = PyDict::new(py);
1751
-
1752
- // For iter mode tests, inject external function implementations into globals
1753
- if iter_mode {
1754
- let ext_funcs_cstr = CString::new(ITER_EXT_FUNCTIONS_PYTHON).expect("Invalid C string in ext funcs");
1755
- py.run(&ext_funcs_cstr, Some(&globals), None)
1756
- .expect("Failed to define external functions for iter mode");
1757
- }
1758
-
1759
- // Run the statements
1760
- let statements_cstr = CString::new(statements.as_str()).expect("Invalid C string in statements");
1761
- let stmt_result = py.run(&statements_cstr, Some(&globals), None);
1762
-
1763
- // Handle exception during statement execution
1764
- if let Err(e) = stmt_result {
1765
- if matches!(expectation, Expectation::NoException) {
1766
- return CpythonResult::Failed(TestFailure {
1767
- test_name: test_name.clone(),
1768
- kind: "CPython unexpected exception".to_string(),
1769
- expected: "no exception".to_string(),
1770
- actual: format_traceback(py, &e),
1771
- });
1772
- }
1773
- if matches!(expectation, Expectation::Raise(_)) {
1774
- return CpythonResult::Value(format_cpython_exception(py, &e));
1775
- }
1776
- return CpythonResult::Failed(TestFailure {
1777
- test_name: test_name.clone(),
1778
- kind: "CPython unexpected exception".to_string(),
1779
- expected: "success".to_string(),
1780
- actual: format_traceback(py, &e),
1781
- });
1782
- }
1783
-
1784
- // If we have an expression to evaluate, evaluate it
1785
- if let Some(expr) = maybe_expr {
1786
- let expr_cstr = CString::new(expr.as_str()).expect("Invalid C string in expr");
1787
- match py.eval(&expr_cstr, Some(&globals), None) {
1788
- Ok(result) => {
1789
- // Code returned successfully - format based on expectation type
1790
- match expectation {
1791
- Expectation::Return(_) => CpythonResult::Value(result.repr().unwrap().to_string()),
1792
- Expectation::ReturnStr(_) => CpythonResult::Value(result.str().unwrap().to_string()),
1793
- Expectation::ReturnType(_) => {
1794
- CpythonResult::Value(result.get_type().name().unwrap().to_string())
1795
- }
1796
- Expectation::Raise(expected) => CpythonResult::Failed(TestFailure {
1797
- test_name: test_name.clone(),
1798
- kind: "CPython exception".to_string(),
1799
- expected: expected.clone(),
1800
- actual: "no exception raised".to_string(),
1801
- }),
1802
- // Traceback tests are handled by run_traceback_script above
1803
- Expectation::Traceback(_) | Expectation::NoException | Expectation::RefCounts(_) => {
1804
- unreachable!()
1805
- }
1806
- }
1807
- }
1808
- Err(e) => {
1809
- // Expression raised an exception
1810
- if matches!(expectation, Expectation::NoException) {
1811
- return CpythonResult::Failed(TestFailure {
1812
- test_name: test_name.clone(),
1813
- kind: "CPython unexpected exception".to_string(),
1814
- expected: "no exception".to_string(),
1815
- actual: format_traceback(py, &e),
1816
- });
1817
- }
1818
- if matches!(expectation, Expectation::Raise(_)) {
1819
- return CpythonResult::Value(format_cpython_exception(py, &e));
1820
- }
1821
- // Traceback tests are handled by run_traceback_script above
1822
- CpythonResult::Failed(TestFailure {
1823
- test_name: test_name.clone(),
1824
- kind: "CPython unexpected exception".to_string(),
1825
- expected: "success".to_string(),
1826
- actual: format_traceback(py, &e),
1827
- })
1828
- }
1829
- }
1830
- } else {
1831
- // No expression to evaluate
1832
- // Traceback tests are handled by run_traceback_script above
1833
- if let Expectation::Raise(expected) = expectation {
1834
- return CpythonResult::Failed(TestFailure {
1835
- test_name: test_name.clone(),
1836
- kind: "CPython exception".to_string(),
1837
- expected: expected.clone(),
1838
- actual: "no exception raised".to_string(),
1839
- });
1840
- }
1841
- CpythonResult::NoValue // NoException expectation - success
1842
- }
1843
- });
1844
-
1845
- match result {
1846
- CpythonResult::Value(actual) => {
1847
- let expected = expectation.expected_value();
1848
- if actual != expected {
1849
- return Err(TestFailure {
1850
- test_name,
1851
- kind: "CPython result".to_string(),
1852
- expected: expected.to_string(),
1853
- actual,
1854
- });
1855
- }
1856
- Ok(())
1857
- }
1858
- CpythonResult::NoValue => Ok(()),
1859
- CpythonResult::Failed(failure) => Err(failure),
1860
- }
1861
- }
1862
-
1863
- /// Format a CPython exception into the expected format.
1864
- fn format_cpython_exception(py: Python<'_>, e: &PyErr) -> String {
1865
- let exc_type = e.get_type(py).name().unwrap();
1866
- let exc_message: String = e
1867
- .value(py)
1868
- .getattr("args")
1869
- .and_then(|args| args.get_item(0))
1870
- .and_then(|item| item.extract())
1871
- .unwrap_or_default();
1872
-
1873
- if exc_message.is_empty() {
1874
- format!("{exc_type}()")
1875
- } else if exc_message.contains('\'') {
1876
- // Use double quotes when message contains single quotes (like Python's repr)
1877
- format!("{exc_type}(\"{exc_message}\")")
1878
- } else {
1879
- // Use single quotes (default Python repr format)
1880
- format!("{exc_type}('{exc_message}')")
1881
- }
1882
- }
1883
-
1884
- /// Timeout duration for Monty tests.
1885
- ///
1886
- /// Tests that exceed this duration are considered to be hanging (infinite loop)
1887
- /// and will fail with a timeout error.
1888
- const TEST_TIMEOUT: Duration = Duration::from_secs(2);
1889
-
1890
- /// Result from running a test with a timeout.
1891
- enum TimeoutResult<T> {
1892
- /// The closure completed successfully.
1893
- Ok(T),
1894
- /// The closure panicked with the given message.
1895
- Panicked(String),
1896
- /// The timeout was exceeded.
1897
- TimedOut,
1898
- }
1899
-
1900
- /// Runs a closure with a timeout, returning an error if it exceeds the duration or panics.
1901
- ///
1902
- /// Spawns the closure in a separate thread and waits for the result with a timeout.
1903
- /// Distinguishes between three cases:
1904
- /// - Success: the closure returned normally
1905
- /// - Panic: the closure panicked (detected via channel disconnect + catch_unwind)
1906
- /// - Timeout: the timeout was exceeded (possible infinite loop)
1907
- ///
1908
- /// Note that if a timeout occurs, the spawned thread will continue running in the
1909
- /// background (Rust doesn't support killing threads), but the test will fail immediately.
1910
- fn run_with_timeout<F, T>(timeout: Duration, f: F) -> TimeoutResult<T>
1911
- where
1912
- F: FnOnce() -> T + Send + 'static,
1913
- T: Send + 'static,
1914
- {
1915
- let (tx, rx) = mpsc::channel();
1916
- thread::spawn(move || {
1917
- // Catch panics so we can report them properly instead of as timeouts
1918
- let result = panic::catch_unwind(AssertUnwindSafe(f));
1919
- match result {
1920
- Ok(value) => {
1921
- let _ = tx.send(Ok(value));
1922
- }
1923
- Err(panic_payload) => {
1924
- // Extract panic message from the payload
1925
- let msg = if let Some(s) = panic_payload.downcast_ref::<&str>() {
1926
- (*s).to_string()
1927
- } else if let Some(s) = panic_payload.downcast_ref::<String>() {
1928
- s.clone()
1929
- } else {
1930
- "unknown panic".to_string()
1931
- };
1932
- let _ = tx.send(Err(msg));
1933
- }
1934
- }
1935
- });
1936
-
1937
- match rx.recv_timeout(timeout) {
1938
- Ok(Ok(value)) => TimeoutResult::Ok(value),
1939
- Ok(Err(panic_msg)) => TimeoutResult::Panicked(panic_msg),
1940
- Err(RecvTimeoutError::Timeout) => TimeoutResult::TimedOut,
1941
- // Disconnected without sending means something went very wrong
1942
- Err(RecvTimeoutError::Disconnected) => {
1943
- TimeoutResult::Panicked("thread terminated without sending result".to_string())
1944
- }
1945
- }
1946
- }
1947
-
1948
- /// Test function that runs each fixture through Monty.
1949
- ///
1950
- /// Handles xfail with strict semantics: if a test is marked `xfail=monty`, it must fail.
1951
- /// If an xfail test passes unexpectedly, that's an error.
1952
- fn run_test_cases_monty(path: &Path) -> Result<(), Box<dyn Error>> {
1953
- let content = fs::read_to_string(path)?;
1954
- let (code, expectation, config) = parse_fixture(&content);
1955
- let test_name = path.strip_prefix("test_cases/").unwrap_or(path).display().to_string();
1956
-
1957
- // Move data into the closure since it needs 'static lifetime
1958
- let path_owned = path.to_owned();
1959
- let iter_mode = config.iter_mode;
1960
-
1961
- let result = run_with_timeout(TEST_TIMEOUT, move || {
1962
- if iter_mode {
1963
- try_run_iter_test(&path_owned, &code, &expectation)
1964
- } else {
1965
- try_run_test(&path_owned, &code, &expectation)
1966
- }
1967
- });
1968
-
1969
- // Handle timeout/panic errors from the test thread
1970
- let result = match result {
1971
- TimeoutResult::Ok(inner_result) => inner_result,
1972
- TimeoutResult::Panicked(panic_msg) => Err(TestFailure {
1973
- test_name: test_name.clone(),
1974
- kind: "Panic".to_string(),
1975
- expected: "no panic".to_string(),
1976
- actual: format!("test panicked: {panic_msg}"),
1977
- }),
1978
- TimeoutResult::TimedOut => Err(TestFailure {
1979
- test_name: test_name.clone(),
1980
- kind: "Timeout".to_string(),
1981
- expected: format!("completion within {TEST_TIMEOUT:?}"),
1982
- actual: format!("test timed out after {TEST_TIMEOUT:?} (possible infinite loop)"),
1983
- }),
1984
- };
1985
-
1986
- if config.xfail_monty {
1987
- // Strict xfail: test must fail; if it passed, xfail should be removed
1988
- assert!(
1989
- result.is_err(),
1990
- "[{test_name}] Test marked xfail=monty passed unexpectedly. Remove xfail if the test is now fixed."
1991
- );
1992
- } else if let Err(failure) = result {
1993
- panic!("{failure}");
1994
- }
1995
- Ok(())
1996
- }
1997
-
1998
- /// Test function that runs each fixture through CPython.
1999
- ///
2000
- /// Handles xfail with strict semantics: if a test is marked `xfail=cpython`, it must fail.
2001
- /// If an xfail test passes unexpectedly, that's an error.
2002
- fn run_test_cases_cpython(path: &Path) -> Result<(), Box<dyn Error>> {
2003
- let content = fs::read_to_string(path)?;
2004
- let (code, expectation, config) = parse_fixture(&content);
2005
- let test_name = path.strip_prefix("test_cases/").unwrap_or(path).display().to_string();
2006
-
2007
- let result = try_run_cpython_test(path, &code, &expectation, config.iter_mode, config.async_mode);
2008
-
2009
- if config.xfail_cpython {
2010
- // Strict xfail: test must fail; if it passed, xfail should be removed
2011
- assert!(
2012
- result.is_err(),
2013
- "[{test_name}] Test marked xfail=cpython passed unexpectedly. Remove xfail if the test is now fixed."
2014
- );
2015
- } else if let Err(failure) = result {
2016
- panic!("{failure}");
2017
- }
2018
- Ok(())
2019
- }
2020
-
2021
- // Generate tests for all fixture files using datatest-stable harness macro
2022
- datatest_stable::harness!(
2023
- run_test_cases_monty,
2024
- "test_cases",
2025
- r"^.*\.py$",
2026
- run_test_cases_cpython,
2027
- "test_cases",
2028
- r"^.*\.py$",
2029
- );