superacli 1.1.6 → 1.1.7

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 (1262) hide show
  1. package/README.md +77 -53
  2. package/__tests__/azd-plugin.test.js +109 -0
  3. package/__tests__/config.test.js +4 -3
  4. package/__tests__/discover.test.js +59 -0
  5. package/__tests__/goose-plugin.test.js +149 -0
  6. package/__tests__/help-json.test.js +2 -0
  7. package/__tests__/openhands-plugin.test.js +106 -0
  8. package/__tests__/plugin-cocoindex-code-uninstall.test.js +19 -0
  9. package/__tests__/plugin-cocoindex-code.test.js +37 -0
  10. package/__tests__/plugin-install-guidance.test.js +81 -0
  11. package/__tests__/plugins-registry.test.js +44 -0
  12. package/__tests__/plugins-store.test.js +40 -5
  13. package/__tests__/process-adapter.test.js +50 -1
  14. package/__tests__/server-app.test.js +1 -0
  15. package/__tests__/server-routes-commands.test.js +20 -2
  16. package/__tests__/server-routes-plugins.test.js +130 -0
  17. package/__tests__/skills.test.js +26 -0
  18. package/__tests__/squirrelscan-plugin.test.js +129 -0
  19. package/__tests__/uipath-plugin.test.js +104 -0
  20. package/__tests__/uipathcli-plugin.test.js +95 -0
  21. package/cli/adapters/mcp.js +2 -0
  22. package/cli/adapters/process.js +49 -2
  23. package/cli/config.js +240 -3
  24. package/cli/discover.js +157 -0
  25. package/cli/help-json.js +16 -1
  26. package/cli/plugin-install-guidance.js +92 -37
  27. package/cli/plugins-manager.js +1 -0
  28. package/cli/plugins-registry.js +74 -8
  29. package/cli/plugins-store.js +78 -17
  30. package/cli/skills-mcp.js +1 -1
  31. package/cli/skills.js +39 -2
  32. package/cli/supercli.js +87 -11
  33. package/docs/feature-gaps.md +8 -8
  34. package/docs/features/azd-uipath-plugins.md +43 -0
  35. package/docs/features/server-plugins.md +62 -0
  36. package/docs/features/skills.md +9 -5
  37. package/docs/{supported-harnesses.md → plugins-available.md} +4 -3
  38. package/docs/{plugin-harness-guide.md → plugins-how-to.md} +1 -1
  39. package/docs/plugins.md +26 -20
  40. package/docs/server-plugins-usage-guide.md +182 -0
  41. package/docs/skills-catalog.md +12 -10
  42. package/package.json +1 -1
  43. package/plugins/agent-browser/README.md +69 -0
  44. package/plugins/agent-browser/plugin.json +111 -0
  45. package/plugins/agent-browser/skills/quickstart/SKILL.md +66 -0
  46. package/plugins/aider/README.md +53 -0
  47. package/plugins/aider/plugin.json +105 -0
  48. package/plugins/aider/scripts/aider-wrapper.js +243 -0
  49. package/plugins/aider/scripts/setup-aider.js +37 -0
  50. package/plugins/aider/skills/dry-run-review.md +24 -0
  51. package/plugins/aider/skills/model-and-provider.md +24 -0
  52. package/plugins/aider/skills/one-shot-edits.md +30 -0
  53. package/plugins/aider/skills/quickstart/SKILL.md +51 -0
  54. package/plugins/azd/README.md +28 -0
  55. package/plugins/azd/plugin.json +87 -0
  56. package/plugins/azd/skills/quickstart/SKILL.md +41 -0
  57. package/plugins/blogwatcher/README.md +3 -3
  58. package/plugins/boxlite/Dockerfile +9 -0
  59. package/plugins/boxlite/README.md +62 -0
  60. package/plugins/boxlite/plugin.json +201 -0
  61. package/plugins/boxlite/scripts/run-boxlite.js +106 -0
  62. package/plugins/boxlite/skills/quickstart/SKILL.md +40 -0
  63. package/plugins/cass/plugin.json +150 -0
  64. package/plugins/cass/scripts/setup-cass.js +47 -0
  65. package/plugins/cass/skills/quickstart/SKILL.md +46 -0
  66. package/plugins/clever/README.md +46 -0
  67. package/plugins/clever/plugin.json +119 -0
  68. package/plugins/clever/scripts/setup-clever.js +28 -0
  69. package/plugins/clever/skills/auth-and-profile.md +29 -0
  70. package/plugins/clever/skills/passthrough-safety.md +21 -0
  71. package/plugins/clever/skills/quickstart/SKILL.md +45 -0
  72. package/plugins/clever/skills/resource-inventory.md +24 -0
  73. package/plugins/clix/README.md +4 -4
  74. package/plugins/cocoindex-code/README.md +64 -0
  75. package/plugins/cocoindex-code/plugin.json +81 -0
  76. package/plugins/cocoindex-code/scripts/__pycache__/query.cpython-310.pyc +0 -0
  77. package/plugins/cocoindex-code/scripts/__pycache__/query.cpython-311.pyc +0 -0
  78. package/plugins/cocoindex-code/scripts/post-install.js +61 -0
  79. package/plugins/cocoindex-code/scripts/post-uninstall.js +25 -0
  80. package/plugins/cocoindex-code/scripts/query.py +88 -0
  81. package/plugins/cocoindex-code/scripts/run-query.js +50 -0
  82. package/plugins/cocoindex-code/skills/quickstart/SKILL.md +73 -0
  83. package/plugins/copilot/README.md +24 -0
  84. package/plugins/copilot/plugin.json +80 -0
  85. package/plugins/copilot/skills/quickstart/SKILL.md +44 -0
  86. package/plugins/gemini/README.md +24 -0
  87. package/plugins/gemini/plugin.json +98 -0
  88. package/plugins/gemini/skills/quickstart/SKILL.md +44 -0
  89. package/plugins/gifcap/plugin.json +119 -0
  90. package/plugins/gifcap/scripts/setup-gifcap.js +44 -0
  91. package/plugins/gifcap/skills/quickstart/SKILL.md +34 -0
  92. package/plugins/gifcap/test-record-quiet.gif +0 -0
  93. package/plugins/gifcap/test-record.gif +0 -0
  94. package/plugins/goose/README.md +36 -0
  95. package/plugins/goose/plugin.json +183 -0
  96. package/plugins/goose/skills/quickstart/SKILL.md +44 -0
  97. package/plugins/json-server/README.md +58 -0
  98. package/plugins/json-server/plugin.json +113 -0
  99. package/plugins/json-server/skills/quickstart/SKILL.md +57 -0
  100. package/plugins/lightpanda/README.md +145 -0
  101. package/plugins/lightpanda/package-lock.json +1375 -0
  102. package/plugins/lightpanda/package.json +12 -0
  103. package/plugins/lightpanda/plugin.json +116 -0
  104. package/plugins/lightpanda/scripts/lightpanda-contacts.js +494 -0
  105. package/plugins/lightpanda/scripts/lightpanda-generic-extract.js +403 -0
  106. package/plugins/lightpanda/scripts/lightpanda-wrapper.js +480 -0
  107. package/plugins/lightpanda/scripts/setup-lightpanda.js +39 -0
  108. package/plugins/lightpanda/skills/contact-discovery.md +51 -0
  109. package/plugins/lightpanda/skills/generic-extraction.md +66 -0
  110. package/plugins/lightpanda/skills/quickstart/SKILL.md +103 -0
  111. package/plugins/lightpanda/skills/resilient-navigation.md +42 -0
  112. package/plugins/monty/README.md +2 -2
  113. package/plugins/nullclaw/README.md +3 -3
  114. package/plugins/offline-ai/README.md +23 -0
  115. package/plugins/offline-ai/plugin.json +82 -0
  116. package/plugins/offline-ai/skills/quickstart/SKILL.md +43 -0
  117. package/plugins/openhands/README.md +25 -0
  118. package/plugins/openhands/plugin.json +116 -0
  119. package/plugins/openhands/skills/quickstart/SKILL.md +26 -0
  120. package/plugins/plandex/README.md +25 -0
  121. package/plugins/plandex/plugin.json +130 -0
  122. package/plugins/plandex/skills/quickstart/SKILL.md +50 -0
  123. package/plugins/plugins.json +188 -0
  124. package/plugins/squirrelscan/Dockerfile +5 -0
  125. package/plugins/squirrelscan/README.md +47 -0
  126. package/plugins/squirrelscan/plugin.json +493 -0
  127. package/plugins/squirrelscan/scripts/post-install.js +33 -0
  128. package/plugins/squirrelscan/scripts/post-uninstall.js +25 -0
  129. package/plugins/squirrelscan/scripts/run-squirrel.js +73 -0
  130. package/plugins/squirrelscan/skills/audit-workflow/SKILL.md +33 -0
  131. package/plugins/squirrelscan/skills/publish-report/SKILL.md +33 -0
  132. package/plugins/squirrelscan/skills/quickstart/SKILL.md +41 -0
  133. package/plugins/uipath/README.md +27 -0
  134. package/plugins/uipath/plugin.json +86 -0
  135. package/plugins/uipath/skills/quickstart/SKILL.md +47 -0
  136. package/plugins/uipathcli/README.md +28 -0
  137. package/plugins/uipathcli/plugin.json +120 -0
  138. package/plugins/uipathcli/scripts/run-uipath-cli.js +49 -0
  139. package/plugins/uipathcli/skills/quickstart/SKILL.md +22 -0
  140. package/plugins/xurl/README.md +4 -4
  141. package/server/app.js +5 -2
  142. package/server/public/app.js +3 -0
  143. package/server/routes/commands.js +95 -12
  144. package/server/routes/plugins.js +262 -0
  145. package/server/services/pluginsService.js +303 -0
  146. package/server/views/command-edit.ejs +196 -14
  147. package/server/views/partials/head.ejs +1 -0
  148. package/server/views/plugins.ejs +264 -0
  149. package/tests/test-plugins-registry.js +30 -0
  150. package/.beads/.br_history/issues.20260308_200823_636718328.jsonl +0 -20
  151. package/.beads/.br_history/issues.20260308_200823_636718328.jsonl.meta.json +0 -1
  152. package/.beads/.br_history/issues.20260308_200827_033159453.jsonl +0 -21
  153. package/.beads/.br_history/issues.20260308_200827_033159453.jsonl.meta.json +0 -1
  154. package/.beads/.br_history/issues.20260308_200829_595900053.jsonl +0 -22
  155. package/.beads/.br_history/issues.20260308_200829_595900053.jsonl.meta.json +0 -1
  156. package/.beads/.br_history/issues.20260308_200834_079930100.jsonl +0 -23
  157. package/.beads/.br_history/issues.20260308_200834_079930100.jsonl.meta.json +0 -1
  158. package/.beads/.br_history/issues.20260308_200858_370924996.jsonl +0 -24
  159. package/.beads/.br_history/issues.20260308_200858_370924996.jsonl.meta.json +0 -1
  160. package/.beads/.br_history/issues.20260308_201031_019730855.jsonl +0 -24
  161. package/.beads/.br_history/issues.20260308_201031_019730855.jsonl.meta.json +0 -1
  162. package/.beads/.br_history/issues.20260308_201031_578974884.jsonl +0 -24
  163. package/.beads/.br_history/issues.20260308_201031_578974884.jsonl.meta.json +0 -1
  164. package/.beads/.br_history/issues.20260308_201054_780345548.jsonl +0 -24
  165. package/.beads/.br_history/issues.20260308_201054_780345548.jsonl.meta.json +0 -1
  166. package/.beads/.br_history/issues.20260308_201054_896980019.jsonl +0 -24
  167. package/.beads/.br_history/issues.20260308_201054_896980019.jsonl.meta.json +0 -1
  168. package/.beads/.br_history/issues.20260308_201128_599819688.jsonl +0 -24
  169. package/.beads/.br_history/issues.20260308_201128_599819688.jsonl.meta.json +0 -1
  170. package/.beads/.br_history/issues.20260308_201128_710221699.jsonl +0 -24
  171. package/.beads/.br_history/issues.20260308_201128_710221699.jsonl.meta.json +0 -1
  172. package/.beads/.br_history/issues.20260308_201204_745649213.jsonl +0 -24
  173. package/.beads/.br_history/issues.20260308_201204_745649213.jsonl.meta.json +0 -1
  174. package/.beads/.br_history/issues.20260308_201338_908436144.jsonl +0 -24
  175. package/.beads/.br_history/issues.20260308_201338_908436144.jsonl.meta.json +0 -1
  176. package/.beads/.br_history/issues.20260308_201344_734860714.jsonl +0 -25
  177. package/.beads/.br_history/issues.20260308_201344_734860714.jsonl.meta.json +0 -1
  178. package/.beads/.br_history/issues.20260308_201630_819282295.jsonl +0 -25
  179. package/.beads/.br_history/issues.20260308_201630_819282295.jsonl.meta.json +0 -1
  180. package/.beads/.br_history/issues.20260308_203538_054279699.jsonl +0 -25
  181. package/.beads/.br_history/issues.20260308_203538_054279699.jsonl.meta.json +0 -1
  182. package/.beads/.br_history/issues.20260308_203547_597113070.jsonl +0 -26
  183. package/.beads/.br_history/issues.20260308_203547_597113070.jsonl.meta.json +0 -1
  184. package/.beads/.br_history/issues.20260308_203547_775139216.jsonl +0 -27
  185. package/.beads/.br_history/issues.20260308_203547_775139216.jsonl.meta.json +0 -1
  186. package/.beads/.br_history/issues.20260308_203547_950724773.jsonl +0 -28
  187. package/.beads/.br_history/issues.20260308_203547_950724773.jsonl.meta.json +0 -1
  188. package/.beads/.br_history/issues.20260308_203548_107684523.jsonl +0 -29
  189. package/.beads/.br_history/issues.20260308_203548_107684523.jsonl.meta.json +0 -1
  190. package/.beads/.br_history/issues.20260308_203548_310389993.jsonl +0 -30
  191. package/.beads/.br_history/issues.20260308_203548_310389993.jsonl.meta.json +0 -1
  192. package/.beads/.br_history/issues.20260308_203825_953337320.jsonl +0 -31
  193. package/.beads/.br_history/issues.20260308_203825_953337320.jsonl.meta.json +0 -1
  194. package/.beads/.br_history/issues.20260308_204056_071377736.jsonl +0 -32
  195. package/.beads/.br_history/issues.20260308_204056_071377736.jsonl.meta.json +0 -1
  196. package/.beads/.br_history/issues.20260308_205141_517616844.jsonl +0 -32
  197. package/.beads/.br_history/issues.20260308_205141_517616844.jsonl.meta.json +0 -1
  198. package/.beads/.br_history/issues.20260308_205141_648994024.jsonl +0 -32
  199. package/.beads/.br_history/issues.20260308_205141_648994024.jsonl.meta.json +0 -1
  200. package/.beads/.br_history/issues.20260308_205141_867598036.jsonl +0 -32
  201. package/.beads/.br_history/issues.20260308_205141_867598036.jsonl.meta.json +0 -1
  202. package/.beads/.br_history/issues.20260308_205142_094157355.jsonl +0 -32
  203. package/.beads/.br_history/issues.20260308_205142_094157355.jsonl.meta.json +0 -1
  204. package/.beads/.br_history/issues.20260308_205142_327315677.jsonl +0 -32
  205. package/.beads/.br_history/issues.20260308_205142_327315677.jsonl.meta.json +0 -1
  206. package/.beads/.br_history/issues.20260308_205142_545563822.jsonl +0 -32
  207. package/.beads/.br_history/issues.20260308_205142_545563822.jsonl.meta.json +0 -1
  208. package/.beads/.br_history/issues.20260308_205213_061989333.jsonl +0 -32
  209. package/.beads/.br_history/issues.20260308_205213_061989333.jsonl.meta.json +0 -1
  210. package/.beads/.br_history/issues.20260308_205213_181103364.jsonl +0 -32
  211. package/.beads/.br_history/issues.20260308_205213_181103364.jsonl.meta.json +0 -1
  212. package/.beads/.br_history/issues.20260308_205213_408872234.jsonl +0 -32
  213. package/.beads/.br_history/issues.20260308_205213_408872234.jsonl.meta.json +0 -1
  214. package/.beads/.br_history/issues.20260308_205213_616681652.jsonl +0 -32
  215. package/.beads/.br_history/issues.20260308_205213_616681652.jsonl.meta.json +0 -1
  216. package/.beads/.br_history/issues.20260308_205213_821507069.jsonl +0 -32
  217. package/.beads/.br_history/issues.20260308_205213_821507069.jsonl.meta.json +0 -1
  218. package/.beads/.br_history/issues.20260308_205214_026661112.jsonl +0 -32
  219. package/.beads/.br_history/issues.20260308_205214_026661112.jsonl.meta.json +0 -1
  220. package/.beads/.br_history/issues.20260308_205454_955250554.jsonl +0 -32
  221. package/.beads/.br_history/issues.20260308_205454_955250554.jsonl.meta.json +0 -1
  222. package/.beads/.br_history/issues.20260308_205556_337800392.jsonl +0 -33
  223. package/.beads/.br_history/issues.20260308_205556_337800392.jsonl.meta.json +0 -1
  224. package/.beads/.br_history/issues.20260308_205824_274686694.jsonl +0 -33
  225. package/.beads/.br_history/issues.20260308_205824_274686694.jsonl.meta.json +0 -1
  226. package/.beads/.br_history/issues.20260308_210240_583768328.jsonl +0 -34
  227. package/.beads/.br_history/issues.20260308_210240_583768328.jsonl.meta.json +0 -1
  228. package/.beads/.br_history/issues.20260308_212223_641541494.jsonl +0 -34
  229. package/.beads/.br_history/issues.20260308_212223_641541494.jsonl.meta.json +0 -1
  230. package/.beads/.br_history/issues.20260308_212227_735550996.jsonl +0 -35
  231. package/.beads/.br_history/issues.20260308_212227_735550996.jsonl.meta.json +0 -1
  232. package/.beads/.br_history/issues.20260308_212232_547298548.jsonl +0 -36
  233. package/.beads/.br_history/issues.20260308_212232_547298548.jsonl.meta.json +0 -1
  234. package/.beads/.br_history/issues.20260308_212528_843628125.jsonl +0 -37
  235. package/.beads/.br_history/issues.20260308_212528_843628125.jsonl.meta.json +0 -1
  236. package/.beads/.br_history/issues.20260308_212529_094530502.jsonl +0 -38
  237. package/.beads/.br_history/issues.20260308_212529_094530502.jsonl.meta.json +0 -1
  238. package/.beads/.br_history/issues.20260308_212529_331000853.jsonl +0 -39
  239. package/.beads/.br_history/issues.20260308_212529_331000853.jsonl.meta.json +0 -1
  240. package/.beads/.br_history/issues.20260308_212529_587925652.jsonl +0 -40
  241. package/.beads/.br_history/issues.20260308_212529_587925652.jsonl.meta.json +0 -1
  242. package/.beads/.br_history/issues.20260308_212804_927764103.jsonl +0 -41
  243. package/.beads/.br_history/issues.20260308_212804_927764103.jsonl.meta.json +0 -1
  244. package/.beads/.br_history/issues.20260308_212805_153673453.jsonl +0 -42
  245. package/.beads/.br_history/issues.20260308_212805_153673453.jsonl.meta.json +0 -1
  246. package/.beads/.br_history/issues.20260308_212805_415982363.jsonl +0 -43
  247. package/.beads/.br_history/issues.20260308_212805_415982363.jsonl.meta.json +0 -1
  248. package/.beads/.br_history/issues.20260308_212805_657497741.jsonl +0 -44
  249. package/.beads/.br_history/issues.20260308_212805_657497741.jsonl.meta.json +0 -1
  250. package/.beads/.br_history/issues.20260308_212805_952838724.jsonl +0 -45
  251. package/.beads/.br_history/issues.20260308_212805_952838724.jsonl.meta.json +0 -1
  252. package/.beads/.br_history/issues.20260308_212806_325433779.jsonl +0 -46
  253. package/.beads/.br_history/issues.20260308_212806_325433779.jsonl.meta.json +0 -1
  254. package/.beads/.br_history/issues.20260308_212806_584685598.jsonl +0 -47
  255. package/.beads/.br_history/issues.20260308_212806_584685598.jsonl.meta.json +0 -1
  256. package/.beads/.br_history/issues.20260308_212806_827817208.jsonl +0 -48
  257. package/.beads/.br_history/issues.20260308_212806_827817208.jsonl.meta.json +0 -1
  258. package/.beads/.br_history/issues.20260308_212807_111320451.jsonl +0 -49
  259. package/.beads/.br_history/issues.20260308_212807_111320451.jsonl.meta.json +0 -1
  260. package/.beads/.br_history/issues.20260308_212807_409545536.jsonl +0 -50
  261. package/.beads/.br_history/issues.20260308_212807_409545536.jsonl.meta.json +0 -1
  262. package/.beads/.br_history/issues.20260308_212807_625063294.jsonl +0 -51
  263. package/.beads/.br_history/issues.20260308_212807_625063294.jsonl.meta.json +0 -1
  264. package/.beads/.br_history/issues.20260308_212807_843906551.jsonl +0 -52
  265. package/.beads/.br_history/issues.20260308_212807_843906551.jsonl.meta.json +0 -1
  266. package/.beads/.br_history/issues.20260308_212808_100304073.jsonl +0 -53
  267. package/.beads/.br_history/issues.20260308_212808_100304073.jsonl.meta.json +0 -1
  268. package/.beads/.br_history/issues.20260308_212808_324723976.jsonl +0 -54
  269. package/.beads/.br_history/issues.20260308_212808_324723976.jsonl.meta.json +0 -1
  270. package/.beads/.br_history/issues.20260308_212808_557513104.jsonl +0 -55
  271. package/.beads/.br_history/issues.20260308_212808_557513104.jsonl.meta.json +0 -1
  272. package/.beads/.br_history/issues.20260308_212808_788048322.jsonl +0 -56
  273. package/.beads/.br_history/issues.20260308_212808_788048322.jsonl.meta.json +0 -1
  274. package/.beads/.br_history/issues.20260308_213702_613249728.jsonl +0 -57
  275. package/.beads/.br_history/issues.20260308_213702_613249728.jsonl.meta.json +0 -1
  276. package/.beads/.br_history/issues.20260308_213715_115792063.jsonl +0 -57
  277. package/.beads/.br_history/issues.20260308_213715_115792063.jsonl.meta.json +0 -1
  278. package/.beads/.br_history/issues.20260308_213715_462220666.jsonl +0 -57
  279. package/.beads/.br_history/issues.20260308_213715_462220666.jsonl.meta.json +0 -1
  280. package/.beads/.br_history/issues.20260308_213727_191258923.jsonl +0 -57
  281. package/.beads/.br_history/issues.20260308_213727_191258923.jsonl.meta.json +0 -1
  282. package/.beads/.br_history/issues.20260308_213727_684383652.jsonl +0 -57
  283. package/.beads/.br_history/issues.20260308_213727_684383652.jsonl.meta.json +0 -1
  284. package/.beads/.br_history/issues.20260308_213735_751882991.jsonl +0 -57
  285. package/.beads/.br_history/issues.20260308_213735_751882991.jsonl.meta.json +0 -1
  286. package/.beads/.br_history/issues.20260308_222052_279844960.jsonl +0 -57
  287. package/.beads/.br_history/issues.20260308_222052_279844960.jsonl.meta.json +0 -1
  288. package/.beads/.br_history/issues.20260308_222056_873282114.jsonl +0 -57
  289. package/.beads/.br_history/issues.20260308_222056_873282114.jsonl.meta.json +0 -1
  290. package/.beads/.br_history/issues.20260308_222103_402410761.jsonl +0 -57
  291. package/.beads/.br_history/issues.20260308_222103_402410761.jsonl.meta.json +0 -1
  292. package/.beads/.br_history/issues.20260308_235202_180577215.jsonl +0 -57
  293. package/.beads/.br_history/issues.20260308_235202_180577215.jsonl.meta.json +0 -1
  294. package/.beads/.br_history/issues.20260308_235202_387414163.jsonl +0 -57
  295. package/.beads/.br_history/issues.20260308_235202_387414163.jsonl.meta.json +0 -1
  296. package/.beads/.br_history/issues.20260308_235202_564422794.jsonl +0 -57
  297. package/.beads/.br_history/issues.20260308_235202_564422794.jsonl.meta.json +0 -1
  298. package/.beads/.br_history/issues.20260308_235202_742600597.jsonl +0 -57
  299. package/.beads/.br_history/issues.20260308_235202_742600597.jsonl.meta.json +0 -1
  300. package/.beads/.br_history/issues.20260308_235208_133360069.jsonl +0 -57
  301. package/.beads/.br_history/issues.20260308_235208_133360069.jsonl.meta.json +0 -1
  302. package/.beads/.br_history/issues.20260308_235505_473406307.jsonl +0 -57
  303. package/.beads/.br_history/issues.20260308_235505_473406307.jsonl.meta.json +0 -1
  304. package/.beads/.br_history/issues.20260308_235505_662360489.jsonl +0 -57
  305. package/.beads/.br_history/issues.20260308_235505_662360489.jsonl.meta.json +0 -1
  306. package/.beads/.br_history/issues.20260308_235505_843935624.jsonl +0 -57
  307. package/.beads/.br_history/issues.20260308_235505_843935624.jsonl.meta.json +0 -1
  308. package/.beads/.br_history/issues.20260308_235506_044530221.jsonl +0 -57
  309. package/.beads/.br_history/issues.20260308_235506_044530221.jsonl.meta.json +0 -1
  310. package/.beads/.br_history/issues.20260309_002618_115728731.jsonl +0 -57
  311. package/.beads/.br_history/issues.20260309_002618_115728731.jsonl.meta.json +0 -1
  312. package/.beads/.br_history/issues.20260309_003748_878174586.jsonl +0 -57
  313. package/.beads/.br_history/issues.20260309_003748_878174586.jsonl.meta.json +0 -1
  314. package/.beads/.br_history/issues.20260309_004057_868755623.jsonl +0 -57
  315. package/.beads/.br_history/issues.20260309_004057_868755623.jsonl.meta.json +0 -1
  316. package/.beads/.br_history/issues.20260309_004058_512842163.jsonl +0 -57
  317. package/.beads/.br_history/issues.20260309_004058_512842163.jsonl.meta.json +0 -1
  318. package/.beads/.br_history/issues.20260309_004058_994445226.jsonl +0 -57
  319. package/.beads/.br_history/issues.20260309_004058_994445226.jsonl.meta.json +0 -1
  320. package/.beads/.br_history/issues.20260309_004059_475988596.jsonl +0 -57
  321. package/.beads/.br_history/issues.20260309_004059_475988596.jsonl.meta.json +0 -1
  322. package/.beads/.br_history/issues.20260309_161902_566857851.jsonl +0 -57
  323. package/.beads/.br_history/issues.20260309_161902_566857851.jsonl.meta.json +0 -1
  324. package/.beads/.br_history/issues.20260309_170512_277017739.jsonl +0 -57
  325. package/.beads/.br_history/issues.20260309_170512_277017739.jsonl.meta.json +0 -1
  326. package/.beads/.br_history/issues.20260309_170512_477876921.jsonl +0 -57
  327. package/.beads/.br_history/issues.20260309_170512_477876921.jsonl.meta.json +0 -1
  328. package/.beads/.br_history/issues.20260309_170512_664382701.jsonl +0 -57
  329. package/.beads/.br_history/issues.20260309_170512_664382701.jsonl.meta.json +0 -1
  330. package/.beads/.br_history/issues.20260309_170512_859400333.jsonl +0 -57
  331. package/.beads/.br_history/issues.20260309_170512_859400333.jsonl.meta.json +0 -1
  332. package/.beads/.br_history/issues.20260309_212326_082771164.jsonl +0 -57
  333. package/.beads/.br_history/issues.20260309_212326_082771164.jsonl.meta.json +0 -1
  334. package/.beads/.br_history/issues.20260309_212326_245619716.jsonl +0 -58
  335. package/.beads/.br_history/issues.20260309_212326_245619716.jsonl.meta.json +0 -1
  336. package/.beads/.br_history/issues.20260309_212326_403198317.jsonl +0 -59
  337. package/.beads/.br_history/issues.20260309_212326_403198317.jsonl.meta.json +0 -1
  338. package/.beads/.br_history/issues.20260309_212332_539197678.jsonl +0 -60
  339. package/.beads/.br_history/issues.20260309_212332_539197678.jsonl.meta.json +0 -1
  340. package/.beads/.br_history/issues.20260309_212332_731373599.jsonl +0 -60
  341. package/.beads/.br_history/issues.20260309_212332_731373599.jsonl.meta.json +0 -1
  342. package/.beads/.br_history/issues.20260309_212332_928710953.jsonl +0 -60
  343. package/.beads/.br_history/issues.20260309_212332_928710953.jsonl.meta.json +0 -1
  344. package/.beads/.br_history/issues.20260309_213021_341505240.jsonl +0 -60
  345. package/.beads/.br_history/issues.20260309_213021_341505240.jsonl.meta.json +0 -1
  346. package/.beads/.br_history/issues.20260309_213022_023136934.jsonl +0 -60
  347. package/.beads/.br_history/issues.20260309_213022_023136934.jsonl.meta.json +0 -1
  348. package/.beads/.br_history/issues.20260309_213022_400050719.jsonl +0 -60
  349. package/.beads/.br_history/issues.20260309_213022_400050719.jsonl.meta.json +0 -1
  350. package/.beads/config.yaml +0 -4
  351. package/.beads/issues.jsonl +0 -60
  352. package/.beads/metadata.json +0 -4
  353. package/docs/mcp-cheatsheet.md +0 -324
  354. package/docs/visual-overview.md +0 -21
  355. package/ref-monty/.cargo/config.toml +0 -3
  356. package/ref-monty/.claude/settings.json +0 -60
  357. package/ref-monty/.claude/skills/fastmod/SKILL.md +0 -22
  358. package/ref-monty/.claude/skills/python-playground/SKILL.md +0 -47
  359. package/ref-monty/.codecov.yml +0 -12
  360. package/ref-monty/.github/actions/build-pgo-wheel/action.yml +0 -72
  361. package/ref-monty/.github/workflows/ci.yml +0 -776
  362. package/ref-monty/.github/workflows/codspeed.yml +0 -45
  363. package/ref-monty/.github/workflows/init-npm-packages.yml +0 -82
  364. package/ref-monty/.pre-commit-config.yaml +0 -47
  365. package/ref-monty/.python-version +0 -1
  366. package/ref-monty/.rustfmt.toml +0 -4
  367. package/ref-monty/.zed/settings.json +0 -11
  368. package/ref-monty/CLAUDE.md +0 -535
  369. package/ref-monty/Cargo.lock +0 -3798
  370. package/ref-monty/Cargo.toml +0 -87
  371. package/ref-monty/LICENSE +0 -21
  372. package/ref-monty/Makefile +0 -216
  373. package/ref-monty/README.md +0 -430
  374. package/ref-monty/RELEASING.md +0 -47
  375. package/ref-monty/crates/fuzz/Cargo.toml +0 -30
  376. package/ref-monty/crates/fuzz/fuzz_targets/string_input_panic.rs +0 -37
  377. package/ref-monty/crates/fuzz/fuzz_targets/tokens_input_panic.rs +0 -552
  378. package/ref-monty/crates/monty/Cargo.toml +0 -68
  379. package/ref-monty/crates/monty/benches/main.rs +0 -247
  380. package/ref-monty/crates/monty/build.rs +0 -10
  381. package/ref-monty/crates/monty/src/args.rs +0 -733
  382. package/ref-monty/crates/monty/src/asyncio.rs +0 -179
  383. package/ref-monty/crates/monty/src/builtins/abs.rs +0 -55
  384. package/ref-monty/crates/monty/src/builtins/all.rs +0 -30
  385. package/ref-monty/crates/monty/src/builtins/any.rs +0 -30
  386. package/ref-monty/crates/monty/src/builtins/bin.rs +0 -59
  387. package/ref-monty/crates/monty/src/builtins/chr.rs +0 -46
  388. package/ref-monty/crates/monty/src/builtins/divmod.rs +0 -164
  389. package/ref-monty/crates/monty/src/builtins/enumerate.rs +0 -52
  390. package/ref-monty/crates/monty/src/builtins/filter.rs +0 -67
  391. package/ref-monty/crates/monty/src/builtins/getattr.rs +0 -65
  392. package/ref-monty/crates/monty/src/builtins/hash.rs +0 -28
  393. package/ref-monty/crates/monty/src/builtins/hex.rs +0 -58
  394. package/ref-monty/crates/monty/src/builtins/id.rs +0 -24
  395. package/ref-monty/crates/monty/src/builtins/isinstance.rs +0 -68
  396. package/ref-monty/crates/monty/src/builtins/len.rs +0 -25
  397. package/ref-monty/crates/monty/src/builtins/map.rs +0 -98
  398. package/ref-monty/crates/monty/src/builtins/min_max.rs +0 -113
  399. package/ref-monty/crates/monty/src/builtins/mod.rs +0 -246
  400. package/ref-monty/crates/monty/src/builtins/next.rs +0 -21
  401. package/ref-monty/crates/monty/src/builtins/oct.rs +0 -59
  402. package/ref-monty/crates/monty/src/builtins/ord.rs +0 -67
  403. package/ref-monty/crates/monty/src/builtins/pow.rs +0 -365
  404. package/ref-monty/crates/monty/src/builtins/print.rs +0 -141
  405. package/ref-monty/crates/monty/src/builtins/repr.rs +0 -16
  406. package/ref-monty/crates/monty/src/builtins/reversed.rs +0 -28
  407. package/ref-monty/crates/monty/src/builtins/round.rs +0 -174
  408. package/ref-monty/crates/monty/src/builtins/sorted.rs +0 -151
  409. package/ref-monty/crates/monty/src/builtins/sum.rs +0 -66
  410. package/ref-monty/crates/monty/src/builtins/type_.rs +0 -16
  411. package/ref-monty/crates/monty/src/builtins/zip.rs +0 -77
  412. package/ref-monty/crates/monty/src/bytecode/builder.rs +0 -699
  413. package/ref-monty/crates/monty/src/bytecode/code.rs +0 -310
  414. package/ref-monty/crates/monty/src/bytecode/compiler.rs +0 -3206
  415. package/ref-monty/crates/monty/src/bytecode/mod.rs +0 -24
  416. package/ref-monty/crates/monty/src/bytecode/op.rs +0 -617
  417. package/ref-monty/crates/monty/src/bytecode/vm/async_exec.rs +0 -1058
  418. package/ref-monty/crates/monty/src/bytecode/vm/attr.rs +0 -63
  419. package/ref-monty/crates/monty/src/bytecode/vm/binary.rs +0 -487
  420. package/ref-monty/crates/monty/src/bytecode/vm/call.rs +0 -767
  421. package/ref-monty/crates/monty/src/bytecode/vm/collections.rs +0 -741
  422. package/ref-monty/crates/monty/src/bytecode/vm/compare.rs +0 -147
  423. package/ref-monty/crates/monty/src/bytecode/vm/exceptions.rs +0 -297
  424. package/ref-monty/crates/monty/src/bytecode/vm/format.rs +0 -132
  425. package/ref-monty/crates/monty/src/bytecode/vm/mod.rs +0 -1958
  426. package/ref-monty/crates/monty/src/bytecode/vm/scheduler.rs +0 -620
  427. package/ref-monty/crates/monty/src/exception_private.rs +0 -1513
  428. package/ref-monty/crates/monty/src/exception_public.rs +0 -346
  429. package/ref-monty/crates/monty/src/expressions.rs +0 -694
  430. package/ref-monty/crates/monty/src/fstring.rs +0 -854
  431. package/ref-monty/crates/monty/src/function.rs +0 -119
  432. package/ref-monty/crates/monty/src/heap.rs +0 -1073
  433. package/ref-monty/crates/monty/src/heap_data.rs +0 -985
  434. package/ref-monty/crates/monty/src/heap_traits.rs +0 -312
  435. package/ref-monty/crates/monty/src/intern.rs +0 -837
  436. package/ref-monty/crates/monty/src/io.rs +0 -106
  437. package/ref-monty/crates/monty/src/lib.rs +0 -52
  438. package/ref-monty/crates/monty/src/modules/asyncio.rs +0 -144
  439. package/ref-monty/crates/monty/src/modules/math.rs +0 -1453
  440. package/ref-monty/crates/monty/src/modules/mod.rs +0 -120
  441. package/ref-monty/crates/monty/src/modules/os.rs +0 -116
  442. package/ref-monty/crates/monty/src/modules/pathlib.rs +0 -33
  443. package/ref-monty/crates/monty/src/modules/re.rs +0 -606
  444. package/ref-monty/crates/monty/src/modules/sys.rs +0 -60
  445. package/ref-monty/crates/monty/src/modules/typing.rs +0 -70
  446. package/ref-monty/crates/monty/src/namespace.rs +0 -21
  447. package/ref-monty/crates/monty/src/object.rs +0 -1040
  448. package/ref-monty/crates/monty/src/os.rs +0 -215
  449. package/ref-monty/crates/monty/src/parse.rs +0 -1730
  450. package/ref-monty/crates/monty/src/prepare.rs +0 -3015
  451. package/ref-monty/crates/monty/src/repl.rs +0 -1109
  452. package/ref-monty/crates/monty/src/resource.rs +0 -559
  453. package/ref-monty/crates/monty/src/run.rs +0 -457
  454. package/ref-monty/crates/monty/src/run_progress.rs +0 -821
  455. package/ref-monty/crates/monty/src/signature.rs +0 -651
  456. package/ref-monty/crates/monty/src/sorting.rs +0 -100
  457. package/ref-monty/crates/monty/src/types/bytes.rs +0 -2356
  458. package/ref-monty/crates/monty/src/types/dataclass.rs +0 -345
  459. package/ref-monty/crates/monty/src/types/dict.rs +0 -879
  460. package/ref-monty/crates/monty/src/types/dict_view.rs +0 -619
  461. package/ref-monty/crates/monty/src/types/iter.rs +0 -799
  462. package/ref-monty/crates/monty/src/types/list.rs +0 -929
  463. package/ref-monty/crates/monty/src/types/long_int.rs +0 -211
  464. package/ref-monty/crates/monty/src/types/mod.rs +0 -48
  465. package/ref-monty/crates/monty/src/types/module.rs +0 -146
  466. package/ref-monty/crates/monty/src/types/namedtuple.rs +0 -261
  467. package/ref-monty/crates/monty/src/types/path.rs +0 -596
  468. package/ref-monty/crates/monty/src/types/property.rs +0 -35
  469. package/ref-monty/crates/monty/src/types/py_trait.rs +0 -322
  470. package/ref-monty/crates/monty/src/types/range.rs +0 -285
  471. package/ref-monty/crates/monty/src/types/re_match.rs +0 -522
  472. package/ref-monty/crates/monty/src/types/re_pattern.rs +0 -726
  473. package/ref-monty/crates/monty/src/types/set.rs +0 -1373
  474. package/ref-monty/crates/monty/src/types/slice.rs +0 -257
  475. package/ref-monty/crates/monty/src/types/str.rs +0 -2051
  476. package/ref-monty/crates/monty/src/types/tuple.rs +0 -376
  477. package/ref-monty/crates/monty/src/types/type.rs +0 -407
  478. package/ref-monty/crates/monty/src/value.rs +0 -2558
  479. package/ref-monty/crates/monty/test_cases/args__dict_get_no_args.py +0 -3
  480. package/ref-monty/crates/monty/test_cases/args__dict_get_too_many.py +0 -3
  481. package/ref-monty/crates/monty/test_cases/args__dict_items_with_args.py +0 -3
  482. package/ref-monty/crates/monty/test_cases/args__dict_keys_with_args.py +0 -3
  483. package/ref-monty/crates/monty/test_cases/args__dict_pop_no_args.py +0 -3
  484. package/ref-monty/crates/monty/test_cases/args__dict_pop_too_many.py +0 -3
  485. package/ref-monty/crates/monty/test_cases/args__dict_values_with_args.py +0 -3
  486. package/ref-monty/crates/monty/test_cases/args__id_too_many.py +0 -2
  487. package/ref-monty/crates/monty/test_cases/args__len_no_args.py +0 -2
  488. package/ref-monty/crates/monty/test_cases/args__len_too_many.py +0 -2
  489. package/ref-monty/crates/monty/test_cases/args__len_type_error_int.py +0 -9
  490. package/ref-monty/crates/monty/test_cases/args__len_type_error_none.py +0 -9
  491. package/ref-monty/crates/monty/test_cases/args__list_append_no_args.py +0 -3
  492. package/ref-monty/crates/monty/test_cases/args__list_append_too_many.py +0 -3
  493. package/ref-monty/crates/monty/test_cases/args__list_insert_too_few.py +0 -3
  494. package/ref-monty/crates/monty/test_cases/args__list_insert_too_many.py +0 -3
  495. package/ref-monty/crates/monty/test_cases/args__repr_no_args.py +0 -2
  496. package/ref-monty/crates/monty/test_cases/arith__div_zero_float.py +0 -2
  497. package/ref-monty/crates/monty/test_cases/arith__div_zero_int.py +0 -2
  498. package/ref-monty/crates/monty/test_cases/arith__floordiv_zero_float.py +0 -2
  499. package/ref-monty/crates/monty/test_cases/arith__floordiv_zero_int.py +0 -2
  500. package/ref-monty/crates/monty/test_cases/arith__pow_zero_neg.py +0 -2
  501. package/ref-monty/crates/monty/test_cases/arith__pow_zero_neg_builtin.py +0 -9
  502. package/ref-monty/crates/monty/test_cases/assert__expr_fail.py +0 -2
  503. package/ref-monty/crates/monty/test_cases/assert__fail.py +0 -2
  504. package/ref-monty/crates/monty/test_cases/assert__fail_msg.py +0 -2
  505. package/ref-monty/crates/monty/test_cases/assert__fn_fail.py +0 -3
  506. package/ref-monty/crates/monty/test_cases/assert__ops.py +0 -11
  507. package/ref-monty/crates/monty/test_cases/async__asyncio_run.py +0 -47
  508. package/ref-monty/crates/monty/test_cases/async__basic.py +0 -10
  509. package/ref-monty/crates/monty/test_cases/async__closure.py +0 -14
  510. package/ref-monty/crates/monty/test_cases/async__double_await_coroutine.py +0 -16
  511. package/ref-monty/crates/monty/test_cases/async__exception.py +0 -10
  512. package/ref-monty/crates/monty/test_cases/async__ext_call.py +0 -73
  513. package/ref-monty/crates/monty/test_cases/async__gather_all.py +0 -85
  514. package/ref-monty/crates/monty/test_cases/async__nested_await.py +0 -15
  515. package/ref-monty/crates/monty/test_cases/async__nested_gather_ext.py +0 -37
  516. package/ref-monty/crates/monty/test_cases/async__not_awaitable.py +0 -10
  517. package/ref-monty/crates/monty/test_cases/async__not_imported.py +0 -14
  518. package/ref-monty/crates/monty/test_cases/async__recursion_depth_isolation.py +0 -27
  519. package/ref-monty/crates/monty/test_cases/async__return_types.py +0 -31
  520. package/ref-monty/crates/monty/test_cases/async__sequential.py +0 -16
  521. package/ref-monty/crates/monty/test_cases/async__traceback.py +0 -19
  522. package/ref-monty/crates/monty/test_cases/async__with_args.py +0 -14
  523. package/ref-monty/crates/monty/test_cases/attr__get_int_error.py +0 -9
  524. package/ref-monty/crates/monty/test_cases/attr__get_list_error.py +0 -9
  525. package/ref-monty/crates/monty/test_cases/attr__set_frozen_nonfield.py +0 -12
  526. package/ref-monty/crates/monty/test_cases/attr__set_int_error.py +0 -10
  527. package/ref-monty/crates/monty/test_cases/attr__set_list_error.py +0 -10
  528. package/ref-monty/crates/monty/test_cases/bench__kitchen_sink.py +0 -68
  529. package/ref-monty/crates/monty/test_cases/bool__ops.py +0 -20
  530. package/ref-monty/crates/monty/test_cases/builtin__add_type_error.py +0 -2
  531. package/ref-monty/crates/monty/test_cases/builtin__filter.py +0 -62
  532. package/ref-monty/crates/monty/test_cases/builtin__filter_not_iterable.py +0 -11
  533. package/ref-monty/crates/monty/test_cases/builtin__getattr.py +0 -84
  534. package/ref-monty/crates/monty/test_cases/builtin__iter_funcs.py +0 -42
  535. package/ref-monty/crates/monty/test_cases/builtin__iter_next.py +0 -66
  536. package/ref-monty/crates/monty/test_cases/builtin__map.py +0 -74
  537. package/ref-monty/crates/monty/test_cases/builtin__map_not_iterable.py +0 -11
  538. package/ref-monty/crates/monty/test_cases/builtin__math_funcs.py +0 -154
  539. package/ref-monty/crates/monty/test_cases/builtin__more_iter_funcs.py +0 -148
  540. package/ref-monty/crates/monty/test_cases/builtin__next_stop_iteration.py +0 -10
  541. package/ref-monty/crates/monty/test_cases/builtin__print_invalid_kwarg.py +0 -9
  542. package/ref-monty/crates/monty/test_cases/builtin__print_kwargs.py +0 -12
  543. package/ref-monty/crates/monty/test_cases/builtin__repr.py +0 -3
  544. package/ref-monty/crates/monty/test_cases/builtin__string_funcs.py +0 -73
  545. package/ref-monty/crates/monty/test_cases/bytes__decode_invalid_utf8.py +0 -18
  546. package/ref-monty/crates/monty/test_cases/bytes__endswith_str_error.py +0 -10
  547. package/ref-monty/crates/monty/test_cases/bytes__getitem_index_error.py +0 -10
  548. package/ref-monty/crates/monty/test_cases/bytes__index_start_gt_end.py +0 -10
  549. package/ref-monty/crates/monty/test_cases/bytes__methods.py +0 -394
  550. package/ref-monty/crates/monty/test_cases/bytes__negative_count.py +0 -9
  551. package/ref-monty/crates/monty/test_cases/bytes__ops.py +0 -90
  552. package/ref-monty/crates/monty/test_cases/bytes__startswith_str_error.py +0 -10
  553. package/ref-monty/crates/monty/test_cases/call_object.py +0 -3
  554. package/ref-monty/crates/monty/test_cases/chain_comparison__all.py +0 -79
  555. package/ref-monty/crates/monty/test_cases/closure__param_shadows_outer.py +0 -81
  556. package/ref-monty/crates/monty/test_cases/closure__pep448.py +0 -203
  557. package/ref-monty/crates/monty/test_cases/closure__undefined_nonlocal.py +0 -13
  558. package/ref-monty/crates/monty/test_cases/compare__mixed_types.py +0 -120
  559. package/ref-monty/crates/monty/test_cases/comprehension__all.py +0 -208
  560. package/ref-monty/crates/monty/test_cases/comprehension__scope.py +0 -7
  561. package/ref-monty/crates/monty/test_cases/comprehension__unbound_local.py +0 -14
  562. package/ref-monty/crates/monty/test_cases/dataclass__basic.py +0 -238
  563. package/ref-monty/crates/monty/test_cases/dataclass__call_field_error.py +0 -12
  564. package/ref-monty/crates/monty/test_cases/dataclass__frozen_set_error.py +0 -12
  565. package/ref-monty/crates/monty/test_cases/dataclass__get_missing_attr_error.py +0 -11
  566. package/ref-monty/crates/monty/test_cases/dict__get_unhashable_key.py +0 -3
  567. package/ref-monty/crates/monty/test_cases/dict__literal_unhashable_key.py +0 -2
  568. package/ref-monty/crates/monty/test_cases/dict__method_pop_missing_error.py +0 -3
  569. package/ref-monty/crates/monty/test_cases/dict__methods.py +0 -151
  570. package/ref-monty/crates/monty/test_cases/dict__ops.py +0 -133
  571. package/ref-monty/crates/monty/test_cases/dict__pop_unhashable_key.py +0 -4
  572. package/ref-monty/crates/monty/test_cases/dict__popitem_empty.py +0 -9
  573. package/ref-monty/crates/monty/test_cases/dict__subscript_missing_key.py +0 -3
  574. package/ref-monty/crates/monty/test_cases/dict__unhashable_dict_key.py +0 -2
  575. package/ref-monty/crates/monty/test_cases/dict__unhashable_list_key.py +0 -2
  576. package/ref-monty/crates/monty/test_cases/dict__unpack_type_error.py +0 -2
  577. package/ref-monty/crates/monty/test_cases/dict__views.py +0 -165
  578. package/ref-monty/crates/monty/test_cases/edge__all.py +0 -26
  579. package/ref-monty/crates/monty/test_cases/edge__float_int_mod.py +0 -2
  580. package/ref-monty/crates/monty/test_cases/edge__int_float_mod.py +0 -2
  581. package/ref-monty/crates/monty/test_cases/exc__args.py +0 -16
  582. package/ref-monty/crates/monty/test_cases/exc__str.py +0 -15
  583. package/ref-monty/crates/monty/test_cases/execute_ok__all.py +0 -54
  584. package/ref-monty/crates/monty/test_cases/execute_raise__error_instance_str.py +0 -2
  585. package/ref-monty/crates/monty/test_cases/execute_raise__error_no_args.py +0 -2
  586. package/ref-monty/crates/monty/test_cases/execute_raise__error_string_arg.py +0 -2
  587. package/ref-monty/crates/monty/test_cases/execute_raise__error_string_arg_quotes.py +0 -2
  588. package/ref-monty/crates/monty/test_cases/execute_raise__error_type.py +0 -2
  589. package/ref-monty/crates/monty/test_cases/execute_raise__raise_instance_via_var.py +0 -4
  590. package/ref-monty/crates/monty/test_cases/execute_raise__raise_list.py +0 -2
  591. package/ref-monty/crates/monty/test_cases/execute_raise__raise_number.py +0 -2
  592. package/ref-monty/crates/monty/test_cases/execute_raise__raise_type_call_via_var.py +0 -4
  593. package/ref-monty/crates/monty/test_cases/execute_raise__raise_type_direct.py +0 -3
  594. package/ref-monty/crates/monty/test_cases/execute_raise__raise_type_via_var.py +0 -4
  595. package/ref-monty/crates/monty/test_cases/ext_call__arg_side_effect_bug.py +0 -22
  596. package/ref-monty/crates/monty/test_cases/ext_call__augmented.py +0 -17
  597. package/ref-monty/crates/monty/test_cases/ext_call__augmented_refcount_bug.py +0 -7
  598. package/ref-monty/crates/monty/test_cases/ext_call__bare_raise_after_resume.py +0 -34
  599. package/ref-monty/crates/monty/test_cases/ext_call__basic.py +0 -99
  600. package/ref-monty/crates/monty/test_cases/ext_call__boolean.py +0 -37
  601. package/ref-monty/crates/monty/test_cases/ext_call__boolean_side_effect_hang.py +0 -17
  602. package/ref-monty/crates/monty/test_cases/ext_call__closure_bug.py +0 -16
  603. package/ref-monty/crates/monty/test_cases/ext_call__comparison.py +0 -26
  604. package/ref-monty/crates/monty/test_cases/ext_call__deep_call_stack.py +0 -18
  605. package/ref-monty/crates/monty/test_cases/ext_call__elif.py +0 -171
  606. package/ref-monty/crates/monty/test_cases/ext_call__exc.py +0 -4
  607. package/ref-monty/crates/monty/test_cases/ext_call__exc_deep_stack.py +0 -39
  608. package/ref-monty/crates/monty/test_cases/ext_call__exc_in_function.py +0 -17
  609. package/ref-monty/crates/monty/test_cases/ext_call__exc_nested_functions.py +0 -31
  610. package/ref-monty/crates/monty/test_cases/ext_call__ext_exc.py +0 -171
  611. package/ref-monty/crates/monty/test_cases/ext_call__for.py +0 -114
  612. package/ref-monty/crates/monty/test_cases/ext_call__fstring.py +0 -12
  613. package/ref-monty/crates/monty/test_cases/ext_call__if.py +0 -135
  614. package/ref-monty/crates/monty/test_cases/ext_call__if_condition.py +0 -37
  615. package/ref-monty/crates/monty/test_cases/ext_call__in_closure.py +0 -14
  616. package/ref-monty/crates/monty/test_cases/ext_call__in_function.py +0 -40
  617. package/ref-monty/crates/monty/test_cases/ext_call__in_function_simple.py +0 -7
  618. package/ref-monty/crates/monty/test_cases/ext_call__literals.py +0 -17
  619. package/ref-monty/crates/monty/test_cases/ext_call__multi_in_func.py +0 -32
  620. package/ref-monty/crates/monty/test_cases/ext_call__name_lookup.py +0 -69
  621. package/ref-monty/crates/monty/test_cases/ext_call__name_lookup_undefined.py +0 -4
  622. package/ref-monty/crates/monty/test_cases/ext_call__nested_calls.py +0 -14
  623. package/ref-monty/crates/monty/test_cases/ext_call__recursion_bug.py +0 -19
  624. package/ref-monty/crates/monty/test_cases/ext_call__return.py +0 -28
  625. package/ref-monty/crates/monty/test_cases/ext_call__side_effects.py +0 -25
  626. package/ref-monty/crates/monty/test_cases/ext_call__subscript.py +0 -7
  627. package/ref-monty/crates/monty/test_cases/ext_call__ternary.py +0 -28
  628. package/ref-monty/crates/monty/test_cases/ext_call__try.py +0 -280
  629. package/ref-monty/crates/monty/test_cases/ext_call__try_simple.py +0 -10
  630. package/ref-monty/crates/monty/test_cases/ext_call__unary.py +0 -13
  631. package/ref-monty/crates/monty/test_cases/frozenset__ops.py +0 -178
  632. package/ref-monty/crates/monty/test_cases/fstring__all.py +0 -236
  633. package/ref-monty/crates/monty/test_cases/fstring__error_eq_align_on_str.py +0 -3
  634. package/ref-monty/crates/monty/test_cases/fstring__error_float_f_on_str.py +0 -3
  635. package/ref-monty/crates/monty/test_cases/fstring__error_int_d_on_float.py +0 -3
  636. package/ref-monty/crates/monty/test_cases/fstring__error_int_d_on_str.py +0 -3
  637. package/ref-monty/crates/monty/test_cases/fstring__error_invalid_spec.py +0 -4
  638. package/ref-monty/crates/monty/test_cases/fstring__error_invalid_spec_dynamic.py +0 -4
  639. package/ref-monty/crates/monty/test_cases/fstring__error_invalid_spec_str.py +0 -4
  640. package/ref-monty/crates/monty/test_cases/fstring__error_str_s_on_int.py +0 -3
  641. package/ref-monty/crates/monty/test_cases/function__call_duplicate_kwargs.py +0 -6
  642. package/ref-monty/crates/monty/test_cases/function__call_unpack.py +0 -42
  643. package/ref-monty/crates/monty/test_cases/function__defaults.py +0 -117
  644. package/ref-monty/crates/monty/test_cases/function__err_duplicate_arg.py +0 -7
  645. package/ref-monty/crates/monty/test_cases/function__err_duplicate_first_arg.py +0 -7
  646. package/ref-monty/crates/monty/test_cases/function__err_duplicate_kwarg_cleanup.py +0 -9
  647. package/ref-monty/crates/monty/test_cases/function__err_kwonly_as_positional.py +0 -7
  648. package/ref-monty/crates/monty/test_cases/function__err_missing_all_posonly.py +0 -7
  649. package/ref-monty/crates/monty/test_cases/function__err_missing_heap_cleanup.py +0 -9
  650. package/ref-monty/crates/monty/test_cases/function__err_missing_kwonly.py +0 -7
  651. package/ref-monty/crates/monty/test_cases/function__err_missing_posonly_with_kwarg.py +0 -7
  652. package/ref-monty/crates/monty/test_cases/function__err_missing_with_posonly.py +0 -7
  653. package/ref-monty/crates/monty/test_cases/function__err_posonly_as_kwarg.py +0 -7
  654. package/ref-monty/crates/monty/test_cases/function__err_posonly_first_as_kwarg.py +0 -7
  655. package/ref-monty/crates/monty/test_cases/function__err_too_many_posonly.py +0 -7
  656. package/ref-monty/crates/monty/test_cases/function__err_too_many_with_kwonly.py +0 -7
  657. package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg.py +0 -7
  658. package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg_cleanup.py +0 -9
  659. package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg_quote.py +0 -13
  660. package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg_simple.py +0 -7
  661. package/ref-monty/crates/monty/test_cases/function__err_unpack_duplicate_arg.py +0 -6
  662. package/ref-monty/crates/monty/test_cases/function__err_unpack_duplicate_heap.py +0 -8
  663. package/ref-monty/crates/monty/test_cases/function__err_unpack_int.py +0 -6
  664. package/ref-monty/crates/monty/test_cases/function__err_unpack_nonstring_key.py +0 -6
  665. package/ref-monty/crates/monty/test_cases/function__err_unpack_not_mapping.py +0 -6
  666. package/ref-monty/crates/monty/test_cases/function__kwargs_unpacking.py +0 -173
  667. package/ref-monty/crates/monty/test_cases/function__ops.py +0 -294
  668. package/ref-monty/crates/monty/test_cases/function__return_none.py +0 -42
  669. package/ref-monty/crates/monty/test_cases/function__signatures.py +0 -47
  670. package/ref-monty/crates/monty/test_cases/function__too_few_args_all.py +0 -6
  671. package/ref-monty/crates/monty/test_cases/function__too_few_args_one.py +0 -6
  672. package/ref-monty/crates/monty/test_cases/function__too_few_args_two.py +0 -6
  673. package/ref-monty/crates/monty/test_cases/function__too_many_args_one.py +0 -6
  674. package/ref-monty/crates/monty/test_cases/function__too_many_args_two.py +0 -6
  675. package/ref-monty/crates/monty/test_cases/function__too_many_args_zero.py +0 -6
  676. package/ref-monty/crates/monty/test_cases/global__error_assigned_before.py +0 -7
  677. package/ref-monty/crates/monty/test_cases/global__ops.py +0 -163
  678. package/ref-monty/crates/monty/test_cases/hash__dict_unhashable.py +0 -2
  679. package/ref-monty/crates/monty/test_cases/hash__list_unhashable.py +0 -2
  680. package/ref-monty/crates/monty/test_cases/hash__ops.py +0 -153
  681. package/ref-monty/crates/monty/test_cases/id__bytes_literals_distinct.py +0 -3
  682. package/ref-monty/crates/monty/test_cases/id__int_copy_distinct.py +0 -5
  683. package/ref-monty/crates/monty/test_cases/id__is_number_is_number.py +0 -3
  684. package/ref-monty/crates/monty/test_cases/id__non_overlapping_lifetimes_distinct_types.py +0 -10
  685. package/ref-monty/crates/monty/test_cases/id__non_overlapping_lifetimes_same_types.py +0 -6
  686. package/ref-monty/crates/monty/test_cases/id__ops.py +0 -97
  687. package/ref-monty/crates/monty/test_cases/id__str_literals_same.py +0 -3
  688. package/ref-monty/crates/monty/test_cases/if__elif_else.py +0 -207
  689. package/ref-monty/crates/monty/test_cases/if__raise_elif.py +0 -11
  690. package/ref-monty/crates/monty/test_cases/if__raise_else.py +0 -13
  691. package/ref-monty/crates/monty/test_cases/if__raise_if.py +0 -9
  692. package/ref-monty/crates/monty/test_cases/if__raise_in_elif_condition.py +0 -18
  693. package/ref-monty/crates/monty/test_cases/if__raise_in_if_condition.py +0 -16
  694. package/ref-monty/crates/monty/test_cases/if_else_expr__all.py +0 -55
  695. package/ref-monty/crates/monty/test_cases/import__error_cannot_import.py +0 -9
  696. package/ref-monty/crates/monty/test_cases/import__error_module_not_found.py +0 -9
  697. package/ref-monty/crates/monty/test_cases/import__local_scope.py +0 -68
  698. package/ref-monty/crates/monty/test_cases/import__os.py +0 -25
  699. package/ref-monty/crates/monty/test_cases/import__relative_error.py +0 -9
  700. package/ref-monty/crates/monty/test_cases/import__relative_no_module_error.py +0 -9
  701. package/ref-monty/crates/monty/test_cases/import__runtime_error_when_executed.py +0 -14
  702. package/ref-monty/crates/monty/test_cases/import__star_error.py +0 -11
  703. package/ref-monty/crates/monty/test_cases/import__sys.py +0 -47
  704. package/ref-monty/crates/monty/test_cases/import__sys_monty.py +0 -28
  705. package/ref-monty/crates/monty/test_cases/import__type_checking_guard.py +0 -37
  706. package/ref-monty/crates/monty/test_cases/import__typing.py +0 -25
  707. package/ref-monty/crates/monty/test_cases/import__typing_type_ignore.py +0 -4
  708. package/ref-monty/crates/monty/test_cases/int__bigint.py +0 -467
  709. package/ref-monty/crates/monty/test_cases/int__bigint_errors.py +0 -260
  710. package/ref-monty/crates/monty/test_cases/int__ops.py +0 -219
  711. package/ref-monty/crates/monty/test_cases/int__overflow_division.py +0 -84
  712. package/ref-monty/crates/monty/test_cases/is_variant__all.py +0 -36
  713. package/ref-monty/crates/monty/test_cases/isinstance__arg2_list_error.py +0 -2
  714. package/ref-monty/crates/monty/test_cases/isinstance__arg2_type_error.py +0 -2
  715. package/ref-monty/crates/monty/test_cases/iter__dict_mutation.py +0 -4
  716. package/ref-monty/crates/monty/test_cases/iter__for.py +0 -243
  717. package/ref-monty/crates/monty/test_cases/iter__for_loop_unpacking.py +0 -66
  718. package/ref-monty/crates/monty/test_cases/iter__generator_expr.py +0 -20
  719. package/ref-monty/crates/monty/test_cases/iter__generator_expr_type.py +0 -7
  720. package/ref-monty/crates/monty/test_cases/iter__not_iterable.py +0 -3
  721. package/ref-monty/crates/monty/test_cases/lambda__all.py +0 -145
  722. package/ref-monty/crates/monty/test_cases/list__extend_not_iterable.py +0 -7
  723. package/ref-monty/crates/monty/test_cases/list__getitem_out_of_bounds.py +0 -3
  724. package/ref-monty/crates/monty/test_cases/list__index_not_found.py +0 -9
  725. package/ref-monty/crates/monty/test_cases/list__index_start_gt_end.py +0 -10
  726. package/ref-monty/crates/monty/test_cases/list__ops.py +0 -473
  727. package/ref-monty/crates/monty/test_cases/list__pop_empty.py +0 -9
  728. package/ref-monty/crates/monty/test_cases/list__pop_out_of_range.py +0 -9
  729. package/ref-monty/crates/monty/test_cases/list__pop_type_error.py +0 -9
  730. package/ref-monty/crates/monty/test_cases/list__remove_not_found.py +0 -9
  731. package/ref-monty/crates/monty/test_cases/list__setitem_dict_index.py +0 -13
  732. package/ref-monty/crates/monty/test_cases/list__setitem_huge_int_index.py +0 -13
  733. package/ref-monty/crates/monty/test_cases/list__setitem_index_error.py +0 -10
  734. package/ref-monty/crates/monty/test_cases/list__setitem_type_error.py +0 -10
  735. package/ref-monty/crates/monty/test_cases/list__unpack_type_error.py +0 -2
  736. package/ref-monty/crates/monty/test_cases/longint__index_error.py +0 -3
  737. package/ref-monty/crates/monty/test_cases/longint__repeat_error.py +0 -3
  738. package/ref-monty/crates/monty/test_cases/loop__break_continue.py +0 -113
  739. package/ref-monty/crates/monty/test_cases/loop__break_finally.py +0 -69
  740. package/ref-monty/crates/monty/test_cases/loop__break_in_function_error.py +0 -13
  741. package/ref-monty/crates/monty/test_cases/loop__break_in_if_error.py +0 -11
  742. package/ref-monty/crates/monty/test_cases/loop__break_nested_except_clears.py +0 -55
  743. package/ref-monty/crates/monty/test_cases/loop__break_outside_error.py +0 -9
  744. package/ref-monty/crates/monty/test_cases/loop__continue_finally.py +0 -81
  745. package/ref-monty/crates/monty/test_cases/loop__continue_in_function_error.py +0 -13
  746. package/ref-monty/crates/monty/test_cases/loop__continue_in_if_error.py +0 -11
  747. package/ref-monty/crates/monty/test_cases/loop__continue_nested_except_clears.py +0 -60
  748. package/ref-monty/crates/monty/test_cases/loop__continue_outside_error.py +0 -9
  749. package/ref-monty/crates/monty/test_cases/math__acos_domain_error.py +0 -11
  750. package/ref-monty/crates/monty/test_cases/math__acosh_domain_error.py +0 -11
  751. package/ref-monty/crates/monty/test_cases/math__asin_domain_error.py +0 -11
  752. package/ref-monty/crates/monty/test_cases/math__atanh_domain_error.py +0 -11
  753. package/ref-monty/crates/monty/test_cases/math__cos_inf_error.py +0 -11
  754. package/ref-monty/crates/monty/test_cases/math__cosh_overflow_error.py +0 -11
  755. package/ref-monty/crates/monty/test_cases/math__exp_overflow_error.py +0 -11
  756. package/ref-monty/crates/monty/test_cases/math__factorial_float_error.py +0 -11
  757. package/ref-monty/crates/monty/test_cases/math__factorial_negative_error.py +0 -11
  758. package/ref-monty/crates/monty/test_cases/math__floor_inf_error.py +0 -11
  759. package/ref-monty/crates/monty/test_cases/math__floor_nan_error.py +0 -11
  760. package/ref-monty/crates/monty/test_cases/math__floor_str_error.py +0 -11
  761. package/ref-monty/crates/monty/test_cases/math__fmod_inf_error.py +0 -11
  762. package/ref-monty/crates/monty/test_cases/math__gamma_neg_int_error.py +0 -11
  763. package/ref-monty/crates/monty/test_cases/math__gcd_float_error.py +0 -11
  764. package/ref-monty/crates/monty/test_cases/math__isqrt_negative_error.py +0 -11
  765. package/ref-monty/crates/monty/test_cases/math__ldexp_overflow_error.py +0 -11
  766. package/ref-monty/crates/monty/test_cases/math__log1p_domain_error.py +0 -11
  767. package/ref-monty/crates/monty/test_cases/math__log_base1_error.py +0 -11
  768. package/ref-monty/crates/monty/test_cases/math__log_zero_error.py +0 -11
  769. package/ref-monty/crates/monty/test_cases/math__module.py +0 -1432
  770. package/ref-monty/crates/monty/test_cases/math__pow_domain_error.py +0 -11
  771. package/ref-monty/crates/monty/test_cases/math__sin_inf_error.py +0 -11
  772. package/ref-monty/crates/monty/test_cases/math__sqrt_negative_error.py +0 -11
  773. package/ref-monty/crates/monty/test_cases/math__tan_inf_error.py +0 -11
  774. package/ref-monty/crates/monty/test_cases/math__trunc_str_error.py +0 -11
  775. package/ref-monty/crates/monty/test_cases/method__args_kwargs_unpacking.py +0 -259
  776. package/ref-monty/crates/monty/test_cases/name_error__unbound_local_func.py +0 -19
  777. package/ref-monty/crates/monty/test_cases/name_error__unbound_local_module.py +0 -12
  778. package/ref-monty/crates/monty/test_cases/name_error__undefined_call_chained.py +0 -9
  779. package/ref-monty/crates/monty/test_cases/name_error__undefined_call_in_expr.py +0 -9
  780. package/ref-monty/crates/monty/test_cases/name_error__undefined_call_in_function.py +0 -16
  781. package/ref-monty/crates/monty/test_cases/name_error__undefined_call_with_args.py +0 -9
  782. package/ref-monty/crates/monty/test_cases/name_error__undefined_global.py +0 -10
  783. package/ref-monty/crates/monty/test_cases/namedtuple__missing_attr.py +0 -11
  784. package/ref-monty/crates/monty/test_cases/namedtuple__ops.py +0 -34
  785. package/ref-monty/crates/monty/test_cases/nonlocal__error_module_level.py +0 -3
  786. package/ref-monty/crates/monty/test_cases/nonlocal__ops.py +0 -353
  787. package/ref-monty/crates/monty/test_cases/os__environ.py +0 -40
  788. package/ref-monty/crates/monty/test_cases/os__getenv_key_list_error.py +0 -5
  789. package/ref-monty/crates/monty/test_cases/os__getenv_key_type_error.py +0 -5
  790. package/ref-monty/crates/monty/test_cases/parse_error__complex.py +0 -3
  791. package/ref-monty/crates/monty/test_cases/pathlib__import.py +0 -11
  792. package/ref-monty/crates/monty/test_cases/pathlib__os.py +0 -136
  793. package/ref-monty/crates/monty/test_cases/pathlib__os_read_error.py +0 -12
  794. package/ref-monty/crates/monty/test_cases/pathlib__pure.py +0 -81
  795. package/ref-monty/crates/monty/test_cases/pyobject__cycle_dict_self.py +0 -5
  796. package/ref-monty/crates/monty/test_cases/pyobject__cycle_list_dict.py +0 -6
  797. package/ref-monty/crates/monty/test_cases/pyobject__cycle_list_self.py +0 -5
  798. package/ref-monty/crates/monty/test_cases/pyobject__cycle_multiple_refs.py +0 -6
  799. package/ref-monty/crates/monty/test_cases/range__error_no_args.py +0 -2
  800. package/ref-monty/crates/monty/test_cases/range__error_step_zero.py +0 -2
  801. package/ref-monty/crates/monty/test_cases/range__error_too_many_args.py +0 -2
  802. package/ref-monty/crates/monty/test_cases/range__getitem_index_error.py +0 -10
  803. package/ref-monty/crates/monty/test_cases/range__ops.py +0 -236
  804. package/ref-monty/crates/monty/test_cases/re__basic.py +0 -756
  805. package/ref-monty/crates/monty/test_cases/re__grouping.py +0 -241
  806. package/ref-monty/crates/monty/test_cases/re__match.py +0 -148
  807. package/ref-monty/crates/monty/test_cases/recursion__deep_drop.py +0 -26
  808. package/ref-monty/crates/monty/test_cases/recursion__deep_eq.py +0 -23
  809. package/ref-monty/crates/monty/test_cases/recursion__deep_hash.py +0 -46
  810. package/ref-monty/crates/monty/test_cases/recursion__deep_repr.py +0 -12
  811. package/ref-monty/crates/monty/test_cases/recursion__function_depth.py +0 -13
  812. package/ref-monty/crates/monty/test_cases/refcount__cycle_mutual_reference.py +0 -18
  813. package/ref-monty/crates/monty/test_cases/refcount__cycle_self_reference.py +0 -12
  814. package/ref-monty/crates/monty/test_cases/refcount__dict_basic.py +0 -5
  815. package/ref-monty/crates/monty/test_cases/refcount__dict_get.py +0 -5
  816. package/ref-monty/crates/monty/test_cases/refcount__dict_keys_and.py +0 -14
  817. package/ref-monty/crates/monty/test_cases/refcount__dict_overwrite.py +0 -6
  818. package/ref-monty/crates/monty/test_cases/refcount__gather_cleanup.py +0 -16
  819. package/ref-monty/crates/monty/test_cases/refcount__gather_exception.py +0 -18
  820. package/ref-monty/crates/monty/test_cases/refcount__gather_nested_cancel.py +0 -25
  821. package/ref-monty/crates/monty/test_cases/refcount__immediate_skipped.py +0 -4
  822. package/ref-monty/crates/monty/test_cases/refcount__kwargs_unpacking.py +0 -27
  823. package/ref-monty/crates/monty/test_cases/refcount__list_append_multiple.py +0 -6
  824. package/ref-monty/crates/monty/test_cases/refcount__list_append_ref.py +0 -5
  825. package/ref-monty/crates/monty/test_cases/refcount__list_concat.py +0 -5
  826. package/ref-monty/crates/monty/test_cases/refcount__list_getitem.py +0 -5
  827. package/ref-monty/crates/monty/test_cases/refcount__list_iadd.py +0 -5
  828. package/ref-monty/crates/monty/test_cases/refcount__nested_list.py +0 -4
  829. package/ref-monty/crates/monty/test_cases/refcount__re_pattern_sub_error_paths.py +0 -37
  830. package/ref-monty/crates/monty/test_cases/refcount__re_search_match.py +0 -34
  831. package/ref-monty/crates/monty/test_cases/refcount__re_sub_error_paths.py +0 -31
  832. package/ref-monty/crates/monty/test_cases/refcount__shared_reference.py +0 -4
  833. package/ref-monty/crates/monty/test_cases/refcount__single_list.py +0 -3
  834. package/ref-monty/crates/monty/test_cases/repr__cycle_detection.py +0 -24
  835. package/ref-monty/crates/monty/test_cases/set__ops.py +0 -191
  836. package/ref-monty/crates/monty/test_cases/set__review_bugs.py +0 -35
  837. package/ref-monty/crates/monty/test_cases/set__unpack_type_error.py +0 -2
  838. package/ref-monty/crates/monty/test_cases/slice__invalid_indices.py +0 -2
  839. package/ref-monty/crates/monty/test_cases/slice__kwargs.py +0 -9
  840. package/ref-monty/crates/monty/test_cases/slice__no_args.py +0 -9
  841. package/ref-monty/crates/monty/test_cases/slice__ops.py +0 -149
  842. package/ref-monty/crates/monty/test_cases/slice__step_zero.py +0 -9
  843. package/ref-monty/crates/monty/test_cases/slice__step_zero_bytes.py +0 -9
  844. package/ref-monty/crates/monty/test_cases/slice__step_zero_range.py +0 -9
  845. package/ref-monty/crates/monty/test_cases/slice__step_zero_str.py +0 -9
  846. package/ref-monty/crates/monty/test_cases/slice__step_zero_tuple.py +0 -9
  847. package/ref-monty/crates/monty/test_cases/slice__too_many_args.py +0 -9
  848. package/ref-monty/crates/monty/test_cases/str__getitem_index_error.py +0 -10
  849. package/ref-monty/crates/monty/test_cases/str__index_not_found.py +0 -9
  850. package/ref-monty/crates/monty/test_cases/str__join_no_args.py +0 -9
  851. package/ref-monty/crates/monty/test_cases/str__join_non_string.py +0 -9
  852. package/ref-monty/crates/monty/test_cases/str__join_not_iterable.py +0 -9
  853. package/ref-monty/crates/monty/test_cases/str__join_too_many_args.py +0 -9
  854. package/ref-monty/crates/monty/test_cases/str__methods.py +0 -327
  855. package/ref-monty/crates/monty/test_cases/str__ops.py +0 -162
  856. package/ref-monty/crates/monty/test_cases/str__partition_empty.py +0 -9
  857. package/ref-monty/crates/monty/test_cases/str__rsplit_empty_sep.py +0 -9
  858. package/ref-monty/crates/monty/test_cases/str__split_empty_sep.py +0 -9
  859. package/ref-monty/crates/monty/test_cases/sys__types.py +0 -7
  860. package/ref-monty/crates/monty/test_cases/traceback__division_error.py +0 -30
  861. package/ref-monty/crates/monty/test_cases/traceback__index_error.py +0 -17
  862. package/ref-monty/crates/monty/test_cases/traceback__insert_as_int.py +0 -10
  863. package/ref-monty/crates/monty/test_cases/traceback__nested_call.py +0 -29
  864. package/ref-monty/crates/monty/test_cases/traceback__nonlocal_module_scope.py +0 -10
  865. package/ref-monty/crates/monty/test_cases/traceback__nonlocal_unbound.py +0 -24
  866. package/ref-monty/crates/monty/test_cases/traceback__range_as_int.py +0 -9
  867. package/ref-monty/crates/monty/test_cases/traceback__recursion_error.py +0 -23
  868. package/ref-monty/crates/monty/test_cases/traceback__set_mutation.py +0 -11
  869. package/ref-monty/crates/monty/test_cases/traceback__undefined_attr_call.py +0 -16
  870. package/ref-monty/crates/monty/test_cases/traceback__undefined_call.py +0 -16
  871. package/ref-monty/crates/monty/test_cases/traceback__undefined_raise.py +0 -16
  872. package/ref-monty/crates/monty/test_cases/try_except__all.py +0 -472
  873. package/ref-monty/crates/monty/test_cases/try_except__bare_raise_no_context.py +0 -2
  874. package/ref-monty/crates/monty/test_cases/try_except__invalid_type.py +0 -5
  875. package/ref-monty/crates/monty/test_cases/tuple__getitem_out_of_bounds.py +0 -3
  876. package/ref-monty/crates/monty/test_cases/tuple__index_not_found.py +0 -9
  877. package/ref-monty/crates/monty/test_cases/tuple__index_start_gt_end.py +0 -10
  878. package/ref-monty/crates/monty/test_cases/tuple__methods.py +0 -19
  879. package/ref-monty/crates/monty/test_cases/tuple__ops.py +0 -133
  880. package/ref-monty/crates/monty/test_cases/tuple__unpack_type_error.py +0 -2
  881. package/ref-monty/crates/monty/test_cases/type__builtin_attr_error.py +0 -9
  882. package/ref-monty/crates/monty/test_cases/type__bytes_negative.py +0 -2
  883. package/ref-monty/crates/monty/test_cases/type__cell_not_builtin.py +0 -9
  884. package/ref-monty/crates/monty/test_cases/type__exception_attr_error.py +0 -11
  885. package/ref-monty/crates/monty/test_cases/type__float_conversion_error.py +0 -2
  886. package/ref-monty/crates/monty/test_cases/type__float_repr_both_quotes.py +0 -9
  887. package/ref-monty/crates/monty/test_cases/type__float_repr_newline.py +0 -9
  888. package/ref-monty/crates/monty/test_cases/type__float_repr_single_quote.py +0 -9
  889. package/ref-monty/crates/monty/test_cases/type__int_conversion_error.py +0 -2
  890. package/ref-monty/crates/monty/test_cases/type__list_not_iterable.py +0 -2
  891. package/ref-monty/crates/monty/test_cases/type__non_builtin_name_error.py +0 -9
  892. package/ref-monty/crates/monty/test_cases/type__ops.py +0 -200
  893. package/ref-monty/crates/monty/test_cases/type__shadow_exc.py +0 -3
  894. package/ref-monty/crates/monty/test_cases/type__shadow_int.py +0 -9
  895. package/ref-monty/crates/monty/test_cases/type__shadow_len.py +0 -3
  896. package/ref-monty/crates/monty/test_cases/type__tuple_not_iterable.py +0 -2
  897. package/ref-monty/crates/monty/test_cases/type_error__int_add_list.py +0 -2
  898. package/ref-monty/crates/monty/test_cases/type_error__int_div_str.py +0 -2
  899. package/ref-monty/crates/monty/test_cases/type_error__int_floordiv_str.py +0 -2
  900. package/ref-monty/crates/monty/test_cases/type_error__int_iadd_str.py +0 -3
  901. package/ref-monty/crates/monty/test_cases/type_error__int_mod_str.py +0 -2
  902. package/ref-monty/crates/monty/test_cases/type_error__int_pow_str.py +0 -2
  903. package/ref-monty/crates/monty/test_cases/type_error__int_sub_str.py +0 -2
  904. package/ref-monty/crates/monty/test_cases/type_error__list_add_int.py +0 -2
  905. package/ref-monty/crates/monty/test_cases/type_error__list_add_str.py +0 -2
  906. package/ref-monty/crates/monty/test_cases/type_error__list_iadd_int.py +0 -6
  907. package/ref-monty/crates/monty/test_cases/type_error__str_add_int.py +0 -2
  908. package/ref-monty/crates/monty/test_cases/type_error__str_iadd_int.py +0 -3
  909. package/ref-monty/crates/monty/test_cases/type_error__unary_invert_str.py +0 -3
  910. package/ref-monty/crates/monty/test_cases/type_error__unary_minus_str.py +0 -4
  911. package/ref-monty/crates/monty/test_cases/type_error__unary_neg_str.py +0 -3
  912. package/ref-monty/crates/monty/test_cases/type_error__unary_plus_str.py +0 -4
  913. package/ref-monty/crates/monty/test_cases/typing__types.py +0 -24
  914. package/ref-monty/crates/monty/test_cases/unpack__nested.py +0 -48
  915. package/ref-monty/crates/monty/test_cases/unpack__non_sequence.py +0 -9
  916. package/ref-monty/crates/monty/test_cases/unpack__not_enough.py +0 -9
  917. package/ref-monty/crates/monty/test_cases/unpack__ops.py +0 -153
  918. package/ref-monty/crates/monty/test_cases/unpack__star_not_enough.py +0 -9
  919. package/ref-monty/crates/monty/test_cases/unpack__too_many.py +0 -9
  920. package/ref-monty/crates/monty/test_cases/version__cpython.py +0 -4
  921. package/ref-monty/crates/monty/test_cases/walrus__all.py +0 -178
  922. package/ref-monty/crates/monty/test_cases/while__all.py +0 -206
  923. package/ref-monty/crates/monty/tests/asyncio.rs +0 -764
  924. package/ref-monty/crates/monty/tests/binary_serde.rs +0 -185
  925. package/ref-monty/crates/monty/tests/bytecode_limits.rs +0 -248
  926. package/ref-monty/crates/monty/tests/datatest_runner.rs +0 -2029
  927. package/ref-monty/crates/monty/tests/inputs.rs +0 -420
  928. package/ref-monty/crates/monty/tests/json_serde.rs +0 -250
  929. package/ref-monty/crates/monty/tests/main.rs +0 -71
  930. package/ref-monty/crates/monty/tests/math_module.rs +0 -114
  931. package/ref-monty/crates/monty/tests/name_lookup.rs +0 -482
  932. package/ref-monty/crates/monty/tests/os_tests.rs +0 -459
  933. package/ref-monty/crates/monty/tests/parse_errors.rs +0 -441
  934. package/ref-monty/crates/monty/tests/print_writer.rs +0 -238
  935. package/ref-monty/crates/monty/tests/py_object.rs +0 -121
  936. package/ref-monty/crates/monty/tests/regex.rs +0 -90
  937. package/ref-monty/crates/monty/tests/repl.rs +0 -344
  938. package/ref-monty/crates/monty/tests/resource_limits.rs +0 -1826
  939. package/ref-monty/crates/monty/tests/try_from.rs +0 -167
  940. package/ref-monty/crates/monty-cli/Cargo.toml +0 -25
  941. package/ref-monty/crates/monty-cli/src/main.rs +0 -541
  942. package/ref-monty/crates/monty-js/.cargo/config.toml +0 -2
  943. package/ref-monty/crates/monty-js/.prettierignore +0 -8
  944. package/ref-monty/crates/monty-js/Cargo.toml +0 -32
  945. package/ref-monty/crates/monty-js/README.md +0 -207
  946. package/ref-monty/crates/monty-js/__test__/async.spec.ts +0 -350
  947. package/ref-monty/crates/monty-js/__test__/basic.spec.ts +0 -114
  948. package/ref-monty/crates/monty-js/__test__/exceptions.spec.ts +0 -427
  949. package/ref-monty/crates/monty-js/__test__/external.spec.ts +0 -354
  950. package/ref-monty/crates/monty-js/__test__/inputs.spec.ts +0 -143
  951. package/ref-monty/crates/monty-js/__test__/limits.spec.ts +0 -162
  952. package/ref-monty/crates/monty-js/__test__/package.json +0 -3
  953. package/ref-monty/crates/monty-js/__test__/print.spec.ts +0 -229
  954. package/ref-monty/crates/monty-js/__test__/repl.spec.ts +0 -34
  955. package/ref-monty/crates/monty-js/__test__/serialize.spec.ts +0 -205
  956. package/ref-monty/crates/monty-js/__test__/start.spec.ts +0 -443
  957. package/ref-monty/crates/monty-js/__test__/type_check.spec.ts +0 -147
  958. package/ref-monty/crates/monty-js/__test__/types.spec.ts +0 -319
  959. package/ref-monty/crates/monty-js/build.rs +0 -61
  960. package/ref-monty/crates/monty-js/index-header.d.ts +0 -3
  961. package/ref-monty/crates/monty-js/package-lock.json +0 -4694
  962. package/ref-monty/crates/monty-js/package.json +0 -100
  963. package/ref-monty/crates/monty-js/scripts/smoke-test.sh +0 -69
  964. package/ref-monty/crates/monty-js/smoke-test/package.json +0 -17
  965. package/ref-monty/crates/monty-js/smoke-test/test.ts +0 -171
  966. package/ref-monty/crates/monty-js/smoke-test/tsconfig.json +0 -11
  967. package/ref-monty/crates/monty-js/src/convert.rs +0 -648
  968. package/ref-monty/crates/monty-js/src/exceptions.rs +0 -293
  969. package/ref-monty/crates/monty-js/src/lib.rs +0 -41
  970. package/ref-monty/crates/monty-js/src/limits.rs +0 -53
  971. package/ref-monty/crates/monty-js/src/monty_cls.rs +0 -1407
  972. package/ref-monty/crates/monty-js/tsconfig.json +0 -17
  973. package/ref-monty/crates/monty-js/wrapper.ts +0 -701
  974. package/ref-monty/crates/monty-python/Cargo.toml +0 -38
  975. package/ref-monty/crates/monty-python/README.md +0 -134
  976. package/ref-monty/crates/monty-python/build.rs +0 -4
  977. package/ref-monty/crates/monty-python/example.py +0 -40
  978. package/ref-monty/crates/monty-python/exercise.py +0 -46
  979. package/ref-monty/crates/monty-python/pyproject.toml +0 -57
  980. package/ref-monty/crates/monty-python/python/pydantic_monty/__init__.py +0 -281
  981. package/ref-monty/crates/monty-python/python/pydantic_monty/_monty.pyi +0 -677
  982. package/ref-monty/crates/monty-python/python/pydantic_monty/os_access.py +0 -933
  983. package/ref-monty/crates/monty-python/python/pydantic_monty/py.typed +0 -0
  984. package/ref-monty/crates/monty-python/src/convert.rs +0 -273
  985. package/ref-monty/crates/monty-python/src/dataclass.rs +0 -461
  986. package/ref-monty/crates/monty-python/src/exceptions.rs +0 -557
  987. package/ref-monty/crates/monty-python/src/external.rs +0 -165
  988. package/ref-monty/crates/monty-python/src/lib.rs +0 -77
  989. package/ref-monty/crates/monty-python/src/limits.rs +0 -142
  990. package/ref-monty/crates/monty-python/src/monty_cls.rs +0 -1650
  991. package/ref-monty/crates/monty-python/src/repl.rs +0 -470
  992. package/ref-monty/crates/monty-python/src/serialization.rs +0 -761
  993. package/ref-monty/crates/monty-python/tests/test_async.py +0 -1201
  994. package/ref-monty/crates/monty-python/tests/test_basic.py +0 -66
  995. package/ref-monty/crates/monty-python/tests/test_dataclasses.py +0 -971
  996. package/ref-monty/crates/monty-python/tests/test_exceptions.py +0 -361
  997. package/ref-monty/crates/monty-python/tests/test_external.py +0 -367
  998. package/ref-monty/crates/monty-python/tests/test_inputs.py +0 -126
  999. package/ref-monty/crates/monty-python/tests/test_limits.py +0 -257
  1000. package/ref-monty/crates/monty-python/tests/test_os_access.py +0 -1286
  1001. package/ref-monty/crates/monty-python/tests/test_os_access_compat.py +0 -731
  1002. package/ref-monty/crates/monty-python/tests/test_os_access_raw.py +0 -483
  1003. package/ref-monty/crates/monty-python/tests/test_os_calls.py +0 -819
  1004. package/ref-monty/crates/monty-python/tests/test_print.py +0 -208
  1005. package/ref-monty/crates/monty-python/tests/test_re.py +0 -170
  1006. package/ref-monty/crates/monty-python/tests/test_readme_examples.py +0 -20
  1007. package/ref-monty/crates/monty-python/tests/test_repl.py +0 -749
  1008. package/ref-monty/crates/monty-python/tests/test_serialize.py +0 -284
  1009. package/ref-monty/crates/monty-python/tests/test_start.py +0 -346
  1010. package/ref-monty/crates/monty-python/tests/test_threading.py +0 -163
  1011. package/ref-monty/crates/monty-python/tests/test_type_check.py +0 -344
  1012. package/ref-monty/crates/monty-python/tests/test_types.py +0 -553
  1013. package/ref-monty/crates/monty-type-checking/Cargo.toml +0 -32
  1014. package/ref-monty/crates/monty-type-checking/src/db.rs +0 -116
  1015. package/ref-monty/crates/monty-type-checking/src/lib.rs +0 -4
  1016. package/ref-monty/crates/monty-type-checking/src/type_check.rs +0 -280
  1017. package/ref-monty/crates/monty-type-checking/tests/bad_types.py +0 -109
  1018. package/ref-monty/crates/monty-type-checking/tests/bad_types_output.txt +0 -21
  1019. package/ref-monty/crates/monty-type-checking/tests/good_types.py +0 -475
  1020. package/ref-monty/crates/monty-type-checking/tests/main.rs +0 -205
  1021. package/ref-monty/crates/monty-type-checking/tests/reveal_types.py +0 -56
  1022. package/ref-monty/crates/monty-type-checking/tests/reveal_types_output.txt +0 -41
  1023. package/ref-monty/crates/monty-typeshed/Cargo.toml +0 -29
  1024. package/ref-monty/crates/monty-typeshed/README.md +0 -11
  1025. package/ref-monty/crates/monty-typeshed/build.rs +0 -101
  1026. package/ref-monty/crates/monty-typeshed/custom/README.md +0 -1
  1027. package/ref-monty/crates/monty-typeshed/custom/asyncio.pyi +0 -138
  1028. package/ref-monty/crates/monty-typeshed/custom/os.pyi +0 -87
  1029. package/ref-monty/crates/monty-typeshed/custom/sys.pyi +0 -33
  1030. package/ref-monty/crates/monty-typeshed/src/lib.rs +0 -56
  1031. package/ref-monty/crates/monty-typeshed/update.py +0 -321
  1032. package/ref-monty/crates/monty-typeshed/vendor/typeshed/source_commit.txt +0 -1
  1033. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/VERSIONS +0 -20
  1034. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/_collections_abc.pyi +0 -105
  1035. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/_typeshed/__init__.pyi +0 -394
  1036. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/asyncio.pyi +0 -138
  1037. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/builtins.pyi +0 -1434
  1038. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/collections/__init__.pyi +0 -527
  1039. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/collections/abc.pyi +0 -2
  1040. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/dataclasses.pyi +0 -502
  1041. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/enum.pyi +0 -376
  1042. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/math.pyi +0 -149
  1043. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/os.pyi +0 -87
  1044. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/pathlib/__init__.pyi +0 -395
  1045. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/pathlib/types.pyi +0 -8
  1046. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/re.pyi +0 -337
  1047. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/sys.pyi +0 -33
  1048. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/types.pyi +0 -741
  1049. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/typing.pyi +0 -1217
  1050. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/typing_extensions.pyi +0 -716
  1051. package/ref-monty/docs/usage-guide.md +0 -117
  1052. package/ref-monty/examples/README.md +0 -3
  1053. package/ref-monty/examples/expense_analysis/README.md +0 -3
  1054. package/ref-monty/examples/expense_analysis/data.py +0 -124
  1055. package/ref-monty/examples/expense_analysis/main.py +0 -115
  1056. package/ref-monty/examples/sql_playground/README.md +0 -20
  1057. package/ref-monty/examples/sql_playground/external_functions.py +0 -129
  1058. package/ref-monty/examples/sql_playground/main.py +0 -81
  1059. package/ref-monty/examples/sql_playground/sandbox_code.py +0 -82
  1060. package/ref-monty/examples/sql_playground/type_stubs.pyi +0 -14
  1061. package/ref-monty/examples/web_scraper/README.md +0 -15
  1062. package/ref-monty/examples/web_scraper/browser.py +0 -56
  1063. package/ref-monty/examples/web_scraper/example_code.py +0 -59
  1064. package/ref-monty/examples/web_scraper/external_functions.py +0 -324
  1065. package/ref-monty/examples/web_scraper/main.py +0 -193
  1066. package/ref-monty/examples/web_scraper/sub_agent.py +0 -79
  1067. package/ref-monty/monty-npm.md +0 -235
  1068. package/ref-monty/pyproject.toml +0 -162
  1069. package/ref-monty/scripts/check_imports.py +0 -91
  1070. package/ref-monty/scripts/codecov_diff.py +0 -412
  1071. package/ref-monty/scripts/complete_tests.py +0 -146
  1072. package/ref-monty/scripts/flamegraph_to_text.py +0 -208
  1073. package/ref-monty/scripts/iter_test_methods.py +0 -540
  1074. package/ref-monty/scripts/run_traceback.py +0 -180
  1075. package/ref-monty/scripts/startup_performance.py +0 -130
  1076. package/ref-monty/uv.lock +0 -1779
  1077. package/temp_resend_cli/repo/.github/scripts/pr-title-check.js +0 -34
  1078. package/temp_resend_cli/repo/.github/workflows/ci.yml +0 -67
  1079. package/temp_resend_cli/repo/.github/workflows/post-release.yml +0 -51
  1080. package/temp_resend_cli/repo/.github/workflows/pr-title-check.yml +0 -13
  1081. package/temp_resend_cli/repo/.github/workflows/release.yml +0 -175
  1082. package/temp_resend_cli/repo/.github/workflows/test-install-unix.yml +0 -34
  1083. package/temp_resend_cli/repo/.github/workflows/test-install-windows.yml +0 -48
  1084. package/temp_resend_cli/repo/CHANGELOG.md +0 -31
  1085. package/temp_resend_cli/repo/LICENSE +0 -21
  1086. package/temp_resend_cli/repo/README.md +0 -450
  1087. package/temp_resend_cli/repo/biome.json +0 -36
  1088. package/temp_resend_cli/repo/install.ps1 +0 -141
  1089. package/temp_resend_cli/repo/install.sh +0 -301
  1090. package/temp_resend_cli/repo/package.json +0 -61
  1091. package/temp_resend_cli/repo/pnpm-lock.yaml +0 -2439
  1092. package/temp_resend_cli/repo/renovate.json +0 -4
  1093. package/temp_resend_cli/repo/src/cli.ts +0 -98
  1094. package/temp_resend_cli/repo/src/commands/api-keys/create.ts +0 -114
  1095. package/temp_resend_cli/repo/src/commands/api-keys/delete.ts +0 -47
  1096. package/temp_resend_cli/repo/src/commands/api-keys/index.ts +0 -26
  1097. package/temp_resend_cli/repo/src/commands/api-keys/list.ts +0 -35
  1098. package/temp_resend_cli/repo/src/commands/api-keys/utils.ts +0 -8
  1099. package/temp_resend_cli/repo/src/commands/auth/index.ts +0 -20
  1100. package/temp_resend_cli/repo/src/commands/auth/login.ts +0 -234
  1101. package/temp_resend_cli/repo/src/commands/auth/logout.ts +0 -105
  1102. package/temp_resend_cli/repo/src/commands/broadcasts/create.ts +0 -196
  1103. package/temp_resend_cli/repo/src/commands/broadcasts/delete.ts +0 -46
  1104. package/temp_resend_cli/repo/src/commands/broadcasts/get.ts +0 -59
  1105. package/temp_resend_cli/repo/src/commands/broadcasts/index.ts +0 -43
  1106. package/temp_resend_cli/repo/src/commands/broadcasts/list.ts +0 -60
  1107. package/temp_resend_cli/repo/src/commands/broadcasts/send.ts +0 -56
  1108. package/temp_resend_cli/repo/src/commands/broadcasts/update.ts +0 -95
  1109. package/temp_resend_cli/repo/src/commands/broadcasts/utils.ts +0 -35
  1110. package/temp_resend_cli/repo/src/commands/contact-properties/create.ts +0 -118
  1111. package/temp_resend_cli/repo/src/commands/contact-properties/delete.ts +0 -48
  1112. package/temp_resend_cli/repo/src/commands/contact-properties/get.ts +0 -46
  1113. package/temp_resend_cli/repo/src/commands/contact-properties/index.ts +0 -48
  1114. package/temp_resend_cli/repo/src/commands/contact-properties/list.ts +0 -68
  1115. package/temp_resend_cli/repo/src/commands/contact-properties/update.ts +0 -88
  1116. package/temp_resend_cli/repo/src/commands/contact-properties/utils.ts +0 -17
  1117. package/temp_resend_cli/repo/src/commands/contacts/add-segment.ts +0 -78
  1118. package/temp_resend_cli/repo/src/commands/contacts/create.ts +0 -122
  1119. package/temp_resend_cli/repo/src/commands/contacts/delete.ts +0 -49
  1120. package/temp_resend_cli/repo/src/commands/contacts/get.ts +0 -53
  1121. package/temp_resend_cli/repo/src/commands/contacts/index.ts +0 -58
  1122. package/temp_resend_cli/repo/src/commands/contacts/list.ts +0 -57
  1123. package/temp_resend_cli/repo/src/commands/contacts/remove-segment.ts +0 -48
  1124. package/temp_resend_cli/repo/src/commands/contacts/segments.ts +0 -39
  1125. package/temp_resend_cli/repo/src/commands/contacts/topics.ts +0 -45
  1126. package/temp_resend_cli/repo/src/commands/contacts/update-topics.ts +0 -90
  1127. package/temp_resend_cli/repo/src/commands/contacts/update.ts +0 -77
  1128. package/temp_resend_cli/repo/src/commands/contacts/utils.ts +0 -119
  1129. package/temp_resend_cli/repo/src/commands/doctor.ts +0 -216
  1130. package/temp_resend_cli/repo/src/commands/domains/create.ts +0 -83
  1131. package/temp_resend_cli/repo/src/commands/domains/delete.ts +0 -42
  1132. package/temp_resend_cli/repo/src/commands/domains/get.ts +0 -47
  1133. package/temp_resend_cli/repo/src/commands/domains/index.ts +0 -35
  1134. package/temp_resend_cli/repo/src/commands/domains/list.ts +0 -53
  1135. package/temp_resend_cli/repo/src/commands/domains/update.ts +0 -75
  1136. package/temp_resend_cli/repo/src/commands/domains/utils.ts +0 -44
  1137. package/temp_resend_cli/repo/src/commands/domains/verify.ts +0 -38
  1138. package/temp_resend_cli/repo/src/commands/emails/batch.ts +0 -140
  1139. package/temp_resend_cli/repo/src/commands/emails/get.ts +0 -44
  1140. package/temp_resend_cli/repo/src/commands/emails/index.ts +0 -30
  1141. package/temp_resend_cli/repo/src/commands/emails/list.ts +0 -84
  1142. package/temp_resend_cli/repo/src/commands/emails/receiving/attachment.ts +0 -55
  1143. package/temp_resend_cli/repo/src/commands/emails/receiving/attachments.ts +0 -68
  1144. package/temp_resend_cli/repo/src/commands/emails/receiving/get.ts +0 -58
  1145. package/temp_resend_cli/repo/src/commands/emails/receiving/index.ts +0 -28
  1146. package/temp_resend_cli/repo/src/commands/emails/receiving/list.ts +0 -59
  1147. package/temp_resend_cli/repo/src/commands/emails/receiving/utils.ts +0 -38
  1148. package/temp_resend_cli/repo/src/commands/emails/send.ts +0 -189
  1149. package/temp_resend_cli/repo/src/commands/open.ts +0 -27
  1150. package/temp_resend_cli/repo/src/commands/segments/create.ts +0 -50
  1151. package/temp_resend_cli/repo/src/commands/segments/delete.ts +0 -47
  1152. package/temp_resend_cli/repo/src/commands/segments/get.ts +0 -38
  1153. package/temp_resend_cli/repo/src/commands/segments/index.ts +0 -36
  1154. package/temp_resend_cli/repo/src/commands/segments/list.ts +0 -58
  1155. package/temp_resend_cli/repo/src/commands/segments/utils.ts +0 -7
  1156. package/temp_resend_cli/repo/src/commands/teams/index.ts +0 -10
  1157. package/temp_resend_cli/repo/src/commands/teams/list.ts +0 -35
  1158. package/temp_resend_cli/repo/src/commands/teams/remove.ts +0 -86
  1159. package/temp_resend_cli/repo/src/commands/teams/switch.ts +0 -76
  1160. package/temp_resend_cli/repo/src/commands/topics/create.ts +0 -73
  1161. package/temp_resend_cli/repo/src/commands/topics/delete.ts +0 -47
  1162. package/temp_resend_cli/repo/src/commands/topics/get.ts +0 -42
  1163. package/temp_resend_cli/repo/src/commands/topics/index.ts +0 -42
  1164. package/temp_resend_cli/repo/src/commands/topics/list.ts +0 -34
  1165. package/temp_resend_cli/repo/src/commands/topics/update.ts +0 -59
  1166. package/temp_resend_cli/repo/src/commands/topics/utils.ts +0 -16
  1167. package/temp_resend_cli/repo/src/commands/webhooks/create.ts +0 -128
  1168. package/temp_resend_cli/repo/src/commands/webhooks/delete.ts +0 -49
  1169. package/temp_resend_cli/repo/src/commands/webhooks/get.ts +0 -42
  1170. package/temp_resend_cli/repo/src/commands/webhooks/index.ts +0 -42
  1171. package/temp_resend_cli/repo/src/commands/webhooks/list.ts +0 -55
  1172. package/temp_resend_cli/repo/src/commands/webhooks/listen.ts +0 -379
  1173. package/temp_resend_cli/repo/src/commands/webhooks/update.ts +0 -83
  1174. package/temp_resend_cli/repo/src/commands/webhooks/utils.ts +0 -36
  1175. package/temp_resend_cli/repo/src/commands/whoami.ts +0 -71
  1176. package/temp_resend_cli/repo/src/lib/actions.ts +0 -157
  1177. package/temp_resend_cli/repo/src/lib/client.ts +0 -37
  1178. package/temp_resend_cli/repo/src/lib/config.ts +0 -217
  1179. package/temp_resend_cli/repo/src/lib/files.ts +0 -15
  1180. package/temp_resend_cli/repo/src/lib/help-text.ts +0 -38
  1181. package/temp_resend_cli/repo/src/lib/output.ts +0 -56
  1182. package/temp_resend_cli/repo/src/lib/pagination.ts +0 -36
  1183. package/temp_resend_cli/repo/src/lib/prompts.ts +0 -149
  1184. package/temp_resend_cli/repo/src/lib/spinner.ts +0 -100
  1185. package/temp_resend_cli/repo/src/lib/table.ts +0 -57
  1186. package/temp_resend_cli/repo/src/lib/tty.ts +0 -28
  1187. package/temp_resend_cli/repo/src/lib/update-check.ts +0 -169
  1188. package/temp_resend_cli/repo/src/lib/version.ts +0 -4
  1189. package/temp_resend_cli/repo/tests/commands/api-keys/create.test.ts +0 -196
  1190. package/temp_resend_cli/repo/tests/commands/api-keys/delete.test.ts +0 -157
  1191. package/temp_resend_cli/repo/tests/commands/api-keys/list.test.ts +0 -134
  1192. package/temp_resend_cli/repo/tests/commands/auth/login.test.ts +0 -153
  1193. package/temp_resend_cli/repo/tests/commands/auth/logout.test.ts +0 -153
  1194. package/temp_resend_cli/repo/tests/commands/broadcasts/create.test.ts +0 -454
  1195. package/temp_resend_cli/repo/tests/commands/broadcasts/delete.test.ts +0 -183
  1196. package/temp_resend_cli/repo/tests/commands/broadcasts/get.test.ts +0 -147
  1197. package/temp_resend_cli/repo/tests/commands/broadcasts/list.test.ts +0 -199
  1198. package/temp_resend_cli/repo/tests/commands/broadcasts/send.test.ts +0 -162
  1199. package/temp_resend_cli/repo/tests/commands/broadcasts/update.test.ts +0 -288
  1200. package/temp_resend_cli/repo/tests/commands/contact-properties/create.test.ts +0 -251
  1201. package/temp_resend_cli/repo/tests/commands/contact-properties/delete.test.ts +0 -184
  1202. package/temp_resend_cli/repo/tests/commands/contact-properties/get.test.ts +0 -145
  1203. package/temp_resend_cli/repo/tests/commands/contact-properties/list.test.ts +0 -181
  1204. package/temp_resend_cli/repo/tests/commands/contact-properties/update.test.ts +0 -217
  1205. package/temp_resend_cli/repo/tests/commands/contacts/add-segment.test.ts +0 -189
  1206. package/temp_resend_cli/repo/tests/commands/contacts/create.test.ts +0 -271
  1207. package/temp_resend_cli/repo/tests/commands/contacts/delete.test.ts +0 -193
  1208. package/temp_resend_cli/repo/tests/commands/contacts/get.test.ts +0 -149
  1209. package/temp_resend_cli/repo/tests/commands/contacts/list.test.ts +0 -176
  1210. package/temp_resend_cli/repo/tests/commands/contacts/remove-segment.test.ts +0 -167
  1211. package/temp_resend_cli/repo/tests/commands/contacts/segments.test.ts +0 -168
  1212. package/temp_resend_cli/repo/tests/commands/contacts/topics.test.ts +0 -164
  1213. package/temp_resend_cli/repo/tests/commands/contacts/update-topics.test.ts +0 -248
  1214. package/temp_resend_cli/repo/tests/commands/contacts/update.test.ts +0 -206
  1215. package/temp_resend_cli/repo/tests/commands/doctor.test.ts +0 -164
  1216. package/temp_resend_cli/repo/tests/commands/domains/create.test.ts +0 -193
  1217. package/temp_resend_cli/repo/tests/commands/domains/delete.test.ts +0 -157
  1218. package/temp_resend_cli/repo/tests/commands/domains/get.test.ts +0 -138
  1219. package/temp_resend_cli/repo/tests/commands/domains/list.test.ts +0 -165
  1220. package/temp_resend_cli/repo/tests/commands/domains/update.test.ts +0 -224
  1221. package/temp_resend_cli/repo/tests/commands/domains/verify.test.ts +0 -118
  1222. package/temp_resend_cli/repo/tests/commands/emails/batch.test.ts +0 -324
  1223. package/temp_resend_cli/repo/tests/commands/emails/get.test.ts +0 -132
  1224. package/temp_resend_cli/repo/tests/commands/emails/receiving/attachment.test.ts +0 -141
  1225. package/temp_resend_cli/repo/tests/commands/emails/receiving/attachments.test.ts +0 -169
  1226. package/temp_resend_cli/repo/tests/commands/emails/receiving/get.test.ts +0 -141
  1227. package/temp_resend_cli/repo/tests/commands/emails/receiving/list.test.ts +0 -182
  1228. package/temp_resend_cli/repo/tests/commands/emails/send.test.ts +0 -312
  1229. package/temp_resend_cli/repo/tests/commands/segments/create.test.ts +0 -164
  1230. package/temp_resend_cli/repo/tests/commands/segments/delete.test.ts +0 -183
  1231. package/temp_resend_cli/repo/tests/commands/segments/get.test.ts +0 -138
  1232. package/temp_resend_cli/repo/tests/commands/segments/list.test.ts +0 -174
  1233. package/temp_resend_cli/repo/tests/commands/teams/list.test.ts +0 -62
  1234. package/temp_resend_cli/repo/tests/commands/teams/remove.test.ts +0 -110
  1235. package/temp_resend_cli/repo/tests/commands/teams/switch.test.ts +0 -103
  1236. package/temp_resend_cli/repo/tests/commands/topics/create.test.ts +0 -192
  1237. package/temp_resend_cli/repo/tests/commands/topics/delete.test.ts +0 -157
  1238. package/temp_resend_cli/repo/tests/commands/topics/get.test.ts +0 -126
  1239. package/temp_resend_cli/repo/tests/commands/topics/list.test.ts +0 -125
  1240. package/temp_resend_cli/repo/tests/commands/topics/update.test.ts +0 -178
  1241. package/temp_resend_cli/repo/tests/commands/webhooks/create.test.ts +0 -225
  1242. package/temp_resend_cli/repo/tests/commands/webhooks/delete.test.ts +0 -157
  1243. package/temp_resend_cli/repo/tests/commands/webhooks/get.test.ts +0 -126
  1244. package/temp_resend_cli/repo/tests/commands/webhooks/list.test.ts +0 -178
  1245. package/temp_resend_cli/repo/tests/commands/webhooks/update.test.ts +0 -207
  1246. package/temp_resend_cli/repo/tests/commands/whoami.test.ts +0 -98
  1247. package/temp_resend_cli/repo/tests/e2e/smoke.test.ts +0 -93
  1248. package/temp_resend_cli/repo/tests/helpers.ts +0 -86
  1249. package/temp_resend_cli/repo/tests/lib/client.test.ts +0 -71
  1250. package/temp_resend_cli/repo/tests/lib/config.test.ts +0 -451
  1251. package/temp_resend_cli/repo/tests/lib/files.test.ts +0 -73
  1252. package/temp_resend_cli/repo/tests/lib/help-text.test.ts +0 -97
  1253. package/temp_resend_cli/repo/tests/lib/output.test.ts +0 -136
  1254. package/temp_resend_cli/repo/tests/lib/prompts.test.ts +0 -185
  1255. package/temp_resend_cli/repo/tests/lib/spinner.test.ts +0 -166
  1256. package/temp_resend_cli/repo/tests/lib/table.test.ts +0 -63
  1257. package/temp_resend_cli/repo/tests/lib/tty.test.ts +0 -89
  1258. package/temp_resend_cli/repo/tests/lib/update-check.test.ts +0 -179
  1259. package/temp_resend_cli/repo/tsconfig.json +0 -14
  1260. package/temp_resend_cli/repo/vitest.config.e2e.ts +0 -8
  1261. package/temp_resend_cli/repo/vitest.config.ts +0 -10
  1262. /package/docs/{plugin-examples.md → plugins-examples.md} +0 -0
@@ -1,1826 +0,0 @@
1
- /// Tests for resource limits and garbage collection.
2
- ///
3
- /// These tests verify that the `ResourceTracker` system correctly enforces
4
- /// allocation limits, time limits, and triggers garbage collection.
5
- use std::time::{Duration, Instant};
6
-
7
- use monty::{
8
- ExcType, LimitedTracker, MontyObject, MontyRun, NameLookupResult, PrintWriter, ResourceLimits, RunProgress,
9
- };
10
-
11
- /// Resolves consecutive `NameLookup` yields by providing a `Function` object for each name.
12
- ///
13
- /// External functions are no longer declared upfront. Instead, the VM yields `NameLookup`
14
- /// when it encounters an unresolved name. This helper resolves all such lookups until
15
- /// a different progress variant is reached.
16
- fn resolve_name_lookups<T: monty::ResourceTracker>(
17
- mut progress: RunProgress<T>,
18
- ) -> Result<RunProgress<T>, monty::MontyException> {
19
- while let RunProgress::NameLookup(lookup) = progress {
20
- let name = lookup.name.clone();
21
- progress = lookup.resume(
22
- NameLookupResult::Value(MontyObject::Function { name, docstring: None }),
23
- PrintWriter::Stdout,
24
- )?;
25
- }
26
- Ok(progress)
27
- }
28
-
29
- /// Test that GC properly collects dict cycles via the has_refs() check in allocate().
30
- ///
31
- /// This test creates cycles using dict literals and dict setitem. Dict setitem
32
- /// does NOT call mark_potential_cycle(), so the ONLY way may_have_cycles gets
33
- /// set is through the has_refs() check when allocating a dict with refs.
34
- ///
35
- /// If has_refs() is disabled, this test will FAIL because GC never runs.
36
- #[test]
37
- #[cfg(feature = "ref-count-return")]
38
- fn gc_collects_dict_cycles_via_has_refs() {
39
- // Create 200,001 dict cycles. Each iteration:
40
- // - Creates empty dict d1
41
- // - Creates dict d2 = {'ref': d1} - d2 is allocated WITH a ref to d1
42
- // This triggers has_refs() which sets may_have_cycles = true
43
- // - Sets d1['ref'] = d2 - creates cycle d1 <-> d2
44
- // Dict setitem does NOT call mark_potential_cycle()
45
- // - On next iteration, both dicts are reassigned, making the cycle unreachable
46
- //
47
- // GC runs every 100,000 allocations. With 200,001 iterations:
48
- // - GC runs at 100k (collects cycles 0-49,999 approximately)
49
- // - GC runs at 200k (collects more cycles)
50
- // After GC runs, only the final cycle should remain.
51
- let code = r"
52
- # Create many dict cycles
53
- for i in range(200001):
54
- d1 = {}
55
- d2 = {'ref': d1} # d2 allocated WITH ref - has_refs() must trigger here
56
- d1['ref'] = d2 # Cycle formed - dict setitem does NOT call mark_potential_cycle
57
-
58
- # Create final result (not a cycle)
59
- result = 'done'
60
- result
61
- ";
62
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
63
-
64
- let output = ex.run_ref_counts(vec![]).expect("should succeed");
65
-
66
- // GC_INTERVAL is 100,000. With 200,001 iterations creating dict cycles,
67
- // GC must have run at least once, resetting allocations_since_gc.
68
- // If may_have_cycles was never set (has_refs() disabled), GC never runs
69
- // and allocations_since_gc would be ~400k (2 dicts per iteration).
70
- assert!(
71
- output.allocations_since_gc < 100_000,
72
- "GC should have run (has_refs() must set may_have_cycles): allocations_since_gc = {}",
73
- output.allocations_since_gc
74
- );
75
-
76
- // Verify that GC collected most cycles.
77
- // If GC failed to collect cycles, heap_count would be >> 400k.
78
- // We allow a small number of extra objects for implementation details.
79
- assert!(
80
- output.heap_count < 20,
81
- "GC should collect most unreachable dict cycles: {} heap objects (expected < 20)",
82
- output.heap_count
83
- );
84
- }
85
-
86
- /// Test that GC properly collects self-referencing list cycles.
87
- ///
88
- /// This test creates cycles using list.append(), which calls mark_potential_cycle().
89
- /// This tests the mutation-based cycle detection path.
90
- #[test]
91
- #[cfg(feature = "ref-count-return")]
92
- fn gc_collects_list_cycles() {
93
- // Create 200,001 self-referencing list cycles. Each iteration:
94
- // - Creates empty list `a`
95
- // - Appends `a` to itself (creating a self-reference cycle)
96
- // This calls mark_potential_cycle() and sets may_have_cycles = true
97
- // - On next iteration, `a` is reassigned, making the cycle unreachable
98
- //
99
- // GC runs every 100,000 allocations. With 200,001 iterations:
100
- // - GC runs at 100k (collects cycles 0-99,999)
101
- // - GC runs at 200k (collects cycles 100k-199,999)
102
- // After GC runs, only the final cycle should remain.
103
- let code = r"
104
- # Create many self-referencing list cycles
105
- for i in range(200001):
106
- a = []
107
- a.append(a) # Creates cycle via list.append() which calls mark_potential_cycle()
108
-
109
- # Create final result (not a cycle)
110
- result = [1, 2, 3]
111
- len(result)
112
- ";
113
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
114
-
115
- let output = ex.run_ref_counts(vec![]).expect("should succeed");
116
-
117
- // GC_INTERVAL is 100,000. With 200,001 iterations creating list cycles,
118
- // GC must have run at least twice, resetting allocations_since_gc.
119
- assert!(
120
- output.allocations_since_gc < 100_000,
121
- "GC should have run: allocations_since_gc = {}",
122
- output.allocations_since_gc
123
- );
124
-
125
- // Verify that GC collected most cycles.
126
- // If GC failed to collect cycles, heap_count would be >> 200k.
127
- assert!(
128
- output.heap_count < 20,
129
- "GC should collect most unreachable list cycles: {} heap objects (expected < 20)",
130
- output.heap_count
131
- );
132
-
133
- // Verify expected ref counts
134
- // `a` is the last self-referencing list (refcount 2: variable + self-reference)
135
- // `result` is a simple list (refcount 1: just the variable)
136
- assert_eq!(
137
- output.counts.get("a"),
138
- Some(&2),
139
- "self-referencing list should have refcount 2"
140
- );
141
- assert_eq!(
142
- output.counts.get("result"),
143
- Some(&1),
144
- "result list should have refcount 1"
145
- );
146
- }
147
-
148
- /// Test that allocation limits return an error.
149
- #[test]
150
- fn allocation_limit_exceeded() {
151
- // Use multi-character strings to ensure heap allocation (single ASCII chars are interned)
152
- let code = r"
153
- result = []
154
- for i in range(100, 115):
155
- result.append(str(i))
156
- result
157
- ";
158
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
159
-
160
- let limits = ResourceLimits::new().max_allocations(4);
161
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
162
-
163
- // Should fail due to allocation limit
164
- assert!(result.is_err(), "should exceed allocation limit");
165
- let exc = result.unwrap_err();
166
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
167
- assert!(
168
- exc.message().is_some_and(|m| m.contains("allocation limit exceeded")),
169
- "expected allocation limit error, got: {exc}"
170
- );
171
- }
172
-
173
- #[test]
174
- fn allocation_limit_not_exceeded() {
175
- // Single-digit strings are interned (no allocation), so this uses minimal heap
176
- let code = r"
177
- result = []
178
- for i in range(9):
179
- result.append(str(i))
180
- result
181
- ";
182
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
183
-
184
- // Allocations: list (1) + range (1) + iterator (1) = 3
185
- // Note: str(0)...str(8) are single ASCII chars, so they use pre-interned strings
186
- let limits = ResourceLimits::new().max_allocations(5);
187
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
188
-
189
- // Should succeed
190
- assert!(result.is_ok(), "should not exceed allocation limit");
191
- }
192
-
193
- #[test]
194
- fn time_limit_exceeded() {
195
- // Create a long-running loop using for + range (while isn't implemented yet)
196
- // Use a very large range to ensure it runs long enough to hit the time limit
197
- let code = r"
198
- x = 0
199
- for i in range(100000000):
200
- x = x + 1
201
- x
202
- ";
203
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
204
-
205
- // Set a short time limit
206
- let limits = ResourceLimits::new().max_duration(Duration::from_millis(50));
207
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
208
-
209
- // Should fail due to time limit
210
- assert!(result.is_err(), "should exceed time limit");
211
- let exc = result.unwrap_err();
212
- assert_eq!(exc.exc_type(), ExcType::TimeoutError);
213
- assert!(
214
- exc.message().is_some_and(|m| m.contains("time limit exceeded")),
215
- "expected time limit error, got: {exc}"
216
- );
217
- }
218
-
219
- #[test]
220
- fn time_limit_not_exceeded() {
221
- // Simple code that runs quickly
222
- let code = "x = 1 + 2\nx";
223
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
224
-
225
- // Set a generous time limit
226
- let limits = ResourceLimits::new().max_duration(Duration::from_secs(5));
227
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
228
-
229
- // Should succeed
230
- assert!(result.is_ok(), "should not exceed time limit");
231
- }
232
-
233
- /// Test that memory limits return an error.
234
- #[test]
235
- fn memory_limit_exceeded() {
236
- // Create code that builds up memory using lists
237
- // Each iteration creates a new list that gets appended
238
- let code = r"
239
- result = []
240
- for i in range(100):
241
- result.append([1, 2, 3, 4, 5])
242
- result
243
- ";
244
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
245
-
246
- // Set a very low memory limit (100 bytes) to trigger on nested list allocation
247
- let limits = ResourceLimits::new().max_memory(100);
248
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
249
-
250
- // Should fail due to memory limit
251
- assert!(result.is_err(), "should exceed memory limit");
252
- let exc = result.unwrap_err();
253
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
254
- assert!(
255
- exc.message().is_some_and(|m| m.contains("memory limit exceeded")),
256
- "expected memory limit error, got: {exc}"
257
- );
258
- }
259
-
260
- #[test]
261
- fn combined_limits() {
262
- // Test multiple limits together
263
- let code = "x = 1 + 2\nx";
264
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
265
-
266
- let limits = ResourceLimits::new()
267
- .max_allocations(1000)
268
- .max_duration(Duration::from_secs(5))
269
- .max_memory(1024 * 1024);
270
-
271
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
272
- assert!(result.is_ok(), "should succeed with generous limits");
273
- }
274
-
275
- #[test]
276
- fn run_without_limits_succeeds() {
277
- // Verify that run() still works (no limits)
278
- let code = r"
279
- result = []
280
- for i in range(100):
281
- result.append(str(i))
282
- len(result)
283
- ";
284
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
285
-
286
- // Standard run should succeed
287
- let result = ex.run_no_limits(vec![]);
288
- assert!(result.is_ok(), "standard run should succeed");
289
- }
290
-
291
- #[test]
292
- fn gc_interval_triggers_collection() {
293
- // This test verifies that GC can run without crashing
294
- // We can't easily verify that GC actually collected anything without
295
- // adding more introspection, but we can verify it runs
296
- let code = r"
297
- result = []
298
- for i in range(100):
299
- temp = [1, 2, 3]
300
- result.append(i)
301
- len(result)
302
- ";
303
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
304
-
305
- // Set GC to run every 10 allocations
306
- let limits = ResourceLimits::new().gc_interval(10);
307
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
308
-
309
- assert!(result.is_ok(), "should succeed with GC enabled");
310
- }
311
-
312
- #[test]
313
- #[cfg_attr(
314
- feature = "ref-count-panic",
315
- ignore = "resource exhaustion doesn't guarantee heap state consistency"
316
- )]
317
- fn executor_iter_resource_limit_on_resume() {
318
- // Test that resource limits are enforced across function calls
319
- // First function call succeeds, but resumed execution exceeds limit
320
-
321
- // f-string to create multi-char strings (not interned)
322
- let code = "foo(1)\nx = []\nfor i in range(10):\n x.append(f'x{i}')\nlen(x)";
323
- let run = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
324
-
325
- // First function call should succeed with generous limit
326
- let limits = ResourceLimits::new().max_allocations(5);
327
- let progress = run
328
- .start(vec![], LimitedTracker::new(limits), PrintWriter::Stdout)
329
- .unwrap();
330
- let call = resolve_name_lookups(progress)
331
- .unwrap()
332
- .into_function_call()
333
- .expect("function call");
334
- assert_eq!(call.function_name, "foo");
335
- assert_eq!(call.args, vec![MontyObject::Int(1)]);
336
-
337
- // Resume - should fail due to allocation limit during the for loop
338
- let result = call.resume(MontyObject::None, PrintWriter::Stdout);
339
- assert!(result.is_err(), "should exceed allocation limit on resume");
340
- let exc = result.unwrap_err();
341
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
342
- assert!(
343
- exc.message().is_some_and(|m| m.contains("allocation limit exceeded")),
344
- "expected allocation limit error, got: {exc}"
345
- );
346
- }
347
-
348
- #[test]
349
- #[cfg_attr(
350
- feature = "ref-count-panic",
351
- ignore = "resource exhaustion doesn't guarantee heap state consistency"
352
- )]
353
- fn executor_iter_resource_limit_before_function_call() {
354
- // Test that resource limits are enforced before first function call
355
-
356
- // f-string to create multi-char strings (not interned)
357
- let code = "x = []\nfor i in range(10):\n x.append(f'x{i}')\nfoo(len(x))\n42";
358
- let run = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
359
-
360
- // Should fail before reaching the function call
361
- let limits = ResourceLimits::new().max_allocations(3);
362
- let result = run.start(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
363
-
364
- assert!(result.is_err(), "should exceed allocation limit before function call");
365
- let exc = result.unwrap_err();
366
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
367
- assert!(
368
- exc.message().is_some_and(|m| m.contains("allocation limit exceeded")),
369
- "expected allocation limit error, got: {exc}"
370
- );
371
- }
372
-
373
- #[test]
374
- #[cfg_attr(
375
- feature = "ref-count-panic",
376
- ignore = "resource exhaustion doesn't guarantee heap state consistency"
377
- )]
378
- fn char_f_string_not_allocated() {
379
- // Single character f-string interned not not allocated
380
-
381
- let code = "x = []\nfor i in range(10):\n x.append(f'{i}')";
382
- let run = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
383
-
384
- let limits = ResourceLimits::new().max_allocations(4);
385
- run.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout)
386
- .unwrap();
387
- }
388
-
389
- #[test]
390
- fn executor_iter_resource_limit_multiple_function_calls() {
391
- // Test resource limits across multiple function calls
392
- let code = "foo(1)\nbar(2)\nbaz(3)\n4";
393
- let run = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
394
-
395
- // Very tight allocation limit - should still work for simple function calls
396
- let limits = ResourceLimits::new().max_allocations(100);
397
-
398
- let progress = run
399
- .start(vec![], LimitedTracker::new(limits), PrintWriter::Stdout)
400
- .unwrap();
401
- let call = resolve_name_lookups(progress)
402
- .unwrap()
403
- .into_function_call()
404
- .expect("first call");
405
- assert_eq!(call.function_name, "foo");
406
- assert_eq!(call.args, vec![MontyObject::Int(1)]);
407
-
408
- let progress = call.resume(MontyObject::None, PrintWriter::Stdout).unwrap();
409
- let call = resolve_name_lookups(progress)
410
- .unwrap()
411
- .into_function_call()
412
- .expect("second call");
413
- assert_eq!(call.function_name, "bar");
414
- assert_eq!(call.args, vec![MontyObject::Int(2)]);
415
-
416
- let progress = call.resume(MontyObject::None, PrintWriter::Stdout).unwrap();
417
- let call = resolve_name_lookups(progress)
418
- .unwrap()
419
- .into_function_call()
420
- .expect("third call");
421
- assert_eq!(call.function_name, "baz");
422
- assert_eq!(call.args, vec![MontyObject::Int(3)]);
423
-
424
- let result = call
425
- .resume(MontyObject::None, PrintWriter::Stdout)
426
- .unwrap()
427
- .into_complete()
428
- .expect("complete");
429
- assert_eq!(result, MontyObject::Int(4));
430
- }
431
-
432
- /// Test that deep recursion triggers memory limit due to namespace tracking.
433
- ///
434
- /// Function call namespaces (local variables) are tracked by ResourceTracker.
435
- /// Each recursive call creates a new namespace, which should count against
436
- /// the memory limit.
437
- #[test]
438
- #[cfg_attr(
439
- feature = "ref-count-panic",
440
- ignore = "resource exhaustion doesn't guarantee heap state consistency"
441
- )]
442
- fn recursion_respects_memory_limit() {
443
- // Recursive function that creates stack frames with local variables
444
- let code = r"
445
- def recurse(n):
446
- x = 1
447
- if n > 0:
448
- return recurse(n - 1)
449
- return 0
450
- recurse(1000)
451
- ";
452
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
453
-
454
- // Very tight memory limit - should fail due to namespace memory
455
- // Each frame needs at least namespace_size * size_of::<Value>() bytes
456
- let limits = ResourceLimits::new().max_memory(1000);
457
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
458
-
459
- assert!(result.is_err(), "should exceed memory limit from recursion");
460
- let exc = result.unwrap_err();
461
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
462
- assert!(
463
- exc.message().is_some_and(|m| m.contains("memory limit exceeded")),
464
- "expected memory limit error, got: {exc}"
465
- );
466
- }
467
-
468
- /// Test that recursion depth limit returns an error.
469
- #[test]
470
- #[cfg_attr(
471
- feature = "ref-count-panic",
472
- ignore = "resource exhaustion doesn't guarantee heap state consistency"
473
- )]
474
- fn recursion_depth_limit_exceeded() {
475
- let code = r"
476
- def recurse(n):
477
- if n > 0:
478
- return recurse(n - 1)
479
- return 0
480
- recurse(100)
481
- ";
482
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
483
-
484
- // Set recursion limit to 10
485
- let limits = ResourceLimits::new().max_recursion_depth(Some(10));
486
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
487
-
488
- assert!(result.is_err(), "should exceed recursion depth limit");
489
- let exc = result.unwrap_err();
490
- assert_eq!(exc.exc_type(), ExcType::RecursionError);
491
- assert!(
492
- exc.message()
493
- .is_some_and(|m| m.contains("maximum recursion depth exceeded")),
494
- "expected recursion depth error, got: {exc}"
495
- );
496
- }
497
-
498
- #[test]
499
- fn recursion_depth_limit_not_exceeded() {
500
- let code = r"
501
- def recurse(n):
502
- if n > 0:
503
- return recurse(n - 1)
504
- return 0
505
- recurse(5)
506
- ";
507
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
508
-
509
- // Set recursion limit to 10 - should succeed with 5 levels
510
- let limits = ResourceLimits::new().max_recursion_depth(Some(10));
511
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
512
-
513
- assert!(result.is_ok(), "should not exceed recursion depth limit");
514
- }
515
-
516
- // === BigInt large result pre-check tests ===
517
- // These tests verify that operations that would produce very large BigInt results
518
- // are rejected before the computation begins, preventing DoS attacks.
519
-
520
- /// Test that large pow operations are rejected by memory limits.
521
- #[test]
522
- fn bigint_pow_memory_limit() {
523
- // 2 ** 10_000_000 would produce ~1.25MB result
524
- let code = "2 ** 10000000";
525
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
526
-
527
- // Set a 1MB memory limit - should fail before computing
528
- let limits = ResourceLimits::new().max_memory(1_000_000);
529
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
530
-
531
- assert!(result.is_err(), "large pow should exceed memory limit");
532
- let exc = result.unwrap_err();
533
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
534
- assert!(
535
- exc.message().is_some_and(|m| m.contains("memory limit exceeded")),
536
- "expected memory limit error, got: {exc}"
537
- );
538
- }
539
-
540
- /// Test that pow with huge exponents is rejected even when the size estimate overflows u64.
541
- ///
542
- /// This catches a bug where `estimate_pow_bytes` returned `None` on u64 overflow,
543
- /// and the `if let Some(estimated)` pattern silently skipped the check.
544
- #[test]
545
- fn pow_overflowing_estimate_rejected() {
546
- // base ~63 bits, exp ~62 bits: estimated result bits = 63 * 3962939411543162624 overflows u64
547
- let code = "-7234189268083315611 ** 3962939411543162624";
548
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
549
-
550
- let limits = ResourceLimits::new().max_memory(1_000_000);
551
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
552
-
553
- assert!(result.is_err(), "pow with overflowing estimate should be rejected");
554
- let exc = result.unwrap_err();
555
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
556
- assert!(
557
- exc.message().is_some_and(|m| m.contains("memory limit exceeded")),
558
- "expected memory limit error, got: {exc}"
559
- );
560
- }
561
-
562
- /// Test that pow with a large base and moderate exponent is rejected by memory limits.
563
- ///
564
- /// `-7234408281351689115 ** 65327` has a 63-bit base, so the result is ~63*65327 ≈ 4M bits ≈ 514KB.
565
- /// With a 100KB memory limit the pre-check should reject this before computing.
566
- #[test]
567
- fn pow_large_base_moderate_exp_rejected() {
568
- let code = "-7234408281351689115 ** 65327";
569
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
570
-
571
- let limits = ResourceLimits::new().max_memory(100_000);
572
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
573
-
574
- assert!(result.is_err(), "large pow should exceed memory limit");
575
- let exc = result.unwrap_err();
576
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
577
- assert!(
578
- exc.message().is_some_and(|m| m.contains("memory limit exceeded")),
579
- "expected memory limit error, got: {exc}"
580
- );
581
- }
582
-
583
- /// Test that the 4× safety multiplier for pow intermediate allocations catches
584
- /// cases where the final result fits but repeated-squaring intermediates don't.
585
- ///
586
- /// `2 ** 500000`: final result = 2 * 500000 bits = 125KB. Without multiplier this
587
- /// passes a 200KB limit. With 4× multiplier: 500KB > 200KB → rejected.
588
- #[test]
589
- fn pow_intermediate_allocation_multiplier() {
590
- let code = "2 ** 500000";
591
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
592
-
593
- // 200KB limit: final result (125KB) fits, but 4× estimate (500KB) exceeds it
594
- let limits = ResourceLimits::new().max_memory(200_000);
595
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
596
-
597
- assert!(
598
- result.is_err(),
599
- "pow should be rejected due to intermediate allocation overhead"
600
- );
601
- let exc = result.unwrap_err();
602
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
603
- // 2 bits * 500000 = 125KB final, × 4 = 500072 bytes (includes base memory offset)
604
- assert_eq!(
605
- exc.message(),
606
- Some("memory limit exceeded: 500072 bytes > 200000 bytes")
607
- );
608
- }
609
-
610
- /// Test that pow still succeeds when the 4× estimate is within the limit.
611
- ///
612
- /// `2 ** 100000`: final result = 2 * 100000 bits ≈ 25KB. With 4× multiplier: ~100KB.
613
- /// A 1MB limit should comfortably allow this.
614
- #[test]
615
- fn pow_within_limit_with_multiplier() {
616
- let code = "x = 2 ** 100000\nx > 0";
617
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
618
-
619
- let limits = ResourceLimits::new().max_memory(1_000_000);
620
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
621
-
622
- assert!(result.is_ok(), "pow with 4× estimate under limit should succeed");
623
- assert_eq!(result.unwrap(), MontyObject::Bool(true));
624
- }
625
-
626
- /// Test the exact fuzzer OOM pattern: right-associative chained exponentiation.
627
- ///
628
- /// `3 ** 3661666` is the first sub-expression of the fuzzer input
629
- /// `1666**3**366**3**3661666`. Since `**` is right-associative, `3**3661666`
630
- /// is computed first. Base 3 has 2 bits, so: 2 * 3661666 = 7323332 bits ≈ 915KB.
631
- /// With 4× multiplier: 3660KB > 1MB fuzz limit → rejected.
632
- #[test]
633
- fn pow_fuzzer_oom_chained_exponentiation() {
634
- // This is the subexpression that caused the fuzzer OOM
635
- let code = "3 ** 3661666";
636
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
637
-
638
- // 1MB limit (matching the fuzzer's resource limit)
639
- let limits = ResourceLimits::new().max_memory(1_024 * 1_024);
640
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
641
-
642
- assert!(
643
- result.is_err(),
644
- "fuzzer OOM pattern should be rejected by 4× multiplier"
645
- );
646
- let exc = result.unwrap_err();
647
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
648
- // 2 bits * 3661666 = 915KB final, × 4 = 3661740 bytes
649
- assert_eq!(
650
- exc.message(),
651
- Some("memory limit exceeded: 3661740 bytes > 1048576 bytes")
652
- );
653
- }
654
-
655
- /// Test the full fuzzer input that originally caused OOM.
656
- ///
657
- /// The input `1666**3**366**3**3661666` should be rejected before any large
658
- /// intermediate allocation occurs.
659
- #[test]
660
- fn pow_fuzzer_oom_full_input() {
661
- let code = "1666**3**366**3**3661666";
662
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
663
-
664
- let limits = ResourceLimits::new().max_memory(1_024 * 1_024);
665
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
666
-
667
- assert!(result.is_err(), "full fuzzer OOM input should be rejected");
668
- let exc = result.unwrap_err();
669
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
670
- // 3**3661666 is evaluated first (right-associative). Base 3 = 2 bits,
671
- // so estimate = 2 * 3661666 bits = 915KB. With 4× multiplier: 3661740 bytes > 1MB.
672
- assert_eq!(
673
- exc.message(),
674
- Some("memory limit exceeded: 3661740 bytes > 1048576 bytes")
675
- );
676
- }
677
-
678
- /// Test that large left shift operations are rejected by memory limits.
679
- #[test]
680
- fn bigint_lshift_memory_limit() {
681
- // 1 << 10_000_000 would produce ~1.25MB result
682
- let code = "1 << 10000000";
683
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
684
-
685
- // Set a 1MB memory limit - should fail before computing
686
- let limits = ResourceLimits::new().max_memory(1_000_000);
687
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
688
-
689
- assert!(result.is_err(), "large lshift should exceed memory limit");
690
- let exc = result.unwrap_err();
691
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
692
- assert!(
693
- exc.message().is_some_and(|m| m.contains("memory limit exceeded")),
694
- "expected memory limit error, got: {exc}"
695
- );
696
- }
697
-
698
- /// Test that large multiplication operations are rejected by memory limits.
699
- #[test]
700
- fn bigint_mult_memory_limit() {
701
- // (2**4_000_000) * (2**4_000_000) would produce ~1MB result
702
- let code = "big = 2 ** 4000000\nbig * big";
703
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
704
-
705
- // Set a 1MB memory limit - should fail before computing the multiplication
706
- let limits = ResourceLimits::new().max_memory(1_000_000);
707
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
708
-
709
- assert!(result.is_err(), "large mult should exceed memory limit");
710
- let exc = result.unwrap_err();
711
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
712
- assert!(
713
- exc.message().is_some_and(|m| m.contains("memory limit exceeded")),
714
- "expected memory limit error, got: {exc}"
715
- );
716
- }
717
-
718
- /// Test that small BigInt operations succeed within memory limits.
719
- #[test]
720
- fn bigint_small_operations_within_limit() {
721
- // 2 ** 1000 produces ~125 bytes - well under limit
722
- let code = "x = 2 ** 1000\ny = 1 << 1000\nz = x * 2\nx > 0 and y > 0 and z > 0";
723
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
724
-
725
- // Set a 1MB memory limit - should succeed
726
- let limits = ResourceLimits::new().max_memory(1_000_000);
727
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
728
-
729
- assert!(result.is_ok(), "small BigInt operations should succeed within limit");
730
- let val = result.unwrap();
731
- assert_eq!(val, MontyObject::Bool(true));
732
- }
733
-
734
- /// Test that edge cases (0, 1, -1) with huge exponents succeed even with limits.
735
- /// These produce constant-size results regardless of exponent.
736
- #[test]
737
- fn bigint_edge_cases_always_succeed() {
738
- // Test each edge case individually to minimize other allocations
739
- // These edge cases produce constant-size results regardless of exponent:
740
- // - 0 ** huge = 0
741
- // - 1 ** huge = 1
742
- // - (-1) ** huge = 1 or -1
743
- // - 0 << huge = 0
744
-
745
- // 1MB limit would reject 2**10000000 (~1.25MB) but allows edge cases
746
- let limits = ResourceLimits::new().max_memory(1_000_000);
747
-
748
- // 0 ** huge = 0
749
- let code = "0 ** 10000000";
750
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
751
- let result = ex.run(vec![], LimitedTracker::new(limits.clone()), PrintWriter::Stdout);
752
- assert!(result.is_ok(), "0 ** huge should succeed");
753
- assert_eq!(result.unwrap(), MontyObject::Int(0));
754
-
755
- // 1 ** huge = 1
756
- let code = "1 ** 10000000";
757
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
758
- let result = ex.run(vec![], LimitedTracker::new(limits.clone()), PrintWriter::Stdout);
759
- assert!(result.is_ok(), "1 ** huge should succeed");
760
- assert_eq!(result.unwrap(), MontyObject::Int(1));
761
-
762
- // (-1) ** huge_even = 1
763
- let code = "(-1) ** 10000000";
764
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
765
- let result = ex.run(vec![], LimitedTracker::new(limits.clone()), PrintWriter::Stdout);
766
- assert!(result.is_ok(), "(-1) ** huge_even should succeed");
767
- assert_eq!(result.unwrap(), MontyObject::Int(1));
768
-
769
- // (-1) ** huge_odd = -1
770
- let code = "(-1) ** 10000001";
771
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
772
- let result = ex.run(vec![], LimitedTracker::new(limits.clone()), PrintWriter::Stdout);
773
- assert!(result.is_ok(), "(-1) ** huge_odd should succeed");
774
- assert_eq!(result.unwrap(), MontyObject::Int(-1));
775
-
776
- // 0 << huge = 0
777
- let code = "0 << 10000000";
778
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
779
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
780
- assert!(result.is_ok(), "0 << huge should succeed");
781
- assert_eq!(result.unwrap(), MontyObject::Int(0));
782
- }
783
-
784
- /// Test that pow() builtin also respects memory limits.
785
- #[test]
786
- fn bigint_builtin_pow_memory_limit() {
787
- let code = "pow(2, 10000000)";
788
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
789
-
790
- let limits = ResourceLimits::new().max_memory(1_000_000);
791
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
792
-
793
- assert!(result.is_err(), "builtin pow should respect memory limit");
794
- let exc = result.unwrap_err();
795
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
796
- }
797
-
798
- /// Test that large BigInt operations are rejected BEFORE allocation via check_large_result.
799
- ///
800
- /// The pre-allocation size check estimates result size and rejects operations that would
801
- /// exceed the memory limit before any memory is actually consumed.
802
- #[test]
803
- fn bigint_rejected_before_allocation() {
804
- // 2**1000000: base 2 has 2 bits, so estimate = 2 * 1000000 bits = 250KB
805
- // With 4× safety multiplier for intermediate allocations = 1000KB
806
- // Set limit to 100KB - the pre-check should reject before allocating
807
- let code = "2 ** 1000000";
808
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
809
-
810
- let limits = ResourceLimits::new().max_memory(100_000); // 100KB limit
811
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
812
-
813
- assert!(result.is_err(), "should be rejected before allocation");
814
- let exc = result.unwrap_err();
815
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
816
- assert_eq!(
817
- exc.message(),
818
- Some("memory limit exceeded: 1000072 bytes > 100000 bytes")
819
- );
820
- }
821
-
822
- // === String/Bytes large result pre-check tests ===
823
- // These tests verify that string/bytes multiplication operations that would produce
824
- // very large results are rejected before the computation begins.
825
-
826
- /// Test that large string multiplication is rejected before allocation.
827
- #[test]
828
- fn string_mult_memory_limit() {
829
- // 'x' * 1000000 = 1MB string
830
- let code = "'x' * 1000000";
831
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
832
-
833
- let limits = ResourceLimits::new().max_memory(100_000); // 100KB limit
834
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
835
-
836
- assert!(result.is_err(), "large string mult should be rejected");
837
- let exc = result.unwrap_err();
838
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
839
- assert!(
840
- exc.message().is_some_and(|m| m.contains("memory limit exceeded")),
841
- "expected memory limit error, got: {exc}"
842
- );
843
- }
844
-
845
- /// Test that large bytes multiplication is rejected before allocation.
846
- #[test]
847
- fn bytes_mult_memory_limit() {
848
- // b'x' * 1000000 = 1MB bytes
849
- let code = "b'x' * 1000000";
850
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
851
-
852
- let limits = ResourceLimits::new().max_memory(100_000); // 100KB limit
853
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
854
-
855
- assert!(result.is_err(), "large bytes mult should be rejected");
856
- let exc = result.unwrap_err();
857
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
858
- assert!(
859
- exc.message().is_some_and(|m| m.contains("memory limit exceeded")),
860
- "expected memory limit error, got: {exc}"
861
- );
862
- }
863
-
864
- /// Test that small string multiplication works within limits.
865
- #[test]
866
- fn string_mult_within_limit() {
867
- // 'abc' * 100 = 300 bytes, well within 100KB limit
868
- let code = "'abc' * 100 == 'abc' * 100";
869
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
870
-
871
- let limits = ResourceLimits::new().max_memory(100_000);
872
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
873
-
874
- assert!(result.is_ok(), "small string mult should succeed");
875
- assert_eq!(result.unwrap(), MontyObject::Bool(true));
876
- }
877
-
878
- /// Test that small bytes multiplication works within limits.
879
- #[test]
880
- fn bytes_mult_within_limit() {
881
- // b'abc' * 100 = 300 bytes, well within 100KB limit
882
- let code = "b'abc' * 100 == b'abc' * 100";
883
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
884
-
885
- let limits = ResourceLimits::new().max_memory(100_000);
886
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
887
-
888
- assert!(result.is_ok(), "small bytes mult should succeed");
889
- assert_eq!(result.unwrap(), MontyObject::Bool(true));
890
- }
891
-
892
- /// Test that string multiplication is rejected before allocation via check_large_result.
893
- #[test]
894
- fn string_mult_rejected_before_allocation() {
895
- // 'x' * 200000 = 200KB string
896
- // Set limit to 100KB - the pre-check should reject before allocating
897
- let code = "'x' * 200000";
898
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
899
-
900
- let limits = ResourceLimits::new().max_memory(100_000); // 100KB limit
901
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
902
-
903
- assert!(result.is_err(), "should be rejected before allocation");
904
- let exc = result.unwrap_err();
905
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
906
- // The exact size may include some overhead, but should be around 200KB
907
- assert!(
908
- exc.message()
909
- .is_some_and(|m| m.contains("memory limit exceeded") && m.contains("> 100000 bytes")),
910
- "expected memory limit error with ~200KB size, got: {:?}",
911
- exc.message()
912
- );
913
- }
914
-
915
- /// Test that large list multiplication is rejected before allocation.
916
- #[test]
917
- fn list_mult_memory_limit() {
918
- // [1] * 10000 = 10,000 Values = ~160KB (at 16 bytes per Value)
919
- let code = "[1] * 10000";
920
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
921
-
922
- let limits = ResourceLimits::new().max_memory(100_000); // 100KB limit
923
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
924
-
925
- assert!(result.is_err(), "large list mult should be rejected");
926
- let exc = result.unwrap_err();
927
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
928
- assert!(
929
- exc.message().is_some_and(|m| m.contains("memory limit exceeded")),
930
- "expected memory limit error, got: {exc}"
931
- );
932
- }
933
-
934
- /// Test that large tuple multiplication is rejected before allocation.
935
- #[test]
936
- fn tuple_mult_memory_limit() {
937
- // (1,) * 10000 = 10,000 Values = ~160KB (at 16 bytes per Value)
938
- let code = "(1,) * 10000";
939
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
940
-
941
- let limits = ResourceLimits::new().max_memory(100_000); // 100KB limit
942
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
943
-
944
- assert!(result.is_err(), "large tuple mult should be rejected");
945
- let exc = result.unwrap_err();
946
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
947
- assert!(
948
- exc.message().is_some_and(|m| m.contains("memory limit exceeded")),
949
- "expected memory limit error, got: {exc}"
950
- );
951
- }
952
-
953
- /// Test that small list multiplication works within limits.
954
- #[test]
955
- fn list_mult_within_limit() {
956
- // [1, 2, 3] * 20 = 60 Values, well within 100KB limit
957
- let code = "[1, 2, 3] * 20 == [1, 2, 3] * 20";
958
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
959
-
960
- let limits = ResourceLimits::new().max_memory(100_000);
961
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
962
-
963
- assert!(result.is_ok(), "small list mult should succeed");
964
- assert_eq!(result.unwrap(), MontyObject::Bool(true));
965
- }
966
-
967
- /// Test that `int * bytes` (int on left) is also rejected by the pre-check.
968
- ///
969
- /// This catches a bug where interned bytes/strings bypassed the `mult_sequence`
970
- /// pre-check because `py_mult` handled `InternBytes * Int` inline without
971
- /// checking resource limits.
972
- #[test]
973
- fn int_times_bytes_memory_limit() {
974
- // int on left side: 1000000 * b'x' = 1MB
975
- let code = "1000000 * b'x'";
976
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
977
-
978
- let limits = ResourceLimits::new().max_memory(100_000); // 100KB limit
979
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
980
-
981
- assert!(result.is_err(), "int * bytes should be rejected");
982
- let exc = result.unwrap_err();
983
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
984
- assert!(
985
- exc.message().is_some_and(|m| m.contains("memory limit exceeded")),
986
- "expected memory limit error, got: {exc}"
987
- );
988
- }
989
-
990
- /// Test that `int * str` (int on left) is also rejected by the pre-check.
991
- #[test]
992
- fn int_times_string_memory_limit() {
993
- // int on left side: 1000000 * 'x' = 1MB
994
- let code = "1000000 * 'x'";
995
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
996
-
997
- let limits = ResourceLimits::new().max_memory(100_000); // 100KB limit
998
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
999
-
1000
- assert!(result.is_err(), "int * str should be rejected");
1001
- let exc = result.unwrap_err();
1002
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
1003
- assert!(
1004
- exc.message().is_some_and(|m| m.contains("memory limit exceeded")),
1005
- "expected memory limit error, got: {exc}"
1006
- );
1007
- }
1008
-
1009
- /// Test that `bigint * bytes` (LongInt on left) is rejected by the pre-check.
1010
- #[test]
1011
- fn longint_times_bytes_memory_limit() {
1012
- // i64::MAX + 1 = 9223372036854775808, which is a LongInt but fits in usize on 64-bit.
1013
- // Multiplied by 1-byte bytes literal, this would be ~9.2 exabytes.
1014
- let code = "9223372036854775808 * b'x'";
1015
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
1016
-
1017
- let limits = ResourceLimits::new().max_memory(100_000);
1018
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
1019
-
1020
- assert!(result.is_err(), "bigint * bytes should be rejected");
1021
- let exc = result.unwrap_err();
1022
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
1023
- assert!(
1024
- exc.message().is_some_and(|m| m.contains("memory limit exceeded")),
1025
- "expected memory limit error, got: {exc}"
1026
- );
1027
- }
1028
-
1029
- /// Test that `bigint * str` (LongInt on left) is rejected by the pre-check.
1030
- #[test]
1031
- fn longint_times_string_memory_limit() {
1032
- // i64::MAX + 1 = 9223372036854775808, which is a LongInt but fits in usize on 64-bit.
1033
- let code = "9223372036854775808 * 'x'";
1034
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
1035
-
1036
- let limits = ResourceLimits::new().max_memory(100_000);
1037
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
1038
-
1039
- assert!(result.is_err(), "bigint * str should be rejected");
1040
- let exc = result.unwrap_err();
1041
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
1042
- assert!(
1043
- exc.message().is_some_and(|m| m.contains("memory limit exceeded")),
1044
- "expected memory limit error, got: {exc}"
1045
- );
1046
- }
1047
-
1048
- /// Test that small tuple multiplication works within limits.
1049
- #[test]
1050
- fn tuple_mult_within_limit() {
1051
- // (1, 2, 3) * 20 = 60 Values, well within 100KB limit
1052
- let code = "(1, 2, 3) * 20 == (1, 2, 3) * 20";
1053
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
1054
-
1055
- let limits = ResourceLimits::new().max_memory(100_000);
1056
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
1057
-
1058
- assert!(result.is_ok(), "small tuple mult should succeed");
1059
- assert_eq!(result.unwrap(), MontyObject::Bool(true));
1060
- }
1061
-
1062
- // === Timeout enforcement in builtin iteration loops ===
1063
- // These tests verify that `max_duration_secs` is enforced inside Rust-side loops
1064
- // within builtin functions. Previously, builtins like sum(), sorted(), min(), max()
1065
- // ran Rust loops entirely within a single bytecode instruction, bypassing the VM's
1066
- // per-instruction timeout check. The fix adds `heap.check_time()` calls inside
1067
- // `MontyIter::for_next()` and other non-iterator loops.
1068
-
1069
- /// Helper: runs code with a short time limit and asserts it produces a TimeoutError promptly.
1070
- fn assert_timeout_in_builtin(code: &str, label: &str) {
1071
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
1072
-
1073
- let limits = ResourceLimits::new().max_duration(Duration::from_millis(100));
1074
- let start = std::time::Instant::now();
1075
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
1076
- let elapsed = start.elapsed();
1077
-
1078
- assert!(result.is_err(), "{label}: should exceed time limit");
1079
- let exc = result.unwrap_err();
1080
- assert_eq!(
1081
- exc.exc_type(),
1082
- ExcType::TimeoutError,
1083
- "{label}: expected TimeoutError, got: {exc}"
1084
- );
1085
- assert!(
1086
- elapsed < Duration::from_secs(2),
1087
- "{label}: should terminate promptly, took {elapsed:?}"
1088
- );
1089
- }
1090
-
1091
- /// Test that `sum(range(huge))` respects the time limit.
1092
- ///
1093
- /// `sum()` iterates via `for_next()` which now calls `heap.check_time()`.
1094
- #[test]
1095
- fn timeout_in_sum_builtin() {
1096
- assert_timeout_in_builtin("sum(range(10**18))", "sum(range(10**18))");
1097
- }
1098
-
1099
- /// Test that `list(range(huge))` respects the time limit.
1100
- ///
1101
- /// The `list()` constructor collects via `MontyIter::collect()` -> `for_next()`.
1102
- #[test]
1103
- fn timeout_in_list_constructor() {
1104
- assert_timeout_in_builtin("list(range(10**18))", "list(range(10**18))");
1105
- }
1106
-
1107
- /// Test that `sorted(range(huge))` respects the time limit.
1108
- ///
1109
- /// `sorted()` first collects items via `for_next()`, then sorts. The collection
1110
- /// phase alone should trigger the timeout for very large ranges.
1111
- #[test]
1112
- fn timeout_in_sorted_builtin() {
1113
- assert_timeout_in_builtin("sorted(range(10**18))", "sorted(range(10**18))");
1114
- }
1115
-
1116
- /// Test that `min(range(huge))` respects the time limit.
1117
- ///
1118
- /// `min()` with a single iterable argument iterates via `for_next()`.
1119
- #[test]
1120
- fn timeout_in_min_builtin() {
1121
- assert_timeout_in_builtin("min(range(10**18))", "min(range(10**18))");
1122
- }
1123
-
1124
- /// Test that `max(range(huge))` respects the time limit.
1125
- ///
1126
- /// `max()` with a single iterable argument iterates via `for_next()`.
1127
- #[test]
1128
- fn timeout_in_max_builtin() {
1129
- assert_timeout_in_builtin("max(range(10**18))", "max(range(10**18))");
1130
- }
1131
-
1132
- /// Test that `all(range(huge))` respects the time limit.
1133
- ///
1134
- /// `all()` iterates via `for_next()` and only short-circuits on falsy values.
1135
- /// `range(1, 10**18)` produces only truthy values so it keeps iterating.
1136
- #[test]
1137
- fn timeout_in_all_builtin() {
1138
- assert_timeout_in_builtin("all(range(1, 10**18))", "all(range(1, 10**18))");
1139
- }
1140
-
1141
- /// Test that `enumerate(range(huge))` iteration respects the time limit.
1142
- ///
1143
- /// `enumerate()` creates tuples on each iteration via `for_next()`.
1144
- #[test]
1145
- #[cfg_attr(
1146
- feature = "ref-count-panic",
1147
- ignore = "resource exhaustion doesn't guarantee heap state consistency"
1148
- )]
1149
- fn timeout_in_any_builtin() {
1150
- // range(0, 1) repeated via a for loop calling any on each chunk isn't ideal,
1151
- // but we can test with a large range starting from 0 where only first element is falsy
1152
- // Actually, any(range(10**18)) will return True immediately because range starts at 0
1153
- // which is falsy, but 1 is truthy. So any() returns True after checking 0, 1.
1154
- // Instead, we need a different approach - just use the for_next timeout via enumerate.
1155
- assert_timeout_in_builtin("list(enumerate(range(10**18)))", "enumerate(range(10**18))");
1156
- }
1157
-
1158
- /// Test that `tuple(range(huge))` respects the time limit.
1159
- ///
1160
- /// The `tuple()` constructor collects via `MontyIter::collect()` -> `for_next()`.
1161
- #[test]
1162
- fn timeout_in_tuple_constructor() {
1163
- assert_timeout_in_builtin("tuple(range(10**18))", "tuple(range(10**18))");
1164
- }
1165
-
1166
- /// Test that `' '.join(...)` iteration respects the time limit.
1167
- ///
1168
- /// `str.join()` collects items from the iterable via `for_next()`.
1169
- #[test]
1170
- fn timeout_in_str_join() {
1171
- assert_timeout_in_builtin("' '.join(str(i) for i in range(10**18))", "str.join with generator");
1172
- }
1173
-
1174
- /// Test that the insertion sort inner loop in `sorted()` respects the time limit.
1175
- ///
1176
- /// Uses reverse-sorted data to trigger worst-case O(n^2) insertion sort behavior.
1177
- /// The sort comparison loop has an explicit `heap.check_time()` call.
1178
- #[test]
1179
- #[cfg_attr(
1180
- feature = "ref-count-panic",
1181
- ignore = "resource exhaustion doesn't guarantee heap state consistency"
1182
- )]
1183
- fn timeout_in_sorted_comparison_loop() {
1184
- // Build a reverse-sorted list, then sort it. Insertion sort on reverse-sorted
1185
- // data is O(n^2).
1186
- let code = r"
1187
- x = list(range(10**6, 0, -1))
1188
- sorted(x)
1189
- ";
1190
- assert_timeout_in_builtin(code, "sorted(reversed list)");
1191
- }
1192
-
1193
- /// Test that `[1] * 10_000_000` (list repetition) respects the time limit.
1194
- ///
1195
- /// The `mult_sequence()` copy loop now calls `heap.check_time()` on each
1196
- /// repetition to prevent large sequence multiplications from bypassing timeout.
1197
- #[test]
1198
- #[cfg_attr(
1199
- feature = "ref-count-panic",
1200
- ignore = "resource exhaustion doesn't guarantee heap state consistency"
1201
- )]
1202
- fn timeout_in_list_repetition() {
1203
- assert_timeout_in_builtin("[1, 2, 3] * 10_000_000", "list repetition");
1204
- }
1205
-
1206
- /// Test that `(1,) * 10_000_000` (tuple repetition) respects the time limit.
1207
- ///
1208
- /// Same as list repetition but for tuples — both paths in `mult_sequence()`
1209
- /// now check the time limit.
1210
- #[test]
1211
- #[cfg_attr(
1212
- feature = "ref-count-panic",
1213
- ignore = "resource exhaustion doesn't guarantee heap state consistency"
1214
- )]
1215
- fn timeout_in_tuple_repetition() {
1216
- assert_timeout_in_builtin("(1, 2, 3) * 10_000_000", "tuple repetition");
1217
- }
1218
-
1219
- /// Test that comparing two large equal lists respects the time limit.
1220
- ///
1221
- /// `List::py_eq()` iterates element-wise comparing pairs. With large equal lists,
1222
- /// it must compare every element before returning True.
1223
- #[test]
1224
- #[cfg_attr(
1225
- feature = "ref-count-panic",
1226
- ignore = "resource exhaustion doesn't guarantee heap state consistency"
1227
- )]
1228
- fn timeout_in_list_equality() {
1229
- let code = r"
1230
- a = list(range(10_000_000))
1231
- b = list(range(10_000_000))
1232
- a == b
1233
- ";
1234
- assert_timeout_in_builtin(code, "list equality");
1235
- }
1236
-
1237
- /// Test that comparing two large equal dicts respects the time limit.
1238
- ///
1239
- /// `Dict::py_eq()` iterates all entries checking keys and values. With large equal
1240
- /// dicts, it must check every entry before returning True.
1241
- #[test]
1242
- #[cfg_attr(
1243
- feature = "ref-count-panic",
1244
- ignore = "resource exhaustion doesn't guarantee heap state consistency"
1245
- )]
1246
- fn timeout_in_dict_equality() {
1247
- let code = r"
1248
- a = {i: i for i in range(10_000_000)}
1249
- b = {i: i for i in range(10_000_000)}
1250
- a == b
1251
- ";
1252
- assert_timeout_in_builtin(code, "dict equality");
1253
- }
1254
-
1255
- /// Test that `str.splitlines()` on a large string respects the time limit.
1256
- ///
1257
- /// `str_splitlines()` scans the entire string for line endings in a while loop
1258
- /// that now calls `heap.check_time()` on each iteration.
1259
- #[test]
1260
- #[cfg_attr(
1261
- feature = "ref-count-panic",
1262
- ignore = "resource exhaustion doesn't guarantee heap state consistency"
1263
- )]
1264
- fn timeout_in_str_splitlines() {
1265
- let code = r"
1266
- s = 'a\n' * 5_000_000
1267
- s.splitlines()
1268
- ";
1269
- assert_timeout_in_builtin(code, "str.splitlines()");
1270
- }
1271
-
1272
- /// Test that `bytes.splitlines()` on large bytes respects the time limit.
1273
- ///
1274
- /// `bytes_splitlines()` scans bytes for line endings and now checks the time limit.
1275
- #[test]
1276
- #[cfg_attr(
1277
- feature = "ref-count-panic",
1278
- ignore = "resource exhaustion doesn't guarantee heap state consistency"
1279
- )]
1280
- fn timeout_in_bytes_splitlines() {
1281
- let code = r"
1282
- s = b'a\n' * 5_000_000
1283
- s.splitlines()
1284
- ";
1285
- assert_timeout_in_builtin(code, "bytes.splitlines()");
1286
- }
1287
-
1288
- // === Timeout truncation in repr ===
1289
- // These tests verify that `repr()` on large containers respects the time limit
1290
- // and terminates promptly instead of hanging indefinitely. The repr methods
1291
- // (`repr_sequence_fmt`, `Dict::py_repr_fmt`, `SetInner::repr_fmt`) call
1292
- // `heap.check_time()` on each iteration and write `...[timeout]` when the
1293
- // time limit is exceeded, returning normally instead of propagating an error.
1294
- //
1295
- // Each test uses the external function "interrupt" pattern: the large object is
1296
- // built with NO time limit, then execution pauses at `interrupt()`. A short time
1297
- // limit is set before resuming, so only the `repr()` call is timed.
1298
-
1299
- /// Helper: builds a large object without time limit, then runs `repr()` on it
1300
- /// with a short time limit and asserts it produces a TimeoutError promptly.
1301
- ///
1302
- /// The code must call `interrupt()` between object construction and `repr()`.
1303
- fn assert_repr_timeout(code: &str, label: &str) {
1304
- let run = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
1305
-
1306
- // Phase 1: build the large object with no time limit
1307
- let limits = ResourceLimits::new();
1308
- let progress = run
1309
- .start(vec![], LimitedTracker::new(limits), PrintWriter::Stdout)
1310
- .unwrap();
1311
- let mut call = resolve_name_lookups(progress)
1312
- .unwrap()
1313
- .into_function_call()
1314
- .expect("interrupt call");
1315
- assert_eq!(call.function_name, "interrupt");
1316
-
1317
- // Phase 2: set a short time limit and resume — repr() should timeout
1318
- call.tracker_mut().set_max_duration(Duration::from_millis(10));
1319
-
1320
- let start = Instant::now();
1321
- let result = call.resume(MontyObject::None, PrintWriter::Stdout);
1322
- let elapsed = start.elapsed();
1323
-
1324
- let exc = result.unwrap_err();
1325
- assert_eq!(
1326
- exc.exc_type(),
1327
- ExcType::TimeoutError,
1328
- "{label}: expected TimeoutError, got: {exc}"
1329
- );
1330
- let msg = exc.message().unwrap();
1331
- assert!(msg.starts_with("time limit exceeded:"));
1332
- assert!(msg.ends_with("ms > 10ms"));
1333
- assert!(
1334
- elapsed < Duration::from_millis(200),
1335
- "{label}: should terminate promptly, took {elapsed:?}"
1336
- );
1337
- }
1338
-
1339
- /// Test that `repr(large_list)` respects the time limit.
1340
- ///
1341
- /// Uses a list of 100K short strings so that repr formatting is slow enough
1342
- /// to trigger the timeout.
1343
- #[test]
1344
- #[cfg_attr(
1345
- feature = "ref-count-panic",
1346
- ignore = "resource exhaustion doesn't guarantee heap state consistency"
1347
- )]
1348
- fn timeout_truncation_in_list_repr() {
1349
- let code = r"
1350
- x = ['abcdefghij'] * 100_000
1351
- interrupt()
1352
- repr(x)
1353
- ";
1354
- assert_repr_timeout(code, "list repr");
1355
- }
1356
-
1357
- /// Test that `repr(large_dict)` respects the time limit.
1358
- ///
1359
- /// Uses a dict with 100K entries where values are short strings,
1360
- /// making repr formatting slow enough to trigger the timeout.
1361
- #[test]
1362
- #[cfg_attr(
1363
- feature = "ref-count-panic",
1364
- ignore = "resource exhaustion doesn't guarantee heap state consistency"
1365
- )]
1366
- fn timeout_truncation_in_dict_repr() {
1367
- let code = r"
1368
- x = {i: 'abcdefghij' for i in range(100_000)}
1369
- interrupt()
1370
- repr(x)
1371
- ";
1372
- assert_repr_timeout(code, "dict repr");
1373
- }
1374
-
1375
- /// Test that `repr(large_set)` respects the time limit.
1376
- ///
1377
- /// Uses a set of 100K unique strings so that repr formatting is slow enough
1378
- /// to trigger the timeout.
1379
- #[test]
1380
- #[cfg_attr(
1381
- feature = "ref-count-panic",
1382
- ignore = "resource exhaustion doesn't guarantee heap state consistency"
1383
- )]
1384
- fn timeout_truncation_in_set_repr() {
1385
- let code = r"
1386
- x = {str(i) for i in range(100_000)}
1387
- interrupt()
1388
- repr(x)
1389
- ";
1390
- assert_repr_timeout(code, "set repr");
1391
- }
1392
-
1393
- /// Test that `str.replace` with amplification is rejected before allocation.
1394
- ///
1395
- /// `'a' * 1000` is 1KB (within limit), but replacing each 'a' with a 1KB string
1396
- /// produces a 1MB result. The pre-check should reject this before `String::replace()`
1397
- /// allocates the result on the Rust heap.
1398
- #[test]
1399
- fn str_replace_amplification_memory_limit() {
1400
- let code = r"
1401
- s = 'a' * 1000
1402
- s.replace('a', 'b' * 1000)
1403
- ";
1404
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
1405
-
1406
- let limits = ResourceLimits::new().max_memory(500_000); // 500KB limit
1407
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
1408
-
1409
- assert!(result.is_err(), "str.replace amplification should be rejected");
1410
- let exc = result.unwrap_err();
1411
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
1412
- assert!(
1413
- exc.message().is_some_and(|m| m.contains("memory limit exceeded")),
1414
- "expected memory limit error, got: {exc}"
1415
- );
1416
- }
1417
-
1418
- /// Test that small `str.replace` works within limits.
1419
- #[test]
1420
- fn str_replace_within_limit() {
1421
- let code = "'hello world'.replace('world', 'rust') == 'hello rust'";
1422
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
1423
-
1424
- let limits = ResourceLimits::new().max_memory(100_000);
1425
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
1426
-
1427
- assert!(result.is_ok(), "small str.replace should succeed");
1428
- assert_eq!(result.unwrap(), MontyObject::Bool(true));
1429
- }
1430
-
1431
- /// Test that `bytes.replace` with amplification is rejected before allocation.
1432
- #[test]
1433
- fn bytes_replace_amplification_memory_limit() {
1434
- let code = r"
1435
- s = b'a' * 1000
1436
- s.replace(b'a', b'b' * 1000)
1437
- ";
1438
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
1439
-
1440
- let limits = ResourceLimits::new().max_memory(500_000);
1441
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
1442
-
1443
- assert!(result.is_err(), "bytes.replace amplification should be rejected");
1444
- let exc = result.unwrap_err();
1445
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
1446
- assert!(
1447
- exc.message().is_some_and(|m| m.contains("memory limit exceeded")),
1448
- "expected memory limit error, got: {exc}"
1449
- );
1450
- }
1451
-
1452
- /// Test that `str.replace` with empty pattern amplification is rejected.
1453
- ///
1454
- /// Empty pattern inserts `new` before each char and after the last, so
1455
- /// result size = input_len * (new_len + 1).
1456
- #[test]
1457
- fn str_replace_empty_pattern_memory_limit() {
1458
- let code = r"
1459
- s = 'a' * 500
1460
- s.replace('', 'x' * 1000)
1461
- ";
1462
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
1463
-
1464
- let limits = ResourceLimits::new().max_memory(200_000);
1465
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
1466
-
1467
- assert!(
1468
- result.is_err(),
1469
- "str.replace with empty pattern amplification should be rejected"
1470
- );
1471
- let exc = result.unwrap_err();
1472
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
1473
- }
1474
-
1475
- /// Test that `str.ljust` with huge width is rejected before allocation.
1476
- ///
1477
- /// Without the pre-check, `String::with_capacity(width)` would allocate
1478
- /// directly on the Rust heap, bypassing the memory tracker entirely.
1479
- #[test]
1480
- fn str_ljust_memory_limit() {
1481
- let code = "'x'.ljust(2000000)";
1482
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
1483
-
1484
- let limits = ResourceLimits::new().max_memory(100_000);
1485
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
1486
-
1487
- assert!(result.is_err(), "str.ljust with huge width should be rejected");
1488
- let exc = result.unwrap_err();
1489
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
1490
- assert!(
1491
- exc.message().is_some_and(|m| m.contains("memory limit exceeded")),
1492
- "expected memory limit error, got: {exc}"
1493
- );
1494
- }
1495
-
1496
- /// Test that `str.rjust` with huge width is rejected before allocation.
1497
- #[test]
1498
- fn str_rjust_memory_limit() {
1499
- let code = "'x'.rjust(2000000)";
1500
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
1501
-
1502
- let limits = ResourceLimits::new().max_memory(100_000);
1503
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
1504
-
1505
- assert!(result.is_err(), "str.rjust with huge width should be rejected");
1506
- let exc = result.unwrap_err();
1507
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
1508
- }
1509
-
1510
- /// Test that `str.center` with huge width is rejected before allocation.
1511
- #[test]
1512
- fn str_center_memory_limit() {
1513
- let code = "'x'.center(2000000)";
1514
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
1515
-
1516
- let limits = ResourceLimits::new().max_memory(100_000);
1517
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
1518
-
1519
- assert!(result.is_err(), "str.center with huge width should be rejected");
1520
- let exc = result.unwrap_err();
1521
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
1522
- }
1523
-
1524
- /// Test that `str.zfill` with huge width is rejected before allocation.
1525
- #[test]
1526
- fn str_zfill_memory_limit() {
1527
- let code = "'42'.zfill(2000000)";
1528
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
1529
-
1530
- let limits = ResourceLimits::new().max_memory(100_000);
1531
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
1532
-
1533
- assert!(result.is_err(), "str.zfill with huge width should be rejected");
1534
- let exc = result.unwrap_err();
1535
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
1536
- }
1537
-
1538
- /// Test that small padding operations work within limits.
1539
- #[test]
1540
- fn str_padding_within_limit() {
1541
- let code = "'hi'.ljust(10) == 'hi '";
1542
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
1543
-
1544
- let limits = ResourceLimits::new().max_memory(100_000);
1545
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
1546
-
1547
- assert!(result.is_ok(), "small padding should succeed");
1548
- assert_eq!(result.unwrap(), MontyObject::Bool(true));
1549
- }
1550
-
1551
- /// Test that `bytes.ljust` with huge width is rejected before allocation.
1552
- #[test]
1553
- fn bytes_ljust_memory_limit() {
1554
- let code = "b'x'.ljust(2000000)";
1555
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
1556
-
1557
- let limits = ResourceLimits::new().max_memory(100_000);
1558
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
1559
-
1560
- assert!(result.is_err(), "bytes.ljust with huge width should be rejected");
1561
- let exc = result.unwrap_err();
1562
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
1563
- }
1564
-
1565
- /// Test that `bytes.rjust` with huge width is rejected before allocation.
1566
- #[test]
1567
- fn bytes_rjust_memory_limit() {
1568
- let code = "b'x'.rjust(2000000)";
1569
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
1570
-
1571
- let limits = ResourceLimits::new().max_memory(100_000);
1572
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
1573
-
1574
- assert!(result.is_err(), "bytes.rjust with huge width should be rejected");
1575
- let exc = result.unwrap_err();
1576
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
1577
- }
1578
-
1579
- /// Test that `bytes.center` with huge width is rejected before allocation.
1580
- #[test]
1581
- fn bytes_center_memory_limit() {
1582
- let code = "b'x'.center(2000000)";
1583
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
1584
-
1585
- let limits = ResourceLimits::new().max_memory(100_000);
1586
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
1587
-
1588
- assert!(result.is_err(), "bytes.center with huge width should be rejected");
1589
- let exc = result.unwrap_err();
1590
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
1591
- }
1592
-
1593
- /// Test that `bytes.zfill` with huge width is rejected before allocation.
1594
- #[test]
1595
- fn bytes_zfill_memory_limit() {
1596
- let code = "b'42'.zfill(2000000)";
1597
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
1598
-
1599
- let limits = ResourceLimits::new().max_memory(100_000);
1600
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
1601
-
1602
- assert!(result.is_err(), "bytes.zfill with huge width should be rejected");
1603
- let exc = result.unwrap_err();
1604
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
1605
- }
1606
-
1607
- /// Test that f-string formatting with huge width is rejected before allocation.
1608
- #[test]
1609
- fn fstring_dynamic_width_memory_limit() {
1610
- // Dynamic format spec via f-string nesting: {w} produces a runtime-parsed spec
1611
- let code = "w = 2000000\nf\"{'x':>{w}}\"";
1612
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
1613
-
1614
- let limits = ResourceLimits::new().max_memory(100_000);
1615
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
1616
-
1617
- assert!(result.is_err(), "f-string with huge dynamic width should be rejected");
1618
- let exc = result.unwrap_err();
1619
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
1620
- }
1621
-
1622
- // === re.sub() memory tracking tests ===
1623
- // These tests verify that the single-pass replacement loop in `re.sub()` tracks
1624
- // the running output size and bails out when the resource limit is exceeded.
1625
-
1626
- /// Test that `re.sub` with every-char pattern amplification is rejected.
1627
- ///
1628
- /// Pattern 'a' matches every character in 'aaa...'. Each replacement expands
1629
- /// 1 byte → 1000 bytes, so the output grows to ~1MB which exceeds the 500KB limit.
1630
- /// The inline loop catches this after a few hundred matches.
1631
- #[test]
1632
- fn re_sub_amplification_memory_limit() {
1633
- let code = r"
1634
- import re
1635
- s = 'a' * 1000
1636
- re.sub('a', 'b' * 1000, s)
1637
- ";
1638
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
1639
-
1640
- let limits = ResourceLimits::new().max_memory(500_000);
1641
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
1642
-
1643
- assert!(result.is_err(), "re.sub amplification should be rejected");
1644
- let exc = result.unwrap_err();
1645
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
1646
- assert!(
1647
- exc.message().is_some_and(|m| m.contains("memory limit exceeded")),
1648
- "expected memory limit error, got: {exc}"
1649
- );
1650
- }
1651
-
1652
- /// Test that `re.sub` with empty pattern amplification is rejected.
1653
- ///
1654
- /// Empty pattern matches N+1 times for N-char input (between and around every
1655
- /// character). Each match inserts 1000 bytes, so 501 matches × 1000 ≈ 500KB
1656
- /// which exceeds the 200KB limit.
1657
- #[test]
1658
- fn re_sub_empty_pattern_amplification_memory_limit() {
1659
- let code = r"
1660
- import re
1661
- s = 'a' * 500
1662
- re.sub('', 'x' * 1000, s)
1663
- ";
1664
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
1665
-
1666
- let limits = ResourceLimits::new().max_memory(200_000);
1667
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
1668
-
1669
- assert!(
1670
- result.is_err(),
1671
- "re.sub with empty pattern amplification should be rejected"
1672
- );
1673
- let exc = result.unwrap_err();
1674
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
1675
- }
1676
-
1677
- /// Test that `pattern.sub` (compiled pattern method) is also rejected.
1678
- #[test]
1679
- fn re_pattern_sub_amplification_memory_limit() {
1680
- let code = r"
1681
- import re
1682
- p = re.compile('a')
1683
- s = 'a' * 1000
1684
- p.sub('b' * 1000, s)
1685
- ";
1686
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
1687
-
1688
- let limits = ResourceLimits::new().max_memory(500_000);
1689
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
1690
-
1691
- assert!(result.is_err(), "pattern.sub amplification should be rejected");
1692
- let exc = result.unwrap_err();
1693
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
1694
- }
1695
-
1696
- /// Test that `re.sub` raises `re.PatternError` when the regex engine hits its backtracking limit.
1697
- ///
1698
- /// The pattern `(a+)+\1b` forces `fancy_regex` into its backtracking VM (due to the
1699
- /// backreference `\1`). With enough `a`s followed by a non-matching character, the
1700
- /// exponential blowup exceeds the engine's backtracking step limit (~1M steps).
1701
- #[test]
1702
- fn re_sub_backtracking_limit_raises_pattern_error() {
1703
- let code = r"
1704
- import re
1705
- re.sub('(a+)+\\1b', 'X', 'a' * 30 + 'c')
1706
- ";
1707
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
1708
-
1709
- let limits = ResourceLimits::new().max_memory(500_000);
1710
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
1711
-
1712
- assert!(result.is_err(), "backtracking limit should raise an error");
1713
- let exc = result.unwrap_err();
1714
- assert_eq!(exc.exc_type(), ExcType::RePatternError);
1715
- assert!(
1716
- exc.message().is_some_and(|m| m.contains("backtrack")),
1717
- "expected backtracking error, got: {exc}"
1718
- );
1719
- }
1720
-
1721
- // --- Selective patterns: few matches in large text stay within limits ---
1722
-
1723
- /// Test that a selective pattern on large text passes.
1724
- ///
1725
- /// The pattern `xxx` only matches 3 times (at positions 0, 3, 6 in the 9-char prefix),
1726
- /// so the result is ~10000 - 9 + 300 = 10291 bytes — well within the 500KB limit.
1727
- #[test]
1728
- fn re_sub_selective_pattern_passes() {
1729
- // 'xxx' repeated 3 times at the start, rest is 'a's
1730
- let code = r"
1731
- import re
1732
- s = 'xxx' * 3 + 'a' * 9991
1733
- result = re.sub('xxx', 'y' * 100, s)
1734
- len(result) == 9991 + 3 * 100
1735
- ";
1736
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
1737
-
1738
- let limits = ResourceLimits::new().max_memory(500_000);
1739
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
1740
-
1741
- assert!(
1742
- result.is_ok(),
1743
- "selective pattern with few matches should pass: {result:?}"
1744
- );
1745
- assert_eq!(result.unwrap(), MontyObject::Bool(true));
1746
- }
1747
-
1748
- /// Test that a digit-matching pattern on mostly-text input passes.
1749
- ///
1750
- /// Pattern `\d+` matches only the 10-digit number, so the result is
1751
- /// 990 + 200 = 1190 bytes — well within the 150KB limit.
1752
- #[test]
1753
- fn re_sub_digit_pattern_passes() {
1754
- let code = r"
1755
- import re
1756
- s = 'a' * 990 + '1234567890'
1757
- result = re.sub('\d+', 'X' * 200, s)
1758
- len(result) == 990 + 200
1759
- ";
1760
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
1761
-
1762
- let limits = ResourceLimits::new().max_memory(150_000);
1763
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
1764
-
1765
- assert!(result.is_ok(), "digit pattern on mostly-text should pass: {result:?}");
1766
- assert_eq!(result.unwrap(), MontyObject::Bool(true));
1767
- }
1768
-
1769
- /// Test that every-char amplification is still rejected even with a generic pattern.
1770
- ///
1771
- /// Pattern `.` matches every character (10000 matches), each expanding 1 → 1000 bytes.
1772
- /// The inline loop catches this after a few hundred matches once the running output
1773
- /// size exceeds the 500KB limit.
1774
- #[test]
1775
- fn re_sub_every_char_amplification_rejected() {
1776
- let code = r"
1777
- import re
1778
- s = 'a' * 10000
1779
- re.sub('.', 'b' * 1000, s)
1780
- ";
1781
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
1782
-
1783
- let limits = ResourceLimits::new().max_memory(500_000);
1784
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
1785
-
1786
- assert!(result.is_err(), "every-char pattern amplification should be rejected");
1787
- let exc = result.unwrap_err();
1788
- assert_eq!(exc.exc_type(), ExcType::MemoryError);
1789
- }
1790
-
1791
- // --- General re.sub tests ---
1792
-
1793
- /// Test that small `re.sub` works within limits.
1794
- #[test]
1795
- fn re_sub_within_limit() {
1796
- let code = r"
1797
- import re
1798
- re.sub('world', 'rust', 'hello world') == 'hello rust'
1799
- ";
1800
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
1801
-
1802
- let limits = ResourceLimits::new().max_memory(100_000);
1803
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
1804
-
1805
- assert!(result.is_ok(), "small re.sub should succeed");
1806
- assert_eq!(result.unwrap(), MontyObject::Bool(true));
1807
- }
1808
-
1809
- /// Test that `re.sub` with count parameter limits replacements correctly.
1810
- ///
1811
- /// `count=5` caps replacements to 5, so the result is
1812
- /// 995 unchanged bytes + 5 × 100 replacement bytes = 1495 bytes.
1813
- #[test]
1814
- fn re_sub_with_count_within_limit() {
1815
- let code = r"
1816
- import re
1817
- re.sub('a', 'b' * 100, 'a' * 1000, count=5) == 'b' * 500 + 'a' * 995
1818
- ";
1819
- let ex = MontyRun::new(code.to_owned(), "test.py", vec![]).unwrap();
1820
-
1821
- let limits = ResourceLimits::new().max_memory(500_000);
1822
- let result = ex.run(vec![], LimitedTracker::new(limits), PrintWriter::Stdout);
1823
-
1824
- assert!(result.is_ok(), "re.sub with small count should succeed");
1825
- assert_eq!(result.unwrap(), MontyObject::Bool(true));
1826
- }