superacli 1.1.6 → 1.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1268) hide show
  1. package/CONTRIBUTING.md +270 -0
  2. package/README.md +141 -54
  3. package/__tests__/adapter-schema.test.js +251 -86
  4. package/__tests__/azd-plugin.test.js +109 -0
  5. package/__tests__/config.test.js +4 -3
  6. package/__tests__/discover.test.js +59 -0
  7. package/__tests__/goose-plugin.test.js +149 -0
  8. package/__tests__/help-json.test.js +2 -0
  9. package/__tests__/openhands-plugin.test.js +106 -0
  10. package/__tests__/plugin-cocoindex-code-uninstall.test.js +19 -0
  11. package/__tests__/plugin-cocoindex-code.test.js +37 -0
  12. package/__tests__/plugin-install-guidance.test.js +81 -0
  13. package/__tests__/plugins-registry.test.js +44 -0
  14. package/__tests__/plugins-store.test.js +40 -5
  15. package/__tests__/process-adapter.test.js +50 -1
  16. package/__tests__/resend-plugin.test.js +109 -82
  17. package/__tests__/server-app.test.js +1 -0
  18. package/__tests__/server-routes-commands.test.js +20 -2
  19. package/__tests__/server-routes-plugins.test.js +130 -0
  20. package/__tests__/skills.test.js +26 -0
  21. package/__tests__/squirrelscan-plugin.test.js +129 -0
  22. package/__tests__/uipath-plugin.test.js +104 -0
  23. package/__tests__/uipathcli-plugin.test.js +95 -0
  24. package/cli/adapters/mcp.js +2 -0
  25. package/cli/adapters/process.js +50 -7
  26. package/cli/config.js +240 -3
  27. package/cli/discover.js +157 -0
  28. package/cli/help-json.js +16 -1
  29. package/cli/plugin-install-guidance.js +92 -37
  30. package/cli/plugins-manager.js +4 -3
  31. package/cli/plugins-registry.js +74 -8
  32. package/cli/plugins-store.js +78 -17
  33. package/cli/skills-mcp.js +1 -1
  34. package/cli/skills.js +39 -2
  35. package/cli/supercli.js +255 -63
  36. package/docs/feature-gaps.md +8 -8
  37. package/docs/features/azd-uipath-plugins.md +43 -0
  38. package/docs/features/server-plugins.md +62 -0
  39. package/docs/features/skills.md +9 -5
  40. package/docs/index.html +183 -123
  41. package/docs/{supported-harnesses.md → plugins-available.md} +4 -3
  42. package/docs/{plugin-harness-guide.md → plugins-how-to.md} +1 -1
  43. package/docs/plugins.md +26 -20
  44. package/docs/server-plugins-usage-guide.md +182 -0
  45. package/docs/skills-catalog.md +12 -10
  46. package/index.html +384 -0
  47. package/package.json +2 -2
  48. package/plugins/agent-browser/README.md +69 -0
  49. package/plugins/agent-browser/plugin.json +111 -0
  50. package/plugins/agent-browser/skills/quickstart/SKILL.md +66 -0
  51. package/plugins/aider/README.md +53 -0
  52. package/plugins/aider/plugin.json +105 -0
  53. package/plugins/aider/scripts/aider-wrapper.js +243 -0
  54. package/plugins/aider/scripts/setup-aider.js +37 -0
  55. package/plugins/aider/skills/dry-run-review.md +24 -0
  56. package/plugins/aider/skills/model-and-provider.md +24 -0
  57. package/plugins/aider/skills/one-shot-edits.md +30 -0
  58. package/plugins/aider/skills/quickstart/SKILL.md +51 -0
  59. package/plugins/azd/README.md +28 -0
  60. package/plugins/azd/plugin.json +87 -0
  61. package/plugins/azd/skills/quickstart/SKILL.md +41 -0
  62. package/plugins/blogwatcher/README.md +3 -3
  63. package/plugins/boxlite/Dockerfile +9 -0
  64. package/plugins/boxlite/README.md +62 -0
  65. package/plugins/boxlite/plugin.json +201 -0
  66. package/plugins/boxlite/scripts/run-boxlite.js +106 -0
  67. package/plugins/boxlite/skills/quickstart/SKILL.md +40 -0
  68. package/plugins/cass/plugin.json +150 -0
  69. package/plugins/cass/scripts/setup-cass.js +47 -0
  70. package/plugins/cass/skills/quickstart/SKILL.md +46 -0
  71. package/plugins/clever/README.md +46 -0
  72. package/plugins/clever/plugin.json +119 -0
  73. package/plugins/clever/scripts/setup-clever.js +28 -0
  74. package/plugins/clever/skills/auth-and-profile.md +29 -0
  75. package/plugins/clever/skills/passthrough-safety.md +21 -0
  76. package/plugins/clever/skills/quickstart/SKILL.md +45 -0
  77. package/plugins/clever/skills/resource-inventory.md +24 -0
  78. package/plugins/clix/README.md +4 -4
  79. package/plugins/cocoindex-code/README.md +64 -0
  80. package/plugins/cocoindex-code/plugin.json +81 -0
  81. package/plugins/cocoindex-code/scripts/__pycache__/query.cpython-310.pyc +0 -0
  82. package/plugins/cocoindex-code/scripts/__pycache__/query.cpython-311.pyc +0 -0
  83. package/plugins/cocoindex-code/scripts/post-install.js +61 -0
  84. package/plugins/cocoindex-code/scripts/post-uninstall.js +25 -0
  85. package/plugins/cocoindex-code/scripts/query.py +88 -0
  86. package/plugins/cocoindex-code/scripts/run-query.js +50 -0
  87. package/plugins/cocoindex-code/skills/quickstart/SKILL.md +73 -0
  88. package/plugins/copilot/README.md +24 -0
  89. package/plugins/copilot/plugin.json +80 -0
  90. package/plugins/copilot/skills/quickstart/SKILL.md +44 -0
  91. package/plugins/gemini/README.md +24 -0
  92. package/plugins/gemini/plugin.json +98 -0
  93. package/plugins/gemini/skills/quickstart/SKILL.md +44 -0
  94. package/plugins/gifcap/plugin.json +119 -0
  95. package/plugins/gifcap/scripts/setup-gifcap.js +44 -0
  96. package/plugins/gifcap/skills/quickstart/SKILL.md +34 -0
  97. package/plugins/gifcap/test-record-quiet.gif +0 -0
  98. package/plugins/gifcap/test-record.gif +0 -0
  99. package/plugins/goose/README.md +36 -0
  100. package/plugins/goose/plugin.json +183 -0
  101. package/plugins/goose/skills/quickstart/SKILL.md +44 -0
  102. package/plugins/json-server/README.md +58 -0
  103. package/plugins/json-server/plugin.json +113 -0
  104. package/plugins/json-server/skills/quickstart/SKILL.md +57 -0
  105. package/plugins/lightpanda/README.md +145 -0
  106. package/plugins/lightpanda/package-lock.json +1375 -0
  107. package/plugins/lightpanda/package.json +12 -0
  108. package/plugins/lightpanda/plugin.json +116 -0
  109. package/plugins/lightpanda/scripts/lightpanda-contacts.js +494 -0
  110. package/plugins/lightpanda/scripts/lightpanda-generic-extract.js +403 -0
  111. package/plugins/lightpanda/scripts/lightpanda-wrapper.js +480 -0
  112. package/plugins/lightpanda/scripts/setup-lightpanda.js +39 -0
  113. package/plugins/lightpanda/skills/contact-discovery.md +51 -0
  114. package/plugins/lightpanda/skills/generic-extraction.md +66 -0
  115. package/plugins/lightpanda/skills/quickstart/SKILL.md +103 -0
  116. package/plugins/lightpanda/skills/resilient-navigation.md +42 -0
  117. package/plugins/monty/README.md +2 -2
  118. package/plugins/nullclaw/README.md +3 -3
  119. package/plugins/offline-ai/README.md +23 -0
  120. package/plugins/offline-ai/plugin.json +82 -0
  121. package/plugins/offline-ai/skills/quickstart/SKILL.md +43 -0
  122. package/plugins/openhands/README.md +25 -0
  123. package/plugins/openhands/plugin.json +116 -0
  124. package/plugins/openhands/skills/quickstart/SKILL.md +26 -0
  125. package/plugins/plandex/README.md +25 -0
  126. package/plugins/plandex/plugin.json +130 -0
  127. package/plugins/plandex/skills/quickstart/SKILL.md +50 -0
  128. package/plugins/plugins.json +199 -0
  129. package/plugins/squirrelscan/Dockerfile +5 -0
  130. package/plugins/squirrelscan/README.md +47 -0
  131. package/plugins/squirrelscan/plugin.json +493 -0
  132. package/plugins/squirrelscan/scripts/post-install.js +33 -0
  133. package/plugins/squirrelscan/scripts/post-uninstall.js +25 -0
  134. package/plugins/squirrelscan/scripts/run-squirrel.js +73 -0
  135. package/plugins/squirrelscan/skills/audit-workflow/SKILL.md +33 -0
  136. package/plugins/squirrelscan/skills/publish-report/SKILL.md +33 -0
  137. package/plugins/squirrelscan/skills/quickstart/SKILL.md +41 -0
  138. package/plugins/uipath/README.md +27 -0
  139. package/plugins/uipath/plugin.json +86 -0
  140. package/plugins/uipath/skills/quickstart/SKILL.md +47 -0
  141. package/plugins/uipathcli/README.md +28 -0
  142. package/plugins/uipathcli/plugin.json +120 -0
  143. package/plugins/uipathcli/scripts/run-uipath-cli.js +49 -0
  144. package/plugins/uipathcli/skills/quickstart/SKILL.md +22 -0
  145. package/plugins/xurl/README.md +4 -4
  146. package/server/app.js +5 -2
  147. package/server/public/app.js +3 -0
  148. package/server/routes/commands.js +95 -12
  149. package/server/routes/plugins.js +262 -0
  150. package/server/services/pluginsService.js +303 -0
  151. package/server/views/command-edit.ejs +196 -14
  152. package/server/views/partials/head.ejs +1 -0
  153. package/server/views/plugins.ejs +264 -0
  154. package/tests/test-plugins-registry.js +30 -0
  155. package/.beads/.br_history/issues.20260308_200823_636718328.jsonl +0 -20
  156. package/.beads/.br_history/issues.20260308_200823_636718328.jsonl.meta.json +0 -1
  157. package/.beads/.br_history/issues.20260308_200827_033159453.jsonl +0 -21
  158. package/.beads/.br_history/issues.20260308_200827_033159453.jsonl.meta.json +0 -1
  159. package/.beads/.br_history/issues.20260308_200829_595900053.jsonl +0 -22
  160. package/.beads/.br_history/issues.20260308_200829_595900053.jsonl.meta.json +0 -1
  161. package/.beads/.br_history/issues.20260308_200834_079930100.jsonl +0 -23
  162. package/.beads/.br_history/issues.20260308_200834_079930100.jsonl.meta.json +0 -1
  163. package/.beads/.br_history/issues.20260308_200858_370924996.jsonl +0 -24
  164. package/.beads/.br_history/issues.20260308_200858_370924996.jsonl.meta.json +0 -1
  165. package/.beads/.br_history/issues.20260308_201031_019730855.jsonl +0 -24
  166. package/.beads/.br_history/issues.20260308_201031_019730855.jsonl.meta.json +0 -1
  167. package/.beads/.br_history/issues.20260308_201031_578974884.jsonl +0 -24
  168. package/.beads/.br_history/issues.20260308_201031_578974884.jsonl.meta.json +0 -1
  169. package/.beads/.br_history/issues.20260308_201054_780345548.jsonl +0 -24
  170. package/.beads/.br_history/issues.20260308_201054_780345548.jsonl.meta.json +0 -1
  171. package/.beads/.br_history/issues.20260308_201054_896980019.jsonl +0 -24
  172. package/.beads/.br_history/issues.20260308_201054_896980019.jsonl.meta.json +0 -1
  173. package/.beads/.br_history/issues.20260308_201128_599819688.jsonl +0 -24
  174. package/.beads/.br_history/issues.20260308_201128_599819688.jsonl.meta.json +0 -1
  175. package/.beads/.br_history/issues.20260308_201128_710221699.jsonl +0 -24
  176. package/.beads/.br_history/issues.20260308_201128_710221699.jsonl.meta.json +0 -1
  177. package/.beads/.br_history/issues.20260308_201204_745649213.jsonl +0 -24
  178. package/.beads/.br_history/issues.20260308_201204_745649213.jsonl.meta.json +0 -1
  179. package/.beads/.br_history/issues.20260308_201338_908436144.jsonl +0 -24
  180. package/.beads/.br_history/issues.20260308_201338_908436144.jsonl.meta.json +0 -1
  181. package/.beads/.br_history/issues.20260308_201344_734860714.jsonl +0 -25
  182. package/.beads/.br_history/issues.20260308_201344_734860714.jsonl.meta.json +0 -1
  183. package/.beads/.br_history/issues.20260308_201630_819282295.jsonl +0 -25
  184. package/.beads/.br_history/issues.20260308_201630_819282295.jsonl.meta.json +0 -1
  185. package/.beads/.br_history/issues.20260308_203538_054279699.jsonl +0 -25
  186. package/.beads/.br_history/issues.20260308_203538_054279699.jsonl.meta.json +0 -1
  187. package/.beads/.br_history/issues.20260308_203547_597113070.jsonl +0 -26
  188. package/.beads/.br_history/issues.20260308_203547_597113070.jsonl.meta.json +0 -1
  189. package/.beads/.br_history/issues.20260308_203547_775139216.jsonl +0 -27
  190. package/.beads/.br_history/issues.20260308_203547_775139216.jsonl.meta.json +0 -1
  191. package/.beads/.br_history/issues.20260308_203547_950724773.jsonl +0 -28
  192. package/.beads/.br_history/issues.20260308_203547_950724773.jsonl.meta.json +0 -1
  193. package/.beads/.br_history/issues.20260308_203548_107684523.jsonl +0 -29
  194. package/.beads/.br_history/issues.20260308_203548_107684523.jsonl.meta.json +0 -1
  195. package/.beads/.br_history/issues.20260308_203548_310389993.jsonl +0 -30
  196. package/.beads/.br_history/issues.20260308_203548_310389993.jsonl.meta.json +0 -1
  197. package/.beads/.br_history/issues.20260308_203825_953337320.jsonl +0 -31
  198. package/.beads/.br_history/issues.20260308_203825_953337320.jsonl.meta.json +0 -1
  199. package/.beads/.br_history/issues.20260308_204056_071377736.jsonl +0 -32
  200. package/.beads/.br_history/issues.20260308_204056_071377736.jsonl.meta.json +0 -1
  201. package/.beads/.br_history/issues.20260308_205141_517616844.jsonl +0 -32
  202. package/.beads/.br_history/issues.20260308_205141_517616844.jsonl.meta.json +0 -1
  203. package/.beads/.br_history/issues.20260308_205141_648994024.jsonl +0 -32
  204. package/.beads/.br_history/issues.20260308_205141_648994024.jsonl.meta.json +0 -1
  205. package/.beads/.br_history/issues.20260308_205141_867598036.jsonl +0 -32
  206. package/.beads/.br_history/issues.20260308_205141_867598036.jsonl.meta.json +0 -1
  207. package/.beads/.br_history/issues.20260308_205142_094157355.jsonl +0 -32
  208. package/.beads/.br_history/issues.20260308_205142_094157355.jsonl.meta.json +0 -1
  209. package/.beads/.br_history/issues.20260308_205142_327315677.jsonl +0 -32
  210. package/.beads/.br_history/issues.20260308_205142_327315677.jsonl.meta.json +0 -1
  211. package/.beads/.br_history/issues.20260308_205142_545563822.jsonl +0 -32
  212. package/.beads/.br_history/issues.20260308_205142_545563822.jsonl.meta.json +0 -1
  213. package/.beads/.br_history/issues.20260308_205213_061989333.jsonl +0 -32
  214. package/.beads/.br_history/issues.20260308_205213_061989333.jsonl.meta.json +0 -1
  215. package/.beads/.br_history/issues.20260308_205213_181103364.jsonl +0 -32
  216. package/.beads/.br_history/issues.20260308_205213_181103364.jsonl.meta.json +0 -1
  217. package/.beads/.br_history/issues.20260308_205213_408872234.jsonl +0 -32
  218. package/.beads/.br_history/issues.20260308_205213_408872234.jsonl.meta.json +0 -1
  219. package/.beads/.br_history/issues.20260308_205213_616681652.jsonl +0 -32
  220. package/.beads/.br_history/issues.20260308_205213_616681652.jsonl.meta.json +0 -1
  221. package/.beads/.br_history/issues.20260308_205213_821507069.jsonl +0 -32
  222. package/.beads/.br_history/issues.20260308_205213_821507069.jsonl.meta.json +0 -1
  223. package/.beads/.br_history/issues.20260308_205214_026661112.jsonl +0 -32
  224. package/.beads/.br_history/issues.20260308_205214_026661112.jsonl.meta.json +0 -1
  225. package/.beads/.br_history/issues.20260308_205454_955250554.jsonl +0 -32
  226. package/.beads/.br_history/issues.20260308_205454_955250554.jsonl.meta.json +0 -1
  227. package/.beads/.br_history/issues.20260308_205556_337800392.jsonl +0 -33
  228. package/.beads/.br_history/issues.20260308_205556_337800392.jsonl.meta.json +0 -1
  229. package/.beads/.br_history/issues.20260308_205824_274686694.jsonl +0 -33
  230. package/.beads/.br_history/issues.20260308_205824_274686694.jsonl.meta.json +0 -1
  231. package/.beads/.br_history/issues.20260308_210240_583768328.jsonl +0 -34
  232. package/.beads/.br_history/issues.20260308_210240_583768328.jsonl.meta.json +0 -1
  233. package/.beads/.br_history/issues.20260308_212223_641541494.jsonl +0 -34
  234. package/.beads/.br_history/issues.20260308_212223_641541494.jsonl.meta.json +0 -1
  235. package/.beads/.br_history/issues.20260308_212227_735550996.jsonl +0 -35
  236. package/.beads/.br_history/issues.20260308_212227_735550996.jsonl.meta.json +0 -1
  237. package/.beads/.br_history/issues.20260308_212232_547298548.jsonl +0 -36
  238. package/.beads/.br_history/issues.20260308_212232_547298548.jsonl.meta.json +0 -1
  239. package/.beads/.br_history/issues.20260308_212528_843628125.jsonl +0 -37
  240. package/.beads/.br_history/issues.20260308_212528_843628125.jsonl.meta.json +0 -1
  241. package/.beads/.br_history/issues.20260308_212529_094530502.jsonl +0 -38
  242. package/.beads/.br_history/issues.20260308_212529_094530502.jsonl.meta.json +0 -1
  243. package/.beads/.br_history/issues.20260308_212529_331000853.jsonl +0 -39
  244. package/.beads/.br_history/issues.20260308_212529_331000853.jsonl.meta.json +0 -1
  245. package/.beads/.br_history/issues.20260308_212529_587925652.jsonl +0 -40
  246. package/.beads/.br_history/issues.20260308_212529_587925652.jsonl.meta.json +0 -1
  247. package/.beads/.br_history/issues.20260308_212804_927764103.jsonl +0 -41
  248. package/.beads/.br_history/issues.20260308_212804_927764103.jsonl.meta.json +0 -1
  249. package/.beads/.br_history/issues.20260308_212805_153673453.jsonl +0 -42
  250. package/.beads/.br_history/issues.20260308_212805_153673453.jsonl.meta.json +0 -1
  251. package/.beads/.br_history/issues.20260308_212805_415982363.jsonl +0 -43
  252. package/.beads/.br_history/issues.20260308_212805_415982363.jsonl.meta.json +0 -1
  253. package/.beads/.br_history/issues.20260308_212805_657497741.jsonl +0 -44
  254. package/.beads/.br_history/issues.20260308_212805_657497741.jsonl.meta.json +0 -1
  255. package/.beads/.br_history/issues.20260308_212805_952838724.jsonl +0 -45
  256. package/.beads/.br_history/issues.20260308_212805_952838724.jsonl.meta.json +0 -1
  257. package/.beads/.br_history/issues.20260308_212806_325433779.jsonl +0 -46
  258. package/.beads/.br_history/issues.20260308_212806_325433779.jsonl.meta.json +0 -1
  259. package/.beads/.br_history/issues.20260308_212806_584685598.jsonl +0 -47
  260. package/.beads/.br_history/issues.20260308_212806_584685598.jsonl.meta.json +0 -1
  261. package/.beads/.br_history/issues.20260308_212806_827817208.jsonl +0 -48
  262. package/.beads/.br_history/issues.20260308_212806_827817208.jsonl.meta.json +0 -1
  263. package/.beads/.br_history/issues.20260308_212807_111320451.jsonl +0 -49
  264. package/.beads/.br_history/issues.20260308_212807_111320451.jsonl.meta.json +0 -1
  265. package/.beads/.br_history/issues.20260308_212807_409545536.jsonl +0 -50
  266. package/.beads/.br_history/issues.20260308_212807_409545536.jsonl.meta.json +0 -1
  267. package/.beads/.br_history/issues.20260308_212807_625063294.jsonl +0 -51
  268. package/.beads/.br_history/issues.20260308_212807_625063294.jsonl.meta.json +0 -1
  269. package/.beads/.br_history/issues.20260308_212807_843906551.jsonl +0 -52
  270. package/.beads/.br_history/issues.20260308_212807_843906551.jsonl.meta.json +0 -1
  271. package/.beads/.br_history/issues.20260308_212808_100304073.jsonl +0 -53
  272. package/.beads/.br_history/issues.20260308_212808_100304073.jsonl.meta.json +0 -1
  273. package/.beads/.br_history/issues.20260308_212808_324723976.jsonl +0 -54
  274. package/.beads/.br_history/issues.20260308_212808_324723976.jsonl.meta.json +0 -1
  275. package/.beads/.br_history/issues.20260308_212808_557513104.jsonl +0 -55
  276. package/.beads/.br_history/issues.20260308_212808_557513104.jsonl.meta.json +0 -1
  277. package/.beads/.br_history/issues.20260308_212808_788048322.jsonl +0 -56
  278. package/.beads/.br_history/issues.20260308_212808_788048322.jsonl.meta.json +0 -1
  279. package/.beads/.br_history/issues.20260308_213702_613249728.jsonl +0 -57
  280. package/.beads/.br_history/issues.20260308_213702_613249728.jsonl.meta.json +0 -1
  281. package/.beads/.br_history/issues.20260308_213715_115792063.jsonl +0 -57
  282. package/.beads/.br_history/issues.20260308_213715_115792063.jsonl.meta.json +0 -1
  283. package/.beads/.br_history/issues.20260308_213715_462220666.jsonl +0 -57
  284. package/.beads/.br_history/issues.20260308_213715_462220666.jsonl.meta.json +0 -1
  285. package/.beads/.br_history/issues.20260308_213727_191258923.jsonl +0 -57
  286. package/.beads/.br_history/issues.20260308_213727_191258923.jsonl.meta.json +0 -1
  287. package/.beads/.br_history/issues.20260308_213727_684383652.jsonl +0 -57
  288. package/.beads/.br_history/issues.20260308_213727_684383652.jsonl.meta.json +0 -1
  289. package/.beads/.br_history/issues.20260308_213735_751882991.jsonl +0 -57
  290. package/.beads/.br_history/issues.20260308_213735_751882991.jsonl.meta.json +0 -1
  291. package/.beads/.br_history/issues.20260308_222052_279844960.jsonl +0 -57
  292. package/.beads/.br_history/issues.20260308_222052_279844960.jsonl.meta.json +0 -1
  293. package/.beads/.br_history/issues.20260308_222056_873282114.jsonl +0 -57
  294. package/.beads/.br_history/issues.20260308_222056_873282114.jsonl.meta.json +0 -1
  295. package/.beads/.br_history/issues.20260308_222103_402410761.jsonl +0 -57
  296. package/.beads/.br_history/issues.20260308_222103_402410761.jsonl.meta.json +0 -1
  297. package/.beads/.br_history/issues.20260308_235202_180577215.jsonl +0 -57
  298. package/.beads/.br_history/issues.20260308_235202_180577215.jsonl.meta.json +0 -1
  299. package/.beads/.br_history/issues.20260308_235202_387414163.jsonl +0 -57
  300. package/.beads/.br_history/issues.20260308_235202_387414163.jsonl.meta.json +0 -1
  301. package/.beads/.br_history/issues.20260308_235202_564422794.jsonl +0 -57
  302. package/.beads/.br_history/issues.20260308_235202_564422794.jsonl.meta.json +0 -1
  303. package/.beads/.br_history/issues.20260308_235202_742600597.jsonl +0 -57
  304. package/.beads/.br_history/issues.20260308_235202_742600597.jsonl.meta.json +0 -1
  305. package/.beads/.br_history/issues.20260308_235208_133360069.jsonl +0 -57
  306. package/.beads/.br_history/issues.20260308_235208_133360069.jsonl.meta.json +0 -1
  307. package/.beads/.br_history/issues.20260308_235505_473406307.jsonl +0 -57
  308. package/.beads/.br_history/issues.20260308_235505_473406307.jsonl.meta.json +0 -1
  309. package/.beads/.br_history/issues.20260308_235505_662360489.jsonl +0 -57
  310. package/.beads/.br_history/issues.20260308_235505_662360489.jsonl.meta.json +0 -1
  311. package/.beads/.br_history/issues.20260308_235505_843935624.jsonl +0 -57
  312. package/.beads/.br_history/issues.20260308_235505_843935624.jsonl.meta.json +0 -1
  313. package/.beads/.br_history/issues.20260308_235506_044530221.jsonl +0 -57
  314. package/.beads/.br_history/issues.20260308_235506_044530221.jsonl.meta.json +0 -1
  315. package/.beads/.br_history/issues.20260309_002618_115728731.jsonl +0 -57
  316. package/.beads/.br_history/issues.20260309_002618_115728731.jsonl.meta.json +0 -1
  317. package/.beads/.br_history/issues.20260309_003748_878174586.jsonl +0 -57
  318. package/.beads/.br_history/issues.20260309_003748_878174586.jsonl.meta.json +0 -1
  319. package/.beads/.br_history/issues.20260309_004057_868755623.jsonl +0 -57
  320. package/.beads/.br_history/issues.20260309_004057_868755623.jsonl.meta.json +0 -1
  321. package/.beads/.br_history/issues.20260309_004058_512842163.jsonl +0 -57
  322. package/.beads/.br_history/issues.20260309_004058_512842163.jsonl.meta.json +0 -1
  323. package/.beads/.br_history/issues.20260309_004058_994445226.jsonl +0 -57
  324. package/.beads/.br_history/issues.20260309_004058_994445226.jsonl.meta.json +0 -1
  325. package/.beads/.br_history/issues.20260309_004059_475988596.jsonl +0 -57
  326. package/.beads/.br_history/issues.20260309_004059_475988596.jsonl.meta.json +0 -1
  327. package/.beads/.br_history/issues.20260309_161902_566857851.jsonl +0 -57
  328. package/.beads/.br_history/issues.20260309_161902_566857851.jsonl.meta.json +0 -1
  329. package/.beads/.br_history/issues.20260309_170512_277017739.jsonl +0 -57
  330. package/.beads/.br_history/issues.20260309_170512_277017739.jsonl.meta.json +0 -1
  331. package/.beads/.br_history/issues.20260309_170512_477876921.jsonl +0 -57
  332. package/.beads/.br_history/issues.20260309_170512_477876921.jsonl.meta.json +0 -1
  333. package/.beads/.br_history/issues.20260309_170512_664382701.jsonl +0 -57
  334. package/.beads/.br_history/issues.20260309_170512_664382701.jsonl.meta.json +0 -1
  335. package/.beads/.br_history/issues.20260309_170512_859400333.jsonl +0 -57
  336. package/.beads/.br_history/issues.20260309_170512_859400333.jsonl.meta.json +0 -1
  337. package/.beads/.br_history/issues.20260309_212326_082771164.jsonl +0 -57
  338. package/.beads/.br_history/issues.20260309_212326_082771164.jsonl.meta.json +0 -1
  339. package/.beads/.br_history/issues.20260309_212326_245619716.jsonl +0 -58
  340. package/.beads/.br_history/issues.20260309_212326_245619716.jsonl.meta.json +0 -1
  341. package/.beads/.br_history/issues.20260309_212326_403198317.jsonl +0 -59
  342. package/.beads/.br_history/issues.20260309_212326_403198317.jsonl.meta.json +0 -1
  343. package/.beads/.br_history/issues.20260309_212332_539197678.jsonl +0 -60
  344. package/.beads/.br_history/issues.20260309_212332_539197678.jsonl.meta.json +0 -1
  345. package/.beads/.br_history/issues.20260309_212332_731373599.jsonl +0 -60
  346. package/.beads/.br_history/issues.20260309_212332_731373599.jsonl.meta.json +0 -1
  347. package/.beads/.br_history/issues.20260309_212332_928710953.jsonl +0 -60
  348. package/.beads/.br_history/issues.20260309_212332_928710953.jsonl.meta.json +0 -1
  349. package/.beads/.br_history/issues.20260309_213021_341505240.jsonl +0 -60
  350. package/.beads/.br_history/issues.20260309_213021_341505240.jsonl.meta.json +0 -1
  351. package/.beads/.br_history/issues.20260309_213022_023136934.jsonl +0 -60
  352. package/.beads/.br_history/issues.20260309_213022_023136934.jsonl.meta.json +0 -1
  353. package/.beads/.br_history/issues.20260309_213022_400050719.jsonl +0 -60
  354. package/.beads/.br_history/issues.20260309_213022_400050719.jsonl.meta.json +0 -1
  355. package/.beads/config.yaml +0 -4
  356. package/.beads/issues.jsonl +0 -60
  357. package/.beads/metadata.json +0 -4
  358. package/docs/docs.html +0 -224
  359. package/docs/mcp-cheatsheet.md +0 -324
  360. package/docs/visual-overview.md +0 -21
  361. package/ref-monty/.cargo/config.toml +0 -3
  362. package/ref-monty/.claude/settings.json +0 -60
  363. package/ref-monty/.claude/skills/fastmod/SKILL.md +0 -22
  364. package/ref-monty/.claude/skills/python-playground/SKILL.md +0 -47
  365. package/ref-monty/.codecov.yml +0 -12
  366. package/ref-monty/.github/actions/build-pgo-wheel/action.yml +0 -72
  367. package/ref-monty/.github/workflows/ci.yml +0 -776
  368. package/ref-monty/.github/workflows/codspeed.yml +0 -45
  369. package/ref-monty/.github/workflows/init-npm-packages.yml +0 -82
  370. package/ref-monty/.pre-commit-config.yaml +0 -47
  371. package/ref-monty/.python-version +0 -1
  372. package/ref-monty/.rustfmt.toml +0 -4
  373. package/ref-monty/.zed/settings.json +0 -11
  374. package/ref-monty/CLAUDE.md +0 -535
  375. package/ref-monty/Cargo.lock +0 -3798
  376. package/ref-monty/Cargo.toml +0 -87
  377. package/ref-monty/LICENSE +0 -21
  378. package/ref-monty/Makefile +0 -216
  379. package/ref-monty/README.md +0 -430
  380. package/ref-monty/RELEASING.md +0 -47
  381. package/ref-monty/crates/fuzz/Cargo.toml +0 -30
  382. package/ref-monty/crates/fuzz/fuzz_targets/string_input_panic.rs +0 -37
  383. package/ref-monty/crates/fuzz/fuzz_targets/tokens_input_panic.rs +0 -552
  384. package/ref-monty/crates/monty/Cargo.toml +0 -68
  385. package/ref-monty/crates/monty/benches/main.rs +0 -247
  386. package/ref-monty/crates/monty/build.rs +0 -10
  387. package/ref-monty/crates/monty/src/args.rs +0 -733
  388. package/ref-monty/crates/monty/src/asyncio.rs +0 -179
  389. package/ref-monty/crates/monty/src/builtins/abs.rs +0 -55
  390. package/ref-monty/crates/monty/src/builtins/all.rs +0 -30
  391. package/ref-monty/crates/monty/src/builtins/any.rs +0 -30
  392. package/ref-monty/crates/monty/src/builtins/bin.rs +0 -59
  393. package/ref-monty/crates/monty/src/builtins/chr.rs +0 -46
  394. package/ref-monty/crates/monty/src/builtins/divmod.rs +0 -164
  395. package/ref-monty/crates/monty/src/builtins/enumerate.rs +0 -52
  396. package/ref-monty/crates/monty/src/builtins/filter.rs +0 -67
  397. package/ref-monty/crates/monty/src/builtins/getattr.rs +0 -65
  398. package/ref-monty/crates/monty/src/builtins/hash.rs +0 -28
  399. package/ref-monty/crates/monty/src/builtins/hex.rs +0 -58
  400. package/ref-monty/crates/monty/src/builtins/id.rs +0 -24
  401. package/ref-monty/crates/monty/src/builtins/isinstance.rs +0 -68
  402. package/ref-monty/crates/monty/src/builtins/len.rs +0 -25
  403. package/ref-monty/crates/monty/src/builtins/map.rs +0 -98
  404. package/ref-monty/crates/monty/src/builtins/min_max.rs +0 -113
  405. package/ref-monty/crates/monty/src/builtins/mod.rs +0 -246
  406. package/ref-monty/crates/monty/src/builtins/next.rs +0 -21
  407. package/ref-monty/crates/monty/src/builtins/oct.rs +0 -59
  408. package/ref-monty/crates/monty/src/builtins/ord.rs +0 -67
  409. package/ref-monty/crates/monty/src/builtins/pow.rs +0 -365
  410. package/ref-monty/crates/monty/src/builtins/print.rs +0 -141
  411. package/ref-monty/crates/monty/src/builtins/repr.rs +0 -16
  412. package/ref-monty/crates/monty/src/builtins/reversed.rs +0 -28
  413. package/ref-monty/crates/monty/src/builtins/round.rs +0 -174
  414. package/ref-monty/crates/monty/src/builtins/sorted.rs +0 -151
  415. package/ref-monty/crates/monty/src/builtins/sum.rs +0 -66
  416. package/ref-monty/crates/monty/src/builtins/type_.rs +0 -16
  417. package/ref-monty/crates/monty/src/builtins/zip.rs +0 -77
  418. package/ref-monty/crates/monty/src/bytecode/builder.rs +0 -699
  419. package/ref-monty/crates/monty/src/bytecode/code.rs +0 -310
  420. package/ref-monty/crates/monty/src/bytecode/compiler.rs +0 -3206
  421. package/ref-monty/crates/monty/src/bytecode/mod.rs +0 -24
  422. package/ref-monty/crates/monty/src/bytecode/op.rs +0 -617
  423. package/ref-monty/crates/monty/src/bytecode/vm/async_exec.rs +0 -1058
  424. package/ref-monty/crates/monty/src/bytecode/vm/attr.rs +0 -63
  425. package/ref-monty/crates/monty/src/bytecode/vm/binary.rs +0 -487
  426. package/ref-monty/crates/monty/src/bytecode/vm/call.rs +0 -767
  427. package/ref-monty/crates/monty/src/bytecode/vm/collections.rs +0 -741
  428. package/ref-monty/crates/monty/src/bytecode/vm/compare.rs +0 -147
  429. package/ref-monty/crates/monty/src/bytecode/vm/exceptions.rs +0 -297
  430. package/ref-monty/crates/monty/src/bytecode/vm/format.rs +0 -132
  431. package/ref-monty/crates/monty/src/bytecode/vm/mod.rs +0 -1958
  432. package/ref-monty/crates/monty/src/bytecode/vm/scheduler.rs +0 -620
  433. package/ref-monty/crates/monty/src/exception_private.rs +0 -1513
  434. package/ref-monty/crates/monty/src/exception_public.rs +0 -346
  435. package/ref-monty/crates/monty/src/expressions.rs +0 -694
  436. package/ref-monty/crates/monty/src/fstring.rs +0 -854
  437. package/ref-monty/crates/monty/src/function.rs +0 -119
  438. package/ref-monty/crates/monty/src/heap.rs +0 -1073
  439. package/ref-monty/crates/monty/src/heap_data.rs +0 -985
  440. package/ref-monty/crates/monty/src/heap_traits.rs +0 -312
  441. package/ref-monty/crates/monty/src/intern.rs +0 -837
  442. package/ref-monty/crates/monty/src/io.rs +0 -106
  443. package/ref-monty/crates/monty/src/lib.rs +0 -52
  444. package/ref-monty/crates/monty/src/modules/asyncio.rs +0 -144
  445. package/ref-monty/crates/monty/src/modules/math.rs +0 -1453
  446. package/ref-monty/crates/monty/src/modules/mod.rs +0 -120
  447. package/ref-monty/crates/monty/src/modules/os.rs +0 -116
  448. package/ref-monty/crates/monty/src/modules/pathlib.rs +0 -33
  449. package/ref-monty/crates/monty/src/modules/re.rs +0 -606
  450. package/ref-monty/crates/monty/src/modules/sys.rs +0 -60
  451. package/ref-monty/crates/monty/src/modules/typing.rs +0 -70
  452. package/ref-monty/crates/monty/src/namespace.rs +0 -21
  453. package/ref-monty/crates/monty/src/object.rs +0 -1040
  454. package/ref-monty/crates/monty/src/os.rs +0 -215
  455. package/ref-monty/crates/monty/src/parse.rs +0 -1730
  456. package/ref-monty/crates/monty/src/prepare.rs +0 -3015
  457. package/ref-monty/crates/monty/src/repl.rs +0 -1109
  458. package/ref-monty/crates/monty/src/resource.rs +0 -559
  459. package/ref-monty/crates/monty/src/run.rs +0 -457
  460. package/ref-monty/crates/monty/src/run_progress.rs +0 -821
  461. package/ref-monty/crates/monty/src/signature.rs +0 -651
  462. package/ref-monty/crates/monty/src/sorting.rs +0 -100
  463. package/ref-monty/crates/monty/src/types/bytes.rs +0 -2356
  464. package/ref-monty/crates/monty/src/types/dataclass.rs +0 -345
  465. package/ref-monty/crates/monty/src/types/dict.rs +0 -879
  466. package/ref-monty/crates/monty/src/types/dict_view.rs +0 -619
  467. package/ref-monty/crates/monty/src/types/iter.rs +0 -799
  468. package/ref-monty/crates/monty/src/types/list.rs +0 -929
  469. package/ref-monty/crates/monty/src/types/long_int.rs +0 -211
  470. package/ref-monty/crates/monty/src/types/mod.rs +0 -48
  471. package/ref-monty/crates/monty/src/types/module.rs +0 -146
  472. package/ref-monty/crates/monty/src/types/namedtuple.rs +0 -261
  473. package/ref-monty/crates/monty/src/types/path.rs +0 -596
  474. package/ref-monty/crates/monty/src/types/property.rs +0 -35
  475. package/ref-monty/crates/monty/src/types/py_trait.rs +0 -322
  476. package/ref-monty/crates/monty/src/types/range.rs +0 -285
  477. package/ref-monty/crates/monty/src/types/re_match.rs +0 -522
  478. package/ref-monty/crates/monty/src/types/re_pattern.rs +0 -726
  479. package/ref-monty/crates/monty/src/types/set.rs +0 -1373
  480. package/ref-monty/crates/monty/src/types/slice.rs +0 -257
  481. package/ref-monty/crates/monty/src/types/str.rs +0 -2051
  482. package/ref-monty/crates/monty/src/types/tuple.rs +0 -376
  483. package/ref-monty/crates/monty/src/types/type.rs +0 -407
  484. package/ref-monty/crates/monty/src/value.rs +0 -2558
  485. package/ref-monty/crates/monty/test_cases/args__dict_get_no_args.py +0 -3
  486. package/ref-monty/crates/monty/test_cases/args__dict_get_too_many.py +0 -3
  487. package/ref-monty/crates/monty/test_cases/args__dict_items_with_args.py +0 -3
  488. package/ref-monty/crates/monty/test_cases/args__dict_keys_with_args.py +0 -3
  489. package/ref-monty/crates/monty/test_cases/args__dict_pop_no_args.py +0 -3
  490. package/ref-monty/crates/monty/test_cases/args__dict_pop_too_many.py +0 -3
  491. package/ref-monty/crates/monty/test_cases/args__dict_values_with_args.py +0 -3
  492. package/ref-monty/crates/monty/test_cases/args__id_too_many.py +0 -2
  493. package/ref-monty/crates/monty/test_cases/args__len_no_args.py +0 -2
  494. package/ref-monty/crates/monty/test_cases/args__len_too_many.py +0 -2
  495. package/ref-monty/crates/monty/test_cases/args__len_type_error_int.py +0 -9
  496. package/ref-monty/crates/monty/test_cases/args__len_type_error_none.py +0 -9
  497. package/ref-monty/crates/monty/test_cases/args__list_append_no_args.py +0 -3
  498. package/ref-monty/crates/monty/test_cases/args__list_append_too_many.py +0 -3
  499. package/ref-monty/crates/monty/test_cases/args__list_insert_too_few.py +0 -3
  500. package/ref-monty/crates/monty/test_cases/args__list_insert_too_many.py +0 -3
  501. package/ref-monty/crates/monty/test_cases/args__repr_no_args.py +0 -2
  502. package/ref-monty/crates/monty/test_cases/arith__div_zero_float.py +0 -2
  503. package/ref-monty/crates/monty/test_cases/arith__div_zero_int.py +0 -2
  504. package/ref-monty/crates/monty/test_cases/arith__floordiv_zero_float.py +0 -2
  505. package/ref-monty/crates/monty/test_cases/arith__floordiv_zero_int.py +0 -2
  506. package/ref-monty/crates/monty/test_cases/arith__pow_zero_neg.py +0 -2
  507. package/ref-monty/crates/monty/test_cases/arith__pow_zero_neg_builtin.py +0 -9
  508. package/ref-monty/crates/monty/test_cases/assert__expr_fail.py +0 -2
  509. package/ref-monty/crates/monty/test_cases/assert__fail.py +0 -2
  510. package/ref-monty/crates/monty/test_cases/assert__fail_msg.py +0 -2
  511. package/ref-monty/crates/monty/test_cases/assert__fn_fail.py +0 -3
  512. package/ref-monty/crates/monty/test_cases/assert__ops.py +0 -11
  513. package/ref-monty/crates/monty/test_cases/async__asyncio_run.py +0 -47
  514. package/ref-monty/crates/monty/test_cases/async__basic.py +0 -10
  515. package/ref-monty/crates/monty/test_cases/async__closure.py +0 -14
  516. package/ref-monty/crates/monty/test_cases/async__double_await_coroutine.py +0 -16
  517. package/ref-monty/crates/monty/test_cases/async__exception.py +0 -10
  518. package/ref-monty/crates/monty/test_cases/async__ext_call.py +0 -73
  519. package/ref-monty/crates/monty/test_cases/async__gather_all.py +0 -85
  520. package/ref-monty/crates/monty/test_cases/async__nested_await.py +0 -15
  521. package/ref-monty/crates/monty/test_cases/async__nested_gather_ext.py +0 -37
  522. package/ref-monty/crates/monty/test_cases/async__not_awaitable.py +0 -10
  523. package/ref-monty/crates/monty/test_cases/async__not_imported.py +0 -14
  524. package/ref-monty/crates/monty/test_cases/async__recursion_depth_isolation.py +0 -27
  525. package/ref-monty/crates/monty/test_cases/async__return_types.py +0 -31
  526. package/ref-monty/crates/monty/test_cases/async__sequential.py +0 -16
  527. package/ref-monty/crates/monty/test_cases/async__traceback.py +0 -19
  528. package/ref-monty/crates/monty/test_cases/async__with_args.py +0 -14
  529. package/ref-monty/crates/monty/test_cases/attr__get_int_error.py +0 -9
  530. package/ref-monty/crates/monty/test_cases/attr__get_list_error.py +0 -9
  531. package/ref-monty/crates/monty/test_cases/attr__set_frozen_nonfield.py +0 -12
  532. package/ref-monty/crates/monty/test_cases/attr__set_int_error.py +0 -10
  533. package/ref-monty/crates/monty/test_cases/attr__set_list_error.py +0 -10
  534. package/ref-monty/crates/monty/test_cases/bench__kitchen_sink.py +0 -68
  535. package/ref-monty/crates/monty/test_cases/bool__ops.py +0 -20
  536. package/ref-monty/crates/monty/test_cases/builtin__add_type_error.py +0 -2
  537. package/ref-monty/crates/monty/test_cases/builtin__filter.py +0 -62
  538. package/ref-monty/crates/monty/test_cases/builtin__filter_not_iterable.py +0 -11
  539. package/ref-monty/crates/monty/test_cases/builtin__getattr.py +0 -84
  540. package/ref-monty/crates/monty/test_cases/builtin__iter_funcs.py +0 -42
  541. package/ref-monty/crates/monty/test_cases/builtin__iter_next.py +0 -66
  542. package/ref-monty/crates/monty/test_cases/builtin__map.py +0 -74
  543. package/ref-monty/crates/monty/test_cases/builtin__map_not_iterable.py +0 -11
  544. package/ref-monty/crates/monty/test_cases/builtin__math_funcs.py +0 -154
  545. package/ref-monty/crates/monty/test_cases/builtin__more_iter_funcs.py +0 -148
  546. package/ref-monty/crates/monty/test_cases/builtin__next_stop_iteration.py +0 -10
  547. package/ref-monty/crates/monty/test_cases/builtin__print_invalid_kwarg.py +0 -9
  548. package/ref-monty/crates/monty/test_cases/builtin__print_kwargs.py +0 -12
  549. package/ref-monty/crates/monty/test_cases/builtin__repr.py +0 -3
  550. package/ref-monty/crates/monty/test_cases/builtin__string_funcs.py +0 -73
  551. package/ref-monty/crates/monty/test_cases/bytes__decode_invalid_utf8.py +0 -18
  552. package/ref-monty/crates/monty/test_cases/bytes__endswith_str_error.py +0 -10
  553. package/ref-monty/crates/monty/test_cases/bytes__getitem_index_error.py +0 -10
  554. package/ref-monty/crates/monty/test_cases/bytes__index_start_gt_end.py +0 -10
  555. package/ref-monty/crates/monty/test_cases/bytes__methods.py +0 -394
  556. package/ref-monty/crates/monty/test_cases/bytes__negative_count.py +0 -9
  557. package/ref-monty/crates/monty/test_cases/bytes__ops.py +0 -90
  558. package/ref-monty/crates/monty/test_cases/bytes__startswith_str_error.py +0 -10
  559. package/ref-monty/crates/monty/test_cases/call_object.py +0 -3
  560. package/ref-monty/crates/monty/test_cases/chain_comparison__all.py +0 -79
  561. package/ref-monty/crates/monty/test_cases/closure__param_shadows_outer.py +0 -81
  562. package/ref-monty/crates/monty/test_cases/closure__pep448.py +0 -203
  563. package/ref-monty/crates/monty/test_cases/closure__undefined_nonlocal.py +0 -13
  564. package/ref-monty/crates/monty/test_cases/compare__mixed_types.py +0 -120
  565. package/ref-monty/crates/monty/test_cases/comprehension__all.py +0 -208
  566. package/ref-monty/crates/monty/test_cases/comprehension__scope.py +0 -7
  567. package/ref-monty/crates/monty/test_cases/comprehension__unbound_local.py +0 -14
  568. package/ref-monty/crates/monty/test_cases/dataclass__basic.py +0 -238
  569. package/ref-monty/crates/monty/test_cases/dataclass__call_field_error.py +0 -12
  570. package/ref-monty/crates/monty/test_cases/dataclass__frozen_set_error.py +0 -12
  571. package/ref-monty/crates/monty/test_cases/dataclass__get_missing_attr_error.py +0 -11
  572. package/ref-monty/crates/monty/test_cases/dict__get_unhashable_key.py +0 -3
  573. package/ref-monty/crates/monty/test_cases/dict__literal_unhashable_key.py +0 -2
  574. package/ref-monty/crates/monty/test_cases/dict__method_pop_missing_error.py +0 -3
  575. package/ref-monty/crates/monty/test_cases/dict__methods.py +0 -151
  576. package/ref-monty/crates/monty/test_cases/dict__ops.py +0 -133
  577. package/ref-monty/crates/monty/test_cases/dict__pop_unhashable_key.py +0 -4
  578. package/ref-monty/crates/monty/test_cases/dict__popitem_empty.py +0 -9
  579. package/ref-monty/crates/monty/test_cases/dict__subscript_missing_key.py +0 -3
  580. package/ref-monty/crates/monty/test_cases/dict__unhashable_dict_key.py +0 -2
  581. package/ref-monty/crates/monty/test_cases/dict__unhashable_list_key.py +0 -2
  582. package/ref-monty/crates/monty/test_cases/dict__unpack_type_error.py +0 -2
  583. package/ref-monty/crates/monty/test_cases/dict__views.py +0 -165
  584. package/ref-monty/crates/monty/test_cases/edge__all.py +0 -26
  585. package/ref-monty/crates/monty/test_cases/edge__float_int_mod.py +0 -2
  586. package/ref-monty/crates/monty/test_cases/edge__int_float_mod.py +0 -2
  587. package/ref-monty/crates/monty/test_cases/exc__args.py +0 -16
  588. package/ref-monty/crates/monty/test_cases/exc__str.py +0 -15
  589. package/ref-monty/crates/monty/test_cases/execute_ok__all.py +0 -54
  590. package/ref-monty/crates/monty/test_cases/execute_raise__error_instance_str.py +0 -2
  591. package/ref-monty/crates/monty/test_cases/execute_raise__error_no_args.py +0 -2
  592. package/ref-monty/crates/monty/test_cases/execute_raise__error_string_arg.py +0 -2
  593. package/ref-monty/crates/monty/test_cases/execute_raise__error_string_arg_quotes.py +0 -2
  594. package/ref-monty/crates/monty/test_cases/execute_raise__error_type.py +0 -2
  595. package/ref-monty/crates/monty/test_cases/execute_raise__raise_instance_via_var.py +0 -4
  596. package/ref-monty/crates/monty/test_cases/execute_raise__raise_list.py +0 -2
  597. package/ref-monty/crates/monty/test_cases/execute_raise__raise_number.py +0 -2
  598. package/ref-monty/crates/monty/test_cases/execute_raise__raise_type_call_via_var.py +0 -4
  599. package/ref-monty/crates/monty/test_cases/execute_raise__raise_type_direct.py +0 -3
  600. package/ref-monty/crates/monty/test_cases/execute_raise__raise_type_via_var.py +0 -4
  601. package/ref-monty/crates/monty/test_cases/ext_call__arg_side_effect_bug.py +0 -22
  602. package/ref-monty/crates/monty/test_cases/ext_call__augmented.py +0 -17
  603. package/ref-monty/crates/monty/test_cases/ext_call__augmented_refcount_bug.py +0 -7
  604. package/ref-monty/crates/monty/test_cases/ext_call__bare_raise_after_resume.py +0 -34
  605. package/ref-monty/crates/monty/test_cases/ext_call__basic.py +0 -99
  606. package/ref-monty/crates/monty/test_cases/ext_call__boolean.py +0 -37
  607. package/ref-monty/crates/monty/test_cases/ext_call__boolean_side_effect_hang.py +0 -17
  608. package/ref-monty/crates/monty/test_cases/ext_call__closure_bug.py +0 -16
  609. package/ref-monty/crates/monty/test_cases/ext_call__comparison.py +0 -26
  610. package/ref-monty/crates/monty/test_cases/ext_call__deep_call_stack.py +0 -18
  611. package/ref-monty/crates/monty/test_cases/ext_call__elif.py +0 -171
  612. package/ref-monty/crates/monty/test_cases/ext_call__exc.py +0 -4
  613. package/ref-monty/crates/monty/test_cases/ext_call__exc_deep_stack.py +0 -39
  614. package/ref-monty/crates/monty/test_cases/ext_call__exc_in_function.py +0 -17
  615. package/ref-monty/crates/monty/test_cases/ext_call__exc_nested_functions.py +0 -31
  616. package/ref-monty/crates/monty/test_cases/ext_call__ext_exc.py +0 -171
  617. package/ref-monty/crates/monty/test_cases/ext_call__for.py +0 -114
  618. package/ref-monty/crates/monty/test_cases/ext_call__fstring.py +0 -12
  619. package/ref-monty/crates/monty/test_cases/ext_call__if.py +0 -135
  620. package/ref-monty/crates/monty/test_cases/ext_call__if_condition.py +0 -37
  621. package/ref-monty/crates/monty/test_cases/ext_call__in_closure.py +0 -14
  622. package/ref-monty/crates/monty/test_cases/ext_call__in_function.py +0 -40
  623. package/ref-monty/crates/monty/test_cases/ext_call__in_function_simple.py +0 -7
  624. package/ref-monty/crates/monty/test_cases/ext_call__literals.py +0 -17
  625. package/ref-monty/crates/monty/test_cases/ext_call__multi_in_func.py +0 -32
  626. package/ref-monty/crates/monty/test_cases/ext_call__name_lookup.py +0 -69
  627. package/ref-monty/crates/monty/test_cases/ext_call__name_lookup_undefined.py +0 -4
  628. package/ref-monty/crates/monty/test_cases/ext_call__nested_calls.py +0 -14
  629. package/ref-monty/crates/monty/test_cases/ext_call__recursion_bug.py +0 -19
  630. package/ref-monty/crates/monty/test_cases/ext_call__return.py +0 -28
  631. package/ref-monty/crates/monty/test_cases/ext_call__side_effects.py +0 -25
  632. package/ref-monty/crates/monty/test_cases/ext_call__subscript.py +0 -7
  633. package/ref-monty/crates/monty/test_cases/ext_call__ternary.py +0 -28
  634. package/ref-monty/crates/monty/test_cases/ext_call__try.py +0 -280
  635. package/ref-monty/crates/monty/test_cases/ext_call__try_simple.py +0 -10
  636. package/ref-monty/crates/monty/test_cases/ext_call__unary.py +0 -13
  637. package/ref-monty/crates/monty/test_cases/frozenset__ops.py +0 -178
  638. package/ref-monty/crates/monty/test_cases/fstring__all.py +0 -236
  639. package/ref-monty/crates/monty/test_cases/fstring__error_eq_align_on_str.py +0 -3
  640. package/ref-monty/crates/monty/test_cases/fstring__error_float_f_on_str.py +0 -3
  641. package/ref-monty/crates/monty/test_cases/fstring__error_int_d_on_float.py +0 -3
  642. package/ref-monty/crates/monty/test_cases/fstring__error_int_d_on_str.py +0 -3
  643. package/ref-monty/crates/monty/test_cases/fstring__error_invalid_spec.py +0 -4
  644. package/ref-monty/crates/monty/test_cases/fstring__error_invalid_spec_dynamic.py +0 -4
  645. package/ref-monty/crates/monty/test_cases/fstring__error_invalid_spec_str.py +0 -4
  646. package/ref-monty/crates/monty/test_cases/fstring__error_str_s_on_int.py +0 -3
  647. package/ref-monty/crates/monty/test_cases/function__call_duplicate_kwargs.py +0 -6
  648. package/ref-monty/crates/monty/test_cases/function__call_unpack.py +0 -42
  649. package/ref-monty/crates/monty/test_cases/function__defaults.py +0 -117
  650. package/ref-monty/crates/monty/test_cases/function__err_duplicate_arg.py +0 -7
  651. package/ref-monty/crates/monty/test_cases/function__err_duplicate_first_arg.py +0 -7
  652. package/ref-monty/crates/monty/test_cases/function__err_duplicate_kwarg_cleanup.py +0 -9
  653. package/ref-monty/crates/monty/test_cases/function__err_kwonly_as_positional.py +0 -7
  654. package/ref-monty/crates/monty/test_cases/function__err_missing_all_posonly.py +0 -7
  655. package/ref-monty/crates/monty/test_cases/function__err_missing_heap_cleanup.py +0 -9
  656. package/ref-monty/crates/monty/test_cases/function__err_missing_kwonly.py +0 -7
  657. package/ref-monty/crates/monty/test_cases/function__err_missing_posonly_with_kwarg.py +0 -7
  658. package/ref-monty/crates/monty/test_cases/function__err_missing_with_posonly.py +0 -7
  659. package/ref-monty/crates/monty/test_cases/function__err_posonly_as_kwarg.py +0 -7
  660. package/ref-monty/crates/monty/test_cases/function__err_posonly_first_as_kwarg.py +0 -7
  661. package/ref-monty/crates/monty/test_cases/function__err_too_many_posonly.py +0 -7
  662. package/ref-monty/crates/monty/test_cases/function__err_too_many_with_kwonly.py +0 -7
  663. package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg.py +0 -7
  664. package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg_cleanup.py +0 -9
  665. package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg_quote.py +0 -13
  666. package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg_simple.py +0 -7
  667. package/ref-monty/crates/monty/test_cases/function__err_unpack_duplicate_arg.py +0 -6
  668. package/ref-monty/crates/monty/test_cases/function__err_unpack_duplicate_heap.py +0 -8
  669. package/ref-monty/crates/monty/test_cases/function__err_unpack_int.py +0 -6
  670. package/ref-monty/crates/monty/test_cases/function__err_unpack_nonstring_key.py +0 -6
  671. package/ref-monty/crates/monty/test_cases/function__err_unpack_not_mapping.py +0 -6
  672. package/ref-monty/crates/monty/test_cases/function__kwargs_unpacking.py +0 -173
  673. package/ref-monty/crates/monty/test_cases/function__ops.py +0 -294
  674. package/ref-monty/crates/monty/test_cases/function__return_none.py +0 -42
  675. package/ref-monty/crates/monty/test_cases/function__signatures.py +0 -47
  676. package/ref-monty/crates/monty/test_cases/function__too_few_args_all.py +0 -6
  677. package/ref-monty/crates/monty/test_cases/function__too_few_args_one.py +0 -6
  678. package/ref-monty/crates/monty/test_cases/function__too_few_args_two.py +0 -6
  679. package/ref-monty/crates/monty/test_cases/function__too_many_args_one.py +0 -6
  680. package/ref-monty/crates/monty/test_cases/function__too_many_args_two.py +0 -6
  681. package/ref-monty/crates/monty/test_cases/function__too_many_args_zero.py +0 -6
  682. package/ref-monty/crates/monty/test_cases/global__error_assigned_before.py +0 -7
  683. package/ref-monty/crates/monty/test_cases/global__ops.py +0 -163
  684. package/ref-monty/crates/monty/test_cases/hash__dict_unhashable.py +0 -2
  685. package/ref-monty/crates/monty/test_cases/hash__list_unhashable.py +0 -2
  686. package/ref-monty/crates/monty/test_cases/hash__ops.py +0 -153
  687. package/ref-monty/crates/monty/test_cases/id__bytes_literals_distinct.py +0 -3
  688. package/ref-monty/crates/monty/test_cases/id__int_copy_distinct.py +0 -5
  689. package/ref-monty/crates/monty/test_cases/id__is_number_is_number.py +0 -3
  690. package/ref-monty/crates/monty/test_cases/id__non_overlapping_lifetimes_distinct_types.py +0 -10
  691. package/ref-monty/crates/monty/test_cases/id__non_overlapping_lifetimes_same_types.py +0 -6
  692. package/ref-monty/crates/monty/test_cases/id__ops.py +0 -97
  693. package/ref-monty/crates/monty/test_cases/id__str_literals_same.py +0 -3
  694. package/ref-monty/crates/monty/test_cases/if__elif_else.py +0 -207
  695. package/ref-monty/crates/monty/test_cases/if__raise_elif.py +0 -11
  696. package/ref-monty/crates/monty/test_cases/if__raise_else.py +0 -13
  697. package/ref-monty/crates/monty/test_cases/if__raise_if.py +0 -9
  698. package/ref-monty/crates/monty/test_cases/if__raise_in_elif_condition.py +0 -18
  699. package/ref-monty/crates/monty/test_cases/if__raise_in_if_condition.py +0 -16
  700. package/ref-monty/crates/monty/test_cases/if_else_expr__all.py +0 -55
  701. package/ref-monty/crates/monty/test_cases/import__error_cannot_import.py +0 -9
  702. package/ref-monty/crates/monty/test_cases/import__error_module_not_found.py +0 -9
  703. package/ref-monty/crates/monty/test_cases/import__local_scope.py +0 -68
  704. package/ref-monty/crates/monty/test_cases/import__os.py +0 -25
  705. package/ref-monty/crates/monty/test_cases/import__relative_error.py +0 -9
  706. package/ref-monty/crates/monty/test_cases/import__relative_no_module_error.py +0 -9
  707. package/ref-monty/crates/monty/test_cases/import__runtime_error_when_executed.py +0 -14
  708. package/ref-monty/crates/monty/test_cases/import__star_error.py +0 -11
  709. package/ref-monty/crates/monty/test_cases/import__sys.py +0 -47
  710. package/ref-monty/crates/monty/test_cases/import__sys_monty.py +0 -28
  711. package/ref-monty/crates/monty/test_cases/import__type_checking_guard.py +0 -37
  712. package/ref-monty/crates/monty/test_cases/import__typing.py +0 -25
  713. package/ref-monty/crates/monty/test_cases/import__typing_type_ignore.py +0 -4
  714. package/ref-monty/crates/monty/test_cases/int__bigint.py +0 -467
  715. package/ref-monty/crates/monty/test_cases/int__bigint_errors.py +0 -260
  716. package/ref-monty/crates/monty/test_cases/int__ops.py +0 -219
  717. package/ref-monty/crates/monty/test_cases/int__overflow_division.py +0 -84
  718. package/ref-monty/crates/monty/test_cases/is_variant__all.py +0 -36
  719. package/ref-monty/crates/monty/test_cases/isinstance__arg2_list_error.py +0 -2
  720. package/ref-monty/crates/monty/test_cases/isinstance__arg2_type_error.py +0 -2
  721. package/ref-monty/crates/monty/test_cases/iter__dict_mutation.py +0 -4
  722. package/ref-monty/crates/monty/test_cases/iter__for.py +0 -243
  723. package/ref-monty/crates/monty/test_cases/iter__for_loop_unpacking.py +0 -66
  724. package/ref-monty/crates/monty/test_cases/iter__generator_expr.py +0 -20
  725. package/ref-monty/crates/monty/test_cases/iter__generator_expr_type.py +0 -7
  726. package/ref-monty/crates/monty/test_cases/iter__not_iterable.py +0 -3
  727. package/ref-monty/crates/monty/test_cases/lambda__all.py +0 -145
  728. package/ref-monty/crates/monty/test_cases/list__extend_not_iterable.py +0 -7
  729. package/ref-monty/crates/monty/test_cases/list__getitem_out_of_bounds.py +0 -3
  730. package/ref-monty/crates/monty/test_cases/list__index_not_found.py +0 -9
  731. package/ref-monty/crates/monty/test_cases/list__index_start_gt_end.py +0 -10
  732. package/ref-monty/crates/monty/test_cases/list__ops.py +0 -473
  733. package/ref-monty/crates/monty/test_cases/list__pop_empty.py +0 -9
  734. package/ref-monty/crates/monty/test_cases/list__pop_out_of_range.py +0 -9
  735. package/ref-monty/crates/monty/test_cases/list__pop_type_error.py +0 -9
  736. package/ref-monty/crates/monty/test_cases/list__remove_not_found.py +0 -9
  737. package/ref-monty/crates/monty/test_cases/list__setitem_dict_index.py +0 -13
  738. package/ref-monty/crates/monty/test_cases/list__setitem_huge_int_index.py +0 -13
  739. package/ref-monty/crates/monty/test_cases/list__setitem_index_error.py +0 -10
  740. package/ref-monty/crates/monty/test_cases/list__setitem_type_error.py +0 -10
  741. package/ref-monty/crates/monty/test_cases/list__unpack_type_error.py +0 -2
  742. package/ref-monty/crates/monty/test_cases/longint__index_error.py +0 -3
  743. package/ref-monty/crates/monty/test_cases/longint__repeat_error.py +0 -3
  744. package/ref-monty/crates/monty/test_cases/loop__break_continue.py +0 -113
  745. package/ref-monty/crates/monty/test_cases/loop__break_finally.py +0 -69
  746. package/ref-monty/crates/monty/test_cases/loop__break_in_function_error.py +0 -13
  747. package/ref-monty/crates/monty/test_cases/loop__break_in_if_error.py +0 -11
  748. package/ref-monty/crates/monty/test_cases/loop__break_nested_except_clears.py +0 -55
  749. package/ref-monty/crates/monty/test_cases/loop__break_outside_error.py +0 -9
  750. package/ref-monty/crates/monty/test_cases/loop__continue_finally.py +0 -81
  751. package/ref-monty/crates/monty/test_cases/loop__continue_in_function_error.py +0 -13
  752. package/ref-monty/crates/monty/test_cases/loop__continue_in_if_error.py +0 -11
  753. package/ref-monty/crates/monty/test_cases/loop__continue_nested_except_clears.py +0 -60
  754. package/ref-monty/crates/monty/test_cases/loop__continue_outside_error.py +0 -9
  755. package/ref-monty/crates/monty/test_cases/math__acos_domain_error.py +0 -11
  756. package/ref-monty/crates/monty/test_cases/math__acosh_domain_error.py +0 -11
  757. package/ref-monty/crates/monty/test_cases/math__asin_domain_error.py +0 -11
  758. package/ref-monty/crates/monty/test_cases/math__atanh_domain_error.py +0 -11
  759. package/ref-monty/crates/monty/test_cases/math__cos_inf_error.py +0 -11
  760. package/ref-monty/crates/monty/test_cases/math__cosh_overflow_error.py +0 -11
  761. package/ref-monty/crates/monty/test_cases/math__exp_overflow_error.py +0 -11
  762. package/ref-monty/crates/monty/test_cases/math__factorial_float_error.py +0 -11
  763. package/ref-monty/crates/monty/test_cases/math__factorial_negative_error.py +0 -11
  764. package/ref-monty/crates/monty/test_cases/math__floor_inf_error.py +0 -11
  765. package/ref-monty/crates/monty/test_cases/math__floor_nan_error.py +0 -11
  766. package/ref-monty/crates/monty/test_cases/math__floor_str_error.py +0 -11
  767. package/ref-monty/crates/monty/test_cases/math__fmod_inf_error.py +0 -11
  768. package/ref-monty/crates/monty/test_cases/math__gamma_neg_int_error.py +0 -11
  769. package/ref-monty/crates/monty/test_cases/math__gcd_float_error.py +0 -11
  770. package/ref-monty/crates/monty/test_cases/math__isqrt_negative_error.py +0 -11
  771. package/ref-monty/crates/monty/test_cases/math__ldexp_overflow_error.py +0 -11
  772. package/ref-monty/crates/monty/test_cases/math__log1p_domain_error.py +0 -11
  773. package/ref-monty/crates/monty/test_cases/math__log_base1_error.py +0 -11
  774. package/ref-monty/crates/monty/test_cases/math__log_zero_error.py +0 -11
  775. package/ref-monty/crates/monty/test_cases/math__module.py +0 -1432
  776. package/ref-monty/crates/monty/test_cases/math__pow_domain_error.py +0 -11
  777. package/ref-monty/crates/monty/test_cases/math__sin_inf_error.py +0 -11
  778. package/ref-monty/crates/monty/test_cases/math__sqrt_negative_error.py +0 -11
  779. package/ref-monty/crates/monty/test_cases/math__tan_inf_error.py +0 -11
  780. package/ref-monty/crates/monty/test_cases/math__trunc_str_error.py +0 -11
  781. package/ref-monty/crates/monty/test_cases/method__args_kwargs_unpacking.py +0 -259
  782. package/ref-monty/crates/monty/test_cases/name_error__unbound_local_func.py +0 -19
  783. package/ref-monty/crates/monty/test_cases/name_error__unbound_local_module.py +0 -12
  784. package/ref-monty/crates/monty/test_cases/name_error__undefined_call_chained.py +0 -9
  785. package/ref-monty/crates/monty/test_cases/name_error__undefined_call_in_expr.py +0 -9
  786. package/ref-monty/crates/monty/test_cases/name_error__undefined_call_in_function.py +0 -16
  787. package/ref-monty/crates/monty/test_cases/name_error__undefined_call_with_args.py +0 -9
  788. package/ref-monty/crates/monty/test_cases/name_error__undefined_global.py +0 -10
  789. package/ref-monty/crates/monty/test_cases/namedtuple__missing_attr.py +0 -11
  790. package/ref-monty/crates/monty/test_cases/namedtuple__ops.py +0 -34
  791. package/ref-monty/crates/monty/test_cases/nonlocal__error_module_level.py +0 -3
  792. package/ref-monty/crates/monty/test_cases/nonlocal__ops.py +0 -353
  793. package/ref-monty/crates/monty/test_cases/os__environ.py +0 -40
  794. package/ref-monty/crates/monty/test_cases/os__getenv_key_list_error.py +0 -5
  795. package/ref-monty/crates/monty/test_cases/os__getenv_key_type_error.py +0 -5
  796. package/ref-monty/crates/monty/test_cases/parse_error__complex.py +0 -3
  797. package/ref-monty/crates/monty/test_cases/pathlib__import.py +0 -11
  798. package/ref-monty/crates/monty/test_cases/pathlib__os.py +0 -136
  799. package/ref-monty/crates/monty/test_cases/pathlib__os_read_error.py +0 -12
  800. package/ref-monty/crates/monty/test_cases/pathlib__pure.py +0 -81
  801. package/ref-monty/crates/monty/test_cases/pyobject__cycle_dict_self.py +0 -5
  802. package/ref-monty/crates/monty/test_cases/pyobject__cycle_list_dict.py +0 -6
  803. package/ref-monty/crates/monty/test_cases/pyobject__cycle_list_self.py +0 -5
  804. package/ref-monty/crates/monty/test_cases/pyobject__cycle_multiple_refs.py +0 -6
  805. package/ref-monty/crates/monty/test_cases/range__error_no_args.py +0 -2
  806. package/ref-monty/crates/monty/test_cases/range__error_step_zero.py +0 -2
  807. package/ref-monty/crates/monty/test_cases/range__error_too_many_args.py +0 -2
  808. package/ref-monty/crates/monty/test_cases/range__getitem_index_error.py +0 -10
  809. package/ref-monty/crates/monty/test_cases/range__ops.py +0 -236
  810. package/ref-monty/crates/monty/test_cases/re__basic.py +0 -756
  811. package/ref-monty/crates/monty/test_cases/re__grouping.py +0 -241
  812. package/ref-monty/crates/monty/test_cases/re__match.py +0 -148
  813. package/ref-monty/crates/monty/test_cases/recursion__deep_drop.py +0 -26
  814. package/ref-monty/crates/monty/test_cases/recursion__deep_eq.py +0 -23
  815. package/ref-monty/crates/monty/test_cases/recursion__deep_hash.py +0 -46
  816. package/ref-monty/crates/monty/test_cases/recursion__deep_repr.py +0 -12
  817. package/ref-monty/crates/monty/test_cases/recursion__function_depth.py +0 -13
  818. package/ref-monty/crates/monty/test_cases/refcount__cycle_mutual_reference.py +0 -18
  819. package/ref-monty/crates/monty/test_cases/refcount__cycle_self_reference.py +0 -12
  820. package/ref-monty/crates/monty/test_cases/refcount__dict_basic.py +0 -5
  821. package/ref-monty/crates/monty/test_cases/refcount__dict_get.py +0 -5
  822. package/ref-monty/crates/monty/test_cases/refcount__dict_keys_and.py +0 -14
  823. package/ref-monty/crates/monty/test_cases/refcount__dict_overwrite.py +0 -6
  824. package/ref-monty/crates/monty/test_cases/refcount__gather_cleanup.py +0 -16
  825. package/ref-monty/crates/monty/test_cases/refcount__gather_exception.py +0 -18
  826. package/ref-monty/crates/monty/test_cases/refcount__gather_nested_cancel.py +0 -25
  827. package/ref-monty/crates/monty/test_cases/refcount__immediate_skipped.py +0 -4
  828. package/ref-monty/crates/monty/test_cases/refcount__kwargs_unpacking.py +0 -27
  829. package/ref-monty/crates/monty/test_cases/refcount__list_append_multiple.py +0 -6
  830. package/ref-monty/crates/monty/test_cases/refcount__list_append_ref.py +0 -5
  831. package/ref-monty/crates/monty/test_cases/refcount__list_concat.py +0 -5
  832. package/ref-monty/crates/monty/test_cases/refcount__list_getitem.py +0 -5
  833. package/ref-monty/crates/monty/test_cases/refcount__list_iadd.py +0 -5
  834. package/ref-monty/crates/monty/test_cases/refcount__nested_list.py +0 -4
  835. package/ref-monty/crates/monty/test_cases/refcount__re_pattern_sub_error_paths.py +0 -37
  836. package/ref-monty/crates/monty/test_cases/refcount__re_search_match.py +0 -34
  837. package/ref-monty/crates/monty/test_cases/refcount__re_sub_error_paths.py +0 -31
  838. package/ref-monty/crates/monty/test_cases/refcount__shared_reference.py +0 -4
  839. package/ref-monty/crates/monty/test_cases/refcount__single_list.py +0 -3
  840. package/ref-monty/crates/monty/test_cases/repr__cycle_detection.py +0 -24
  841. package/ref-monty/crates/monty/test_cases/set__ops.py +0 -191
  842. package/ref-monty/crates/monty/test_cases/set__review_bugs.py +0 -35
  843. package/ref-monty/crates/monty/test_cases/set__unpack_type_error.py +0 -2
  844. package/ref-monty/crates/monty/test_cases/slice__invalid_indices.py +0 -2
  845. package/ref-monty/crates/monty/test_cases/slice__kwargs.py +0 -9
  846. package/ref-monty/crates/monty/test_cases/slice__no_args.py +0 -9
  847. package/ref-monty/crates/monty/test_cases/slice__ops.py +0 -149
  848. package/ref-monty/crates/monty/test_cases/slice__step_zero.py +0 -9
  849. package/ref-monty/crates/monty/test_cases/slice__step_zero_bytes.py +0 -9
  850. package/ref-monty/crates/monty/test_cases/slice__step_zero_range.py +0 -9
  851. package/ref-monty/crates/monty/test_cases/slice__step_zero_str.py +0 -9
  852. package/ref-monty/crates/monty/test_cases/slice__step_zero_tuple.py +0 -9
  853. package/ref-monty/crates/monty/test_cases/slice__too_many_args.py +0 -9
  854. package/ref-monty/crates/monty/test_cases/str__getitem_index_error.py +0 -10
  855. package/ref-monty/crates/monty/test_cases/str__index_not_found.py +0 -9
  856. package/ref-monty/crates/monty/test_cases/str__join_no_args.py +0 -9
  857. package/ref-monty/crates/monty/test_cases/str__join_non_string.py +0 -9
  858. package/ref-monty/crates/monty/test_cases/str__join_not_iterable.py +0 -9
  859. package/ref-monty/crates/monty/test_cases/str__join_too_many_args.py +0 -9
  860. package/ref-monty/crates/monty/test_cases/str__methods.py +0 -327
  861. package/ref-monty/crates/monty/test_cases/str__ops.py +0 -162
  862. package/ref-monty/crates/monty/test_cases/str__partition_empty.py +0 -9
  863. package/ref-monty/crates/monty/test_cases/str__rsplit_empty_sep.py +0 -9
  864. package/ref-monty/crates/monty/test_cases/str__split_empty_sep.py +0 -9
  865. package/ref-monty/crates/monty/test_cases/sys__types.py +0 -7
  866. package/ref-monty/crates/monty/test_cases/traceback__division_error.py +0 -30
  867. package/ref-monty/crates/monty/test_cases/traceback__index_error.py +0 -17
  868. package/ref-monty/crates/monty/test_cases/traceback__insert_as_int.py +0 -10
  869. package/ref-monty/crates/monty/test_cases/traceback__nested_call.py +0 -29
  870. package/ref-monty/crates/monty/test_cases/traceback__nonlocal_module_scope.py +0 -10
  871. package/ref-monty/crates/monty/test_cases/traceback__nonlocal_unbound.py +0 -24
  872. package/ref-monty/crates/monty/test_cases/traceback__range_as_int.py +0 -9
  873. package/ref-monty/crates/monty/test_cases/traceback__recursion_error.py +0 -23
  874. package/ref-monty/crates/monty/test_cases/traceback__set_mutation.py +0 -11
  875. package/ref-monty/crates/monty/test_cases/traceback__undefined_attr_call.py +0 -16
  876. package/ref-monty/crates/monty/test_cases/traceback__undefined_call.py +0 -16
  877. package/ref-monty/crates/monty/test_cases/traceback__undefined_raise.py +0 -16
  878. package/ref-monty/crates/monty/test_cases/try_except__all.py +0 -472
  879. package/ref-monty/crates/monty/test_cases/try_except__bare_raise_no_context.py +0 -2
  880. package/ref-monty/crates/monty/test_cases/try_except__invalid_type.py +0 -5
  881. package/ref-monty/crates/monty/test_cases/tuple__getitem_out_of_bounds.py +0 -3
  882. package/ref-monty/crates/monty/test_cases/tuple__index_not_found.py +0 -9
  883. package/ref-monty/crates/monty/test_cases/tuple__index_start_gt_end.py +0 -10
  884. package/ref-monty/crates/monty/test_cases/tuple__methods.py +0 -19
  885. package/ref-monty/crates/monty/test_cases/tuple__ops.py +0 -133
  886. package/ref-monty/crates/monty/test_cases/tuple__unpack_type_error.py +0 -2
  887. package/ref-monty/crates/monty/test_cases/type__builtin_attr_error.py +0 -9
  888. package/ref-monty/crates/monty/test_cases/type__bytes_negative.py +0 -2
  889. package/ref-monty/crates/monty/test_cases/type__cell_not_builtin.py +0 -9
  890. package/ref-monty/crates/monty/test_cases/type__exception_attr_error.py +0 -11
  891. package/ref-monty/crates/monty/test_cases/type__float_conversion_error.py +0 -2
  892. package/ref-monty/crates/monty/test_cases/type__float_repr_both_quotes.py +0 -9
  893. package/ref-monty/crates/monty/test_cases/type__float_repr_newline.py +0 -9
  894. package/ref-monty/crates/monty/test_cases/type__float_repr_single_quote.py +0 -9
  895. package/ref-monty/crates/monty/test_cases/type__int_conversion_error.py +0 -2
  896. package/ref-monty/crates/monty/test_cases/type__list_not_iterable.py +0 -2
  897. package/ref-monty/crates/monty/test_cases/type__non_builtin_name_error.py +0 -9
  898. package/ref-monty/crates/monty/test_cases/type__ops.py +0 -200
  899. package/ref-monty/crates/monty/test_cases/type__shadow_exc.py +0 -3
  900. package/ref-monty/crates/monty/test_cases/type__shadow_int.py +0 -9
  901. package/ref-monty/crates/monty/test_cases/type__shadow_len.py +0 -3
  902. package/ref-monty/crates/monty/test_cases/type__tuple_not_iterable.py +0 -2
  903. package/ref-monty/crates/monty/test_cases/type_error__int_add_list.py +0 -2
  904. package/ref-monty/crates/monty/test_cases/type_error__int_div_str.py +0 -2
  905. package/ref-monty/crates/monty/test_cases/type_error__int_floordiv_str.py +0 -2
  906. package/ref-monty/crates/monty/test_cases/type_error__int_iadd_str.py +0 -3
  907. package/ref-monty/crates/monty/test_cases/type_error__int_mod_str.py +0 -2
  908. package/ref-monty/crates/monty/test_cases/type_error__int_pow_str.py +0 -2
  909. package/ref-monty/crates/monty/test_cases/type_error__int_sub_str.py +0 -2
  910. package/ref-monty/crates/monty/test_cases/type_error__list_add_int.py +0 -2
  911. package/ref-monty/crates/monty/test_cases/type_error__list_add_str.py +0 -2
  912. package/ref-monty/crates/monty/test_cases/type_error__list_iadd_int.py +0 -6
  913. package/ref-monty/crates/monty/test_cases/type_error__str_add_int.py +0 -2
  914. package/ref-monty/crates/monty/test_cases/type_error__str_iadd_int.py +0 -3
  915. package/ref-monty/crates/monty/test_cases/type_error__unary_invert_str.py +0 -3
  916. package/ref-monty/crates/monty/test_cases/type_error__unary_minus_str.py +0 -4
  917. package/ref-monty/crates/monty/test_cases/type_error__unary_neg_str.py +0 -3
  918. package/ref-monty/crates/monty/test_cases/type_error__unary_plus_str.py +0 -4
  919. package/ref-monty/crates/monty/test_cases/typing__types.py +0 -24
  920. package/ref-monty/crates/monty/test_cases/unpack__nested.py +0 -48
  921. package/ref-monty/crates/monty/test_cases/unpack__non_sequence.py +0 -9
  922. package/ref-monty/crates/monty/test_cases/unpack__not_enough.py +0 -9
  923. package/ref-monty/crates/monty/test_cases/unpack__ops.py +0 -153
  924. package/ref-monty/crates/monty/test_cases/unpack__star_not_enough.py +0 -9
  925. package/ref-monty/crates/monty/test_cases/unpack__too_many.py +0 -9
  926. package/ref-monty/crates/monty/test_cases/version__cpython.py +0 -4
  927. package/ref-monty/crates/monty/test_cases/walrus__all.py +0 -178
  928. package/ref-monty/crates/monty/test_cases/while__all.py +0 -206
  929. package/ref-monty/crates/monty/tests/asyncio.rs +0 -764
  930. package/ref-monty/crates/monty/tests/binary_serde.rs +0 -185
  931. package/ref-monty/crates/monty/tests/bytecode_limits.rs +0 -248
  932. package/ref-monty/crates/monty/tests/datatest_runner.rs +0 -2029
  933. package/ref-monty/crates/monty/tests/inputs.rs +0 -420
  934. package/ref-monty/crates/monty/tests/json_serde.rs +0 -250
  935. package/ref-monty/crates/monty/tests/main.rs +0 -71
  936. package/ref-monty/crates/monty/tests/math_module.rs +0 -114
  937. package/ref-monty/crates/monty/tests/name_lookup.rs +0 -482
  938. package/ref-monty/crates/monty/tests/os_tests.rs +0 -459
  939. package/ref-monty/crates/monty/tests/parse_errors.rs +0 -441
  940. package/ref-monty/crates/monty/tests/print_writer.rs +0 -238
  941. package/ref-monty/crates/monty/tests/py_object.rs +0 -121
  942. package/ref-monty/crates/monty/tests/regex.rs +0 -90
  943. package/ref-monty/crates/monty/tests/repl.rs +0 -344
  944. package/ref-monty/crates/monty/tests/resource_limits.rs +0 -1826
  945. package/ref-monty/crates/monty/tests/try_from.rs +0 -167
  946. package/ref-monty/crates/monty-cli/Cargo.toml +0 -25
  947. package/ref-monty/crates/monty-cli/src/main.rs +0 -541
  948. package/ref-monty/crates/monty-js/.cargo/config.toml +0 -2
  949. package/ref-monty/crates/monty-js/.prettierignore +0 -8
  950. package/ref-monty/crates/monty-js/Cargo.toml +0 -32
  951. package/ref-monty/crates/monty-js/README.md +0 -207
  952. package/ref-monty/crates/monty-js/__test__/async.spec.ts +0 -350
  953. package/ref-monty/crates/monty-js/__test__/basic.spec.ts +0 -114
  954. package/ref-monty/crates/monty-js/__test__/exceptions.spec.ts +0 -427
  955. package/ref-monty/crates/monty-js/__test__/external.spec.ts +0 -354
  956. package/ref-monty/crates/monty-js/__test__/inputs.spec.ts +0 -143
  957. package/ref-monty/crates/monty-js/__test__/limits.spec.ts +0 -162
  958. package/ref-monty/crates/monty-js/__test__/package.json +0 -3
  959. package/ref-monty/crates/monty-js/__test__/print.spec.ts +0 -229
  960. package/ref-monty/crates/monty-js/__test__/repl.spec.ts +0 -34
  961. package/ref-monty/crates/monty-js/__test__/serialize.spec.ts +0 -205
  962. package/ref-monty/crates/monty-js/__test__/start.spec.ts +0 -443
  963. package/ref-monty/crates/monty-js/__test__/type_check.spec.ts +0 -147
  964. package/ref-monty/crates/monty-js/__test__/types.spec.ts +0 -319
  965. package/ref-monty/crates/monty-js/build.rs +0 -61
  966. package/ref-monty/crates/monty-js/index-header.d.ts +0 -3
  967. package/ref-monty/crates/monty-js/package-lock.json +0 -4694
  968. package/ref-monty/crates/monty-js/package.json +0 -100
  969. package/ref-monty/crates/monty-js/scripts/smoke-test.sh +0 -69
  970. package/ref-monty/crates/monty-js/smoke-test/package.json +0 -17
  971. package/ref-monty/crates/monty-js/smoke-test/test.ts +0 -171
  972. package/ref-monty/crates/monty-js/smoke-test/tsconfig.json +0 -11
  973. package/ref-monty/crates/monty-js/src/convert.rs +0 -648
  974. package/ref-monty/crates/monty-js/src/exceptions.rs +0 -293
  975. package/ref-monty/crates/monty-js/src/lib.rs +0 -41
  976. package/ref-monty/crates/monty-js/src/limits.rs +0 -53
  977. package/ref-monty/crates/monty-js/src/monty_cls.rs +0 -1407
  978. package/ref-monty/crates/monty-js/tsconfig.json +0 -17
  979. package/ref-monty/crates/monty-js/wrapper.ts +0 -701
  980. package/ref-monty/crates/monty-python/Cargo.toml +0 -38
  981. package/ref-monty/crates/monty-python/README.md +0 -134
  982. package/ref-monty/crates/monty-python/build.rs +0 -4
  983. package/ref-monty/crates/monty-python/example.py +0 -40
  984. package/ref-monty/crates/monty-python/exercise.py +0 -46
  985. package/ref-monty/crates/monty-python/pyproject.toml +0 -57
  986. package/ref-monty/crates/monty-python/python/pydantic_monty/__init__.py +0 -281
  987. package/ref-monty/crates/monty-python/python/pydantic_monty/_monty.pyi +0 -677
  988. package/ref-monty/crates/monty-python/python/pydantic_monty/os_access.py +0 -933
  989. package/ref-monty/crates/monty-python/python/pydantic_monty/py.typed +0 -0
  990. package/ref-monty/crates/monty-python/src/convert.rs +0 -273
  991. package/ref-monty/crates/monty-python/src/dataclass.rs +0 -461
  992. package/ref-monty/crates/monty-python/src/exceptions.rs +0 -557
  993. package/ref-monty/crates/monty-python/src/external.rs +0 -165
  994. package/ref-monty/crates/monty-python/src/lib.rs +0 -77
  995. package/ref-monty/crates/monty-python/src/limits.rs +0 -142
  996. package/ref-monty/crates/monty-python/src/monty_cls.rs +0 -1650
  997. package/ref-monty/crates/monty-python/src/repl.rs +0 -470
  998. package/ref-monty/crates/monty-python/src/serialization.rs +0 -761
  999. package/ref-monty/crates/monty-python/tests/test_async.py +0 -1201
  1000. package/ref-monty/crates/monty-python/tests/test_basic.py +0 -66
  1001. package/ref-monty/crates/monty-python/tests/test_dataclasses.py +0 -971
  1002. package/ref-monty/crates/monty-python/tests/test_exceptions.py +0 -361
  1003. package/ref-monty/crates/monty-python/tests/test_external.py +0 -367
  1004. package/ref-monty/crates/monty-python/tests/test_inputs.py +0 -126
  1005. package/ref-monty/crates/monty-python/tests/test_limits.py +0 -257
  1006. package/ref-monty/crates/monty-python/tests/test_os_access.py +0 -1286
  1007. package/ref-monty/crates/monty-python/tests/test_os_access_compat.py +0 -731
  1008. package/ref-monty/crates/monty-python/tests/test_os_access_raw.py +0 -483
  1009. package/ref-monty/crates/monty-python/tests/test_os_calls.py +0 -819
  1010. package/ref-monty/crates/monty-python/tests/test_print.py +0 -208
  1011. package/ref-monty/crates/monty-python/tests/test_re.py +0 -170
  1012. package/ref-monty/crates/monty-python/tests/test_readme_examples.py +0 -20
  1013. package/ref-monty/crates/monty-python/tests/test_repl.py +0 -749
  1014. package/ref-monty/crates/monty-python/tests/test_serialize.py +0 -284
  1015. package/ref-monty/crates/monty-python/tests/test_start.py +0 -346
  1016. package/ref-monty/crates/monty-python/tests/test_threading.py +0 -163
  1017. package/ref-monty/crates/monty-python/tests/test_type_check.py +0 -344
  1018. package/ref-monty/crates/monty-python/tests/test_types.py +0 -553
  1019. package/ref-monty/crates/monty-type-checking/Cargo.toml +0 -32
  1020. package/ref-monty/crates/monty-type-checking/src/db.rs +0 -116
  1021. package/ref-monty/crates/monty-type-checking/src/lib.rs +0 -4
  1022. package/ref-monty/crates/monty-type-checking/src/type_check.rs +0 -280
  1023. package/ref-monty/crates/monty-type-checking/tests/bad_types.py +0 -109
  1024. package/ref-monty/crates/monty-type-checking/tests/bad_types_output.txt +0 -21
  1025. package/ref-monty/crates/monty-type-checking/tests/good_types.py +0 -475
  1026. package/ref-monty/crates/monty-type-checking/tests/main.rs +0 -205
  1027. package/ref-monty/crates/monty-type-checking/tests/reveal_types.py +0 -56
  1028. package/ref-monty/crates/monty-type-checking/tests/reveal_types_output.txt +0 -41
  1029. package/ref-monty/crates/monty-typeshed/Cargo.toml +0 -29
  1030. package/ref-monty/crates/monty-typeshed/README.md +0 -11
  1031. package/ref-monty/crates/monty-typeshed/build.rs +0 -101
  1032. package/ref-monty/crates/monty-typeshed/custom/README.md +0 -1
  1033. package/ref-monty/crates/monty-typeshed/custom/asyncio.pyi +0 -138
  1034. package/ref-monty/crates/monty-typeshed/custom/os.pyi +0 -87
  1035. package/ref-monty/crates/monty-typeshed/custom/sys.pyi +0 -33
  1036. package/ref-monty/crates/monty-typeshed/src/lib.rs +0 -56
  1037. package/ref-monty/crates/monty-typeshed/update.py +0 -321
  1038. package/ref-monty/crates/monty-typeshed/vendor/typeshed/source_commit.txt +0 -1
  1039. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/VERSIONS +0 -20
  1040. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/_collections_abc.pyi +0 -105
  1041. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/_typeshed/__init__.pyi +0 -394
  1042. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/asyncio.pyi +0 -138
  1043. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/builtins.pyi +0 -1434
  1044. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/collections/__init__.pyi +0 -527
  1045. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/collections/abc.pyi +0 -2
  1046. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/dataclasses.pyi +0 -502
  1047. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/enum.pyi +0 -376
  1048. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/math.pyi +0 -149
  1049. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/os.pyi +0 -87
  1050. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/pathlib/__init__.pyi +0 -395
  1051. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/pathlib/types.pyi +0 -8
  1052. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/re.pyi +0 -337
  1053. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/sys.pyi +0 -33
  1054. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/types.pyi +0 -741
  1055. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/typing.pyi +0 -1217
  1056. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/typing_extensions.pyi +0 -716
  1057. package/ref-monty/docs/usage-guide.md +0 -117
  1058. package/ref-monty/examples/README.md +0 -3
  1059. package/ref-monty/examples/expense_analysis/README.md +0 -3
  1060. package/ref-monty/examples/expense_analysis/data.py +0 -124
  1061. package/ref-monty/examples/expense_analysis/main.py +0 -115
  1062. package/ref-monty/examples/sql_playground/README.md +0 -20
  1063. package/ref-monty/examples/sql_playground/external_functions.py +0 -129
  1064. package/ref-monty/examples/sql_playground/main.py +0 -81
  1065. package/ref-monty/examples/sql_playground/sandbox_code.py +0 -82
  1066. package/ref-monty/examples/sql_playground/type_stubs.pyi +0 -14
  1067. package/ref-monty/examples/web_scraper/README.md +0 -15
  1068. package/ref-monty/examples/web_scraper/browser.py +0 -56
  1069. package/ref-monty/examples/web_scraper/example_code.py +0 -59
  1070. package/ref-monty/examples/web_scraper/external_functions.py +0 -324
  1071. package/ref-monty/examples/web_scraper/main.py +0 -193
  1072. package/ref-monty/examples/web_scraper/sub_agent.py +0 -79
  1073. package/ref-monty/monty-npm.md +0 -235
  1074. package/ref-monty/pyproject.toml +0 -162
  1075. package/ref-monty/scripts/check_imports.py +0 -91
  1076. package/ref-monty/scripts/codecov_diff.py +0 -412
  1077. package/ref-monty/scripts/complete_tests.py +0 -146
  1078. package/ref-monty/scripts/flamegraph_to_text.py +0 -208
  1079. package/ref-monty/scripts/iter_test_methods.py +0 -540
  1080. package/ref-monty/scripts/run_traceback.py +0 -180
  1081. package/ref-monty/scripts/startup_performance.py +0 -130
  1082. package/ref-monty/uv.lock +0 -1779
  1083. package/temp_resend_cli/repo/.github/scripts/pr-title-check.js +0 -34
  1084. package/temp_resend_cli/repo/.github/workflows/ci.yml +0 -67
  1085. package/temp_resend_cli/repo/.github/workflows/post-release.yml +0 -51
  1086. package/temp_resend_cli/repo/.github/workflows/pr-title-check.yml +0 -13
  1087. package/temp_resend_cli/repo/.github/workflows/release.yml +0 -175
  1088. package/temp_resend_cli/repo/.github/workflows/test-install-unix.yml +0 -34
  1089. package/temp_resend_cli/repo/.github/workflows/test-install-windows.yml +0 -48
  1090. package/temp_resend_cli/repo/CHANGELOG.md +0 -31
  1091. package/temp_resend_cli/repo/LICENSE +0 -21
  1092. package/temp_resend_cli/repo/README.md +0 -450
  1093. package/temp_resend_cli/repo/biome.json +0 -36
  1094. package/temp_resend_cli/repo/install.ps1 +0 -141
  1095. package/temp_resend_cli/repo/install.sh +0 -301
  1096. package/temp_resend_cli/repo/package.json +0 -61
  1097. package/temp_resend_cli/repo/pnpm-lock.yaml +0 -2439
  1098. package/temp_resend_cli/repo/renovate.json +0 -4
  1099. package/temp_resend_cli/repo/src/cli.ts +0 -98
  1100. package/temp_resend_cli/repo/src/commands/api-keys/create.ts +0 -114
  1101. package/temp_resend_cli/repo/src/commands/api-keys/delete.ts +0 -47
  1102. package/temp_resend_cli/repo/src/commands/api-keys/index.ts +0 -26
  1103. package/temp_resend_cli/repo/src/commands/api-keys/list.ts +0 -35
  1104. package/temp_resend_cli/repo/src/commands/api-keys/utils.ts +0 -8
  1105. package/temp_resend_cli/repo/src/commands/auth/index.ts +0 -20
  1106. package/temp_resend_cli/repo/src/commands/auth/login.ts +0 -234
  1107. package/temp_resend_cli/repo/src/commands/auth/logout.ts +0 -105
  1108. package/temp_resend_cli/repo/src/commands/broadcasts/create.ts +0 -196
  1109. package/temp_resend_cli/repo/src/commands/broadcasts/delete.ts +0 -46
  1110. package/temp_resend_cli/repo/src/commands/broadcasts/get.ts +0 -59
  1111. package/temp_resend_cli/repo/src/commands/broadcasts/index.ts +0 -43
  1112. package/temp_resend_cli/repo/src/commands/broadcasts/list.ts +0 -60
  1113. package/temp_resend_cli/repo/src/commands/broadcasts/send.ts +0 -56
  1114. package/temp_resend_cli/repo/src/commands/broadcasts/update.ts +0 -95
  1115. package/temp_resend_cli/repo/src/commands/broadcasts/utils.ts +0 -35
  1116. package/temp_resend_cli/repo/src/commands/contact-properties/create.ts +0 -118
  1117. package/temp_resend_cli/repo/src/commands/contact-properties/delete.ts +0 -48
  1118. package/temp_resend_cli/repo/src/commands/contact-properties/get.ts +0 -46
  1119. package/temp_resend_cli/repo/src/commands/contact-properties/index.ts +0 -48
  1120. package/temp_resend_cli/repo/src/commands/contact-properties/list.ts +0 -68
  1121. package/temp_resend_cli/repo/src/commands/contact-properties/update.ts +0 -88
  1122. package/temp_resend_cli/repo/src/commands/contact-properties/utils.ts +0 -17
  1123. package/temp_resend_cli/repo/src/commands/contacts/add-segment.ts +0 -78
  1124. package/temp_resend_cli/repo/src/commands/contacts/create.ts +0 -122
  1125. package/temp_resend_cli/repo/src/commands/contacts/delete.ts +0 -49
  1126. package/temp_resend_cli/repo/src/commands/contacts/get.ts +0 -53
  1127. package/temp_resend_cli/repo/src/commands/contacts/index.ts +0 -58
  1128. package/temp_resend_cli/repo/src/commands/contacts/list.ts +0 -57
  1129. package/temp_resend_cli/repo/src/commands/contacts/remove-segment.ts +0 -48
  1130. package/temp_resend_cli/repo/src/commands/contacts/segments.ts +0 -39
  1131. package/temp_resend_cli/repo/src/commands/contacts/topics.ts +0 -45
  1132. package/temp_resend_cli/repo/src/commands/contacts/update-topics.ts +0 -90
  1133. package/temp_resend_cli/repo/src/commands/contacts/update.ts +0 -77
  1134. package/temp_resend_cli/repo/src/commands/contacts/utils.ts +0 -119
  1135. package/temp_resend_cli/repo/src/commands/doctor.ts +0 -216
  1136. package/temp_resend_cli/repo/src/commands/domains/create.ts +0 -83
  1137. package/temp_resend_cli/repo/src/commands/domains/delete.ts +0 -42
  1138. package/temp_resend_cli/repo/src/commands/domains/get.ts +0 -47
  1139. package/temp_resend_cli/repo/src/commands/domains/index.ts +0 -35
  1140. package/temp_resend_cli/repo/src/commands/domains/list.ts +0 -53
  1141. package/temp_resend_cli/repo/src/commands/domains/update.ts +0 -75
  1142. package/temp_resend_cli/repo/src/commands/domains/utils.ts +0 -44
  1143. package/temp_resend_cli/repo/src/commands/domains/verify.ts +0 -38
  1144. package/temp_resend_cli/repo/src/commands/emails/batch.ts +0 -140
  1145. package/temp_resend_cli/repo/src/commands/emails/get.ts +0 -44
  1146. package/temp_resend_cli/repo/src/commands/emails/index.ts +0 -30
  1147. package/temp_resend_cli/repo/src/commands/emails/list.ts +0 -84
  1148. package/temp_resend_cli/repo/src/commands/emails/receiving/attachment.ts +0 -55
  1149. package/temp_resend_cli/repo/src/commands/emails/receiving/attachments.ts +0 -68
  1150. package/temp_resend_cli/repo/src/commands/emails/receiving/get.ts +0 -58
  1151. package/temp_resend_cli/repo/src/commands/emails/receiving/index.ts +0 -28
  1152. package/temp_resend_cli/repo/src/commands/emails/receiving/list.ts +0 -59
  1153. package/temp_resend_cli/repo/src/commands/emails/receiving/utils.ts +0 -38
  1154. package/temp_resend_cli/repo/src/commands/emails/send.ts +0 -189
  1155. package/temp_resend_cli/repo/src/commands/open.ts +0 -27
  1156. package/temp_resend_cli/repo/src/commands/segments/create.ts +0 -50
  1157. package/temp_resend_cli/repo/src/commands/segments/delete.ts +0 -47
  1158. package/temp_resend_cli/repo/src/commands/segments/get.ts +0 -38
  1159. package/temp_resend_cli/repo/src/commands/segments/index.ts +0 -36
  1160. package/temp_resend_cli/repo/src/commands/segments/list.ts +0 -58
  1161. package/temp_resend_cli/repo/src/commands/segments/utils.ts +0 -7
  1162. package/temp_resend_cli/repo/src/commands/teams/index.ts +0 -10
  1163. package/temp_resend_cli/repo/src/commands/teams/list.ts +0 -35
  1164. package/temp_resend_cli/repo/src/commands/teams/remove.ts +0 -86
  1165. package/temp_resend_cli/repo/src/commands/teams/switch.ts +0 -76
  1166. package/temp_resend_cli/repo/src/commands/topics/create.ts +0 -73
  1167. package/temp_resend_cli/repo/src/commands/topics/delete.ts +0 -47
  1168. package/temp_resend_cli/repo/src/commands/topics/get.ts +0 -42
  1169. package/temp_resend_cli/repo/src/commands/topics/index.ts +0 -42
  1170. package/temp_resend_cli/repo/src/commands/topics/list.ts +0 -34
  1171. package/temp_resend_cli/repo/src/commands/topics/update.ts +0 -59
  1172. package/temp_resend_cli/repo/src/commands/topics/utils.ts +0 -16
  1173. package/temp_resend_cli/repo/src/commands/webhooks/create.ts +0 -128
  1174. package/temp_resend_cli/repo/src/commands/webhooks/delete.ts +0 -49
  1175. package/temp_resend_cli/repo/src/commands/webhooks/get.ts +0 -42
  1176. package/temp_resend_cli/repo/src/commands/webhooks/index.ts +0 -42
  1177. package/temp_resend_cli/repo/src/commands/webhooks/list.ts +0 -55
  1178. package/temp_resend_cli/repo/src/commands/webhooks/listen.ts +0 -379
  1179. package/temp_resend_cli/repo/src/commands/webhooks/update.ts +0 -83
  1180. package/temp_resend_cli/repo/src/commands/webhooks/utils.ts +0 -36
  1181. package/temp_resend_cli/repo/src/commands/whoami.ts +0 -71
  1182. package/temp_resend_cli/repo/src/lib/actions.ts +0 -157
  1183. package/temp_resend_cli/repo/src/lib/client.ts +0 -37
  1184. package/temp_resend_cli/repo/src/lib/config.ts +0 -217
  1185. package/temp_resend_cli/repo/src/lib/files.ts +0 -15
  1186. package/temp_resend_cli/repo/src/lib/help-text.ts +0 -38
  1187. package/temp_resend_cli/repo/src/lib/output.ts +0 -56
  1188. package/temp_resend_cli/repo/src/lib/pagination.ts +0 -36
  1189. package/temp_resend_cli/repo/src/lib/prompts.ts +0 -149
  1190. package/temp_resend_cli/repo/src/lib/spinner.ts +0 -100
  1191. package/temp_resend_cli/repo/src/lib/table.ts +0 -57
  1192. package/temp_resend_cli/repo/src/lib/tty.ts +0 -28
  1193. package/temp_resend_cli/repo/src/lib/update-check.ts +0 -169
  1194. package/temp_resend_cli/repo/src/lib/version.ts +0 -4
  1195. package/temp_resend_cli/repo/tests/commands/api-keys/create.test.ts +0 -196
  1196. package/temp_resend_cli/repo/tests/commands/api-keys/delete.test.ts +0 -157
  1197. package/temp_resend_cli/repo/tests/commands/api-keys/list.test.ts +0 -134
  1198. package/temp_resend_cli/repo/tests/commands/auth/login.test.ts +0 -153
  1199. package/temp_resend_cli/repo/tests/commands/auth/logout.test.ts +0 -153
  1200. package/temp_resend_cli/repo/tests/commands/broadcasts/create.test.ts +0 -454
  1201. package/temp_resend_cli/repo/tests/commands/broadcasts/delete.test.ts +0 -183
  1202. package/temp_resend_cli/repo/tests/commands/broadcasts/get.test.ts +0 -147
  1203. package/temp_resend_cli/repo/tests/commands/broadcasts/list.test.ts +0 -199
  1204. package/temp_resend_cli/repo/tests/commands/broadcasts/send.test.ts +0 -162
  1205. package/temp_resend_cli/repo/tests/commands/broadcasts/update.test.ts +0 -288
  1206. package/temp_resend_cli/repo/tests/commands/contact-properties/create.test.ts +0 -251
  1207. package/temp_resend_cli/repo/tests/commands/contact-properties/delete.test.ts +0 -184
  1208. package/temp_resend_cli/repo/tests/commands/contact-properties/get.test.ts +0 -145
  1209. package/temp_resend_cli/repo/tests/commands/contact-properties/list.test.ts +0 -181
  1210. package/temp_resend_cli/repo/tests/commands/contact-properties/update.test.ts +0 -217
  1211. package/temp_resend_cli/repo/tests/commands/contacts/add-segment.test.ts +0 -189
  1212. package/temp_resend_cli/repo/tests/commands/contacts/create.test.ts +0 -271
  1213. package/temp_resend_cli/repo/tests/commands/contacts/delete.test.ts +0 -193
  1214. package/temp_resend_cli/repo/tests/commands/contacts/get.test.ts +0 -149
  1215. package/temp_resend_cli/repo/tests/commands/contacts/list.test.ts +0 -176
  1216. package/temp_resend_cli/repo/tests/commands/contacts/remove-segment.test.ts +0 -167
  1217. package/temp_resend_cli/repo/tests/commands/contacts/segments.test.ts +0 -168
  1218. package/temp_resend_cli/repo/tests/commands/contacts/topics.test.ts +0 -164
  1219. package/temp_resend_cli/repo/tests/commands/contacts/update-topics.test.ts +0 -248
  1220. package/temp_resend_cli/repo/tests/commands/contacts/update.test.ts +0 -206
  1221. package/temp_resend_cli/repo/tests/commands/doctor.test.ts +0 -164
  1222. package/temp_resend_cli/repo/tests/commands/domains/create.test.ts +0 -193
  1223. package/temp_resend_cli/repo/tests/commands/domains/delete.test.ts +0 -157
  1224. package/temp_resend_cli/repo/tests/commands/domains/get.test.ts +0 -138
  1225. package/temp_resend_cli/repo/tests/commands/domains/list.test.ts +0 -165
  1226. package/temp_resend_cli/repo/tests/commands/domains/update.test.ts +0 -224
  1227. package/temp_resend_cli/repo/tests/commands/domains/verify.test.ts +0 -118
  1228. package/temp_resend_cli/repo/tests/commands/emails/batch.test.ts +0 -324
  1229. package/temp_resend_cli/repo/tests/commands/emails/get.test.ts +0 -132
  1230. package/temp_resend_cli/repo/tests/commands/emails/receiving/attachment.test.ts +0 -141
  1231. package/temp_resend_cli/repo/tests/commands/emails/receiving/attachments.test.ts +0 -169
  1232. package/temp_resend_cli/repo/tests/commands/emails/receiving/get.test.ts +0 -141
  1233. package/temp_resend_cli/repo/tests/commands/emails/receiving/list.test.ts +0 -182
  1234. package/temp_resend_cli/repo/tests/commands/emails/send.test.ts +0 -312
  1235. package/temp_resend_cli/repo/tests/commands/segments/create.test.ts +0 -164
  1236. package/temp_resend_cli/repo/tests/commands/segments/delete.test.ts +0 -183
  1237. package/temp_resend_cli/repo/tests/commands/segments/get.test.ts +0 -138
  1238. package/temp_resend_cli/repo/tests/commands/segments/list.test.ts +0 -174
  1239. package/temp_resend_cli/repo/tests/commands/teams/list.test.ts +0 -62
  1240. package/temp_resend_cli/repo/tests/commands/teams/remove.test.ts +0 -110
  1241. package/temp_resend_cli/repo/tests/commands/teams/switch.test.ts +0 -103
  1242. package/temp_resend_cli/repo/tests/commands/topics/create.test.ts +0 -192
  1243. package/temp_resend_cli/repo/tests/commands/topics/delete.test.ts +0 -157
  1244. package/temp_resend_cli/repo/tests/commands/topics/get.test.ts +0 -126
  1245. package/temp_resend_cli/repo/tests/commands/topics/list.test.ts +0 -125
  1246. package/temp_resend_cli/repo/tests/commands/topics/update.test.ts +0 -178
  1247. package/temp_resend_cli/repo/tests/commands/webhooks/create.test.ts +0 -225
  1248. package/temp_resend_cli/repo/tests/commands/webhooks/delete.test.ts +0 -157
  1249. package/temp_resend_cli/repo/tests/commands/webhooks/get.test.ts +0 -126
  1250. package/temp_resend_cli/repo/tests/commands/webhooks/list.test.ts +0 -178
  1251. package/temp_resend_cli/repo/tests/commands/webhooks/update.test.ts +0 -207
  1252. package/temp_resend_cli/repo/tests/commands/whoami.test.ts +0 -98
  1253. package/temp_resend_cli/repo/tests/e2e/smoke.test.ts +0 -93
  1254. package/temp_resend_cli/repo/tests/helpers.ts +0 -86
  1255. package/temp_resend_cli/repo/tests/lib/client.test.ts +0 -71
  1256. package/temp_resend_cli/repo/tests/lib/config.test.ts +0 -451
  1257. package/temp_resend_cli/repo/tests/lib/files.test.ts +0 -73
  1258. package/temp_resend_cli/repo/tests/lib/help-text.test.ts +0 -97
  1259. package/temp_resend_cli/repo/tests/lib/output.test.ts +0 -136
  1260. package/temp_resend_cli/repo/tests/lib/prompts.test.ts +0 -185
  1261. package/temp_resend_cli/repo/tests/lib/spinner.test.ts +0 -166
  1262. package/temp_resend_cli/repo/tests/lib/table.test.ts +0 -63
  1263. package/temp_resend_cli/repo/tests/lib/tty.test.ts +0 -89
  1264. package/temp_resend_cli/repo/tests/lib/update-check.test.ts +0 -179
  1265. package/temp_resend_cli/repo/tsconfig.json +0 -14
  1266. package/temp_resend_cli/repo/vitest.config.e2e.ts +0 -8
  1267. package/temp_resend_cli/repo/vitest.config.ts +0 -10
  1268. /package/docs/{plugin-examples.md → plugins-examples.md} +0 -0
@@ -1,2356 +0,0 @@
1
- /// Python bytes type, wrapping a `Vec<u8>`.
2
- ///
3
- /// This type provides Python bytes semantics with operations on ASCII bytes only.
4
- /// Unlike str methods which operate on Unicode codepoints, bytes methods only
5
- /// recognize ASCII characters (0-127) for case transformations and predicates.
6
- ///
7
- /// # Implemented Methods
8
- ///
9
- /// ## Encoding/Decoding
10
- /// - `decode([encoding[, errors]])` - Decode to string (UTF-8 only)
11
- /// - `hex([sep[, bytes_per_sep]])` - Return hex string representation
12
- /// - `fromhex(string)` - Create bytes from hex string (classmethod)
13
- ///
14
- /// ## Simple Transformations
15
- /// - `lower()` - Convert ASCII uppercase to lowercase
16
- /// - `upper()` - Convert ASCII lowercase to uppercase
17
- /// - `capitalize()` - First byte uppercase, rest lowercase
18
- /// - `title()` - Titlecase ASCII letters
19
- /// - `swapcase()` - Swap ASCII case
20
- ///
21
- /// ## Predicates
22
- /// - `isalpha()` - All bytes are ASCII letters
23
- /// - `isdigit()` - All bytes are ASCII digits
24
- /// - `isalnum()` - All bytes are ASCII alphanumeric
25
- /// - `isspace()` - All bytes are ASCII whitespace
26
- /// - `islower()` - Has cased bytes, all lowercase
27
- /// - `isupper()` - Has cased bytes, all uppercase
28
- /// - `isascii()` - All bytes are ASCII (0-127)
29
- /// - `istitle()` - Titlecased
30
- ///
31
- /// ## Search Methods
32
- /// - `count(sub[, start[, end]])` - Count non-overlapping occurrences
33
- /// - `find(sub[, start[, end]])` - Find first occurrence (-1 if not found)
34
- /// - `rfind(sub[, start[, end]])` - Find last occurrence (-1 if not found)
35
- /// - `index(sub[, start[, end]])` - Find first occurrence (raises ValueError)
36
- /// - `rindex(sub[, start[, end]])` - Find last occurrence (raises ValueError)
37
- /// - `startswith(prefix[, start[, end]])` - Check if starts with prefix
38
- /// - `endswith(suffix[, start[, end]])` - Check if ends with suffix
39
- ///
40
- /// ## Strip/Trim Methods
41
- /// - `strip([chars])` - Remove leading/trailing bytes
42
- /// - `lstrip([chars])` - Remove leading bytes
43
- /// - `rstrip([chars])` - Remove trailing bytes
44
- /// - `removeprefix(prefix)` - Remove prefix if present
45
- /// - `removesuffix(suffix)` - Remove suffix if present
46
- ///
47
- /// ## Split Methods
48
- /// - `split([sep[, maxsplit]])` - Split on separator
49
- /// - `rsplit([sep[, maxsplit]])` - Split from right
50
- /// - `splitlines([keepends])` - Split on line boundaries
51
- /// - `partition(sep)` - Split into 3 parts at first sep
52
- /// - `rpartition(sep)` - Split into 3 parts at last sep
53
- ///
54
- /// ## Replace/Padding Methods
55
- /// - `replace(old, new[, count])` - Replace occurrences
56
- /// - `center(width[, fillbyte])` - Center with fill byte
57
- /// - `ljust(width[, fillbyte])` - Left justify with fill byte
58
- /// - `rjust(width[, fillbyte])` - Right justify with fill byte
59
- /// - `zfill(width)` - Pad with zeros
60
- ///
61
- /// ## Other Methods
62
- /// - `join(iterable)` - Join bytes sequences
63
- ///
64
- /// # Unimplemented Methods
65
- /// - `expandtabs(tabsize=8)` - Tab expansion
66
- /// - `translate(table[, delete])` - Character translation
67
- /// - `maketrans(frm, to)` - Create translation table (staticmethod)
68
- use std::cmp::Ordering;
69
- use std::fmt::Write;
70
-
71
- use ahash::AHashSet;
72
- use smallvec::smallvec;
73
-
74
- use super::{MontyIter, PyTrait, Type, str::Str};
75
- use crate::{
76
- args::ArgValues,
77
- bytecode::{CallResult, VM},
78
- defer_drop, defer_drop_mut,
79
- exception_private::{ExcType, RunResult, SimpleException},
80
- heap::{DropWithHeap, Heap, HeapData, HeapGuard, HeapId},
81
- intern::{Interns, StaticStrings, StringId},
82
- resource::{ResourceError, ResourceTracker, check_repeat_size, check_replace_size},
83
- types::List,
84
- value::{EitherStr, Value},
85
- };
86
-
87
- // =============================================================================
88
- // ASCII byte helper functions
89
- // =============================================================================
90
-
91
- /// Returns true if the byte is Python ASCII whitespace.
92
- ///
93
- /// Python considers these bytes as whitespace: space, tab, newline, carriage return,
94
- /// vertical tab (0x0b), and form feed (0x0c). Note: Rust's `is_ascii_whitespace()`
95
- /// does not include vertical tab (0x0b).
96
- #[inline]
97
- fn is_py_whitespace(b: u8) -> bool {
98
- matches!(b, b' ' | b'\t' | b'\n' | b'\r' | 0x0b | 0x0c)
99
- }
100
-
101
- /// Gets the byte at a given index, handling negative indices.
102
- ///
103
- /// Returns `None` if the index is out of bounds.
104
- /// Negative indices count from the end: -1 is the last byte.
105
- pub fn get_byte_at_index(bytes: &[u8], index: i64) -> Option<u8> {
106
- let len = i64::try_from(bytes.len()).ok()?;
107
- let normalized = if index < 0 { index + len } else { index };
108
-
109
- if normalized < 0 || normalized >= len {
110
- return None;
111
- }
112
-
113
- let idx = usize::try_from(normalized).ok()?;
114
- Some(bytes[idx])
115
- }
116
-
117
- /// Extracts a slice of a byte array.
118
- ///
119
- /// Handles both positive and negative step values. For negative step,
120
- /// iterates backward from start down to (but not including) stop.
121
- /// The `stop` parameter uses a sentinel value of `len + 1` for negative
122
- /// step to indicate "go to the beginning".
123
- ///
124
- /// Note: step must be non-zero (callers should validate this via `slice.indices()`).
125
- pub(crate) fn get_bytes_slice(bytes: &[u8], start: usize, stop: usize, step: i64) -> Vec<u8> {
126
- let mut result = Vec::new();
127
-
128
- // try_from succeeds for non-negative step; step==0 rejected upstream by slice.indices()
129
- if let Ok(step_usize) = usize::try_from(step) {
130
- // Positive step: iterate forward
131
- let mut i = start;
132
- while i < stop && i < bytes.len() {
133
- result.push(bytes[i]);
134
- i += step_usize;
135
- }
136
- } else {
137
- // Negative step: iterate backward
138
- // start is the highest index, stop is the sentinel
139
- // stop > bytes.len() means "go to the beginning"
140
- let step_abs = usize::try_from(-step).expect("step is negative so -step is positive");
141
- let step_abs_i64 = i64::try_from(step_abs).expect("step magnitude fits in i64");
142
- let mut i = i64::try_from(start).expect("start index fits in i64");
143
- let stop_i64 = if stop > bytes.len() {
144
- -1
145
- } else {
146
- i64::try_from(stop).expect("stop bounded by bytes.len() fits in i64")
147
- };
148
-
149
- while let Ok(i_usize) = usize::try_from(i) {
150
- if i_usize >= bytes.len() || i <= stop_i64 {
151
- break;
152
- }
153
- result.push(bytes[i_usize]);
154
- i -= step_abs_i64;
155
- }
156
- }
157
-
158
- result
159
- }
160
-
161
- /// Python bytes value stored on the heap.
162
- ///
163
- /// Wraps a `Vec<u8>` and provides Python-compatible operations.
164
- /// See the module-level documentation for implemented and unimplemented methods.
165
- #[derive(Debug, Clone, PartialEq, Default, serde::Serialize, serde::Deserialize)]
166
- pub(crate) struct Bytes(Vec<u8>);
167
-
168
- impl Bytes {
169
- /// Creates a new Bytes from a byte vector.
170
- #[must_use]
171
- pub fn new(bytes: Vec<u8>) -> Self {
172
- Self(bytes)
173
- }
174
-
175
- /// Returns a reference to the inner byte slice.
176
- #[must_use]
177
- pub fn as_slice(&self) -> &[u8] {
178
- &self.0
179
- }
180
-
181
- /// Creates bytes from the `bytes()` constructor call.
182
- ///
183
- /// - `bytes()` with no args returns empty bytes
184
- /// - `bytes(int)` returns bytes of that length filled with zeros
185
- /// - `bytes(string)` encodes the string as UTF-8 (simplified, no encoding param)
186
- /// - `bytes(bytes)` returns a copy of the bytes
187
- ///
188
- /// Note: Full Python semantics for bytes() are more complex (encoding, errors params).
189
- pub fn init(vm: &mut VM<'_, '_, impl ResourceTracker>, args: ArgValues) -> RunResult<Value> {
190
- let heap = &mut *vm.heap;
191
- let interns = vm.interns;
192
- let value = args.get_zero_one_arg("bytes", heap)?;
193
- defer_drop!(value, heap);
194
- let new_data = match value {
195
- None => Vec::new(),
196
- Some(Value::Int(n)) => {
197
- if *n < 0 {
198
- return Err(ExcType::value_error_negative_bytes_count());
199
- }
200
- let size = usize::try_from(*n).expect("bytes count validated non-negative");
201
- vec![0u8; size]
202
- }
203
- Some(Value::InternString(string_id)) => {
204
- let s = interns.get_str(*string_id);
205
- s.as_bytes().to_vec()
206
- }
207
- Some(Value::InternBytes(bytes_id)) => {
208
- let b = interns.get_bytes(*bytes_id);
209
- b.to_vec()
210
- }
211
- Some(v @ Value::Ref(id)) => match heap.get(*id) {
212
- HeapData::Str(s) => s.as_str().as_bytes().to_vec(),
213
- HeapData::Bytes(b) => b.as_slice().to_vec(),
214
- _ => return Err(ExcType::type_error_bytes_init(v.py_type(heap))),
215
- },
216
- Some(v) => return Err(ExcType::type_error_bytes_init(v.py_type(heap))),
217
- };
218
- let heap_id = heap.allocate(HeapData::Bytes(Self::new(new_data)))?;
219
- Ok(Value::Ref(heap_id))
220
- }
221
- }
222
-
223
- impl From<Vec<u8>> for Bytes {
224
- fn from(bytes: Vec<u8>) -> Self {
225
- Self(bytes)
226
- }
227
- }
228
-
229
- impl From<&[u8]> for Bytes {
230
- fn from(bytes: &[u8]) -> Self {
231
- Self(bytes.to_vec())
232
- }
233
- }
234
-
235
- impl From<Bytes> for Vec<u8> {
236
- fn from(bytes: Bytes) -> Self {
237
- bytes.0
238
- }
239
- }
240
-
241
- impl std::ops::Deref for Bytes {
242
- type Target = Vec<u8>;
243
-
244
- fn deref(&self) -> &Self::Target {
245
- &self.0
246
- }
247
- }
248
-
249
- impl PyTrait for Bytes {
250
- fn py_type(&self, _heap: &Heap<impl ResourceTracker>) -> Type {
251
- Type::Bytes
252
- }
253
-
254
- fn py_estimate_size(&self) -> usize {
255
- std::mem::size_of::<Self>() + self.0.len()
256
- }
257
-
258
- fn py_len(&self, _vm: &VM<'_, '_, impl ResourceTracker>) -> Option<usize> {
259
- Some(self.0.len())
260
- }
261
-
262
- fn py_getitem(&self, key: &Value, vm: &mut VM<'_, '_, impl ResourceTracker>) -> RunResult<Value> {
263
- let heap = &mut *vm.heap;
264
- // Check for slice first (Value::Ref pointing to HeapData::Slice)
265
- if let Value::Ref(id) = key
266
- && let HeapData::Slice(slice) = heap.get(*id)
267
- {
268
- let (start, stop, step) = slice
269
- .indices(self.0.len())
270
- .map_err(|()| ExcType::value_error_slice_step_zero())?;
271
-
272
- let sliced_bytes = get_bytes_slice(&self.0, start, stop, step);
273
- let heap_id = heap.allocate(HeapData::Bytes(Self::new(sliced_bytes)))?;
274
- return Ok(Value::Ref(heap_id));
275
- }
276
-
277
- // Extract integer index, accepting Int, Bool (True=1, False=0), and LongInt
278
- let index = key.as_index(heap, Type::Bytes)?;
279
-
280
- // Use helper for byte indexing
281
- let byte = get_byte_at_index(&self.0, index).ok_or_else(ExcType::bytes_index_error)?;
282
- Ok(Value::Int(i64::from(byte)))
283
- }
284
-
285
- fn py_eq(&self, other: &Self, _vm: &mut VM<'_, '_, impl ResourceTracker>) -> Result<bool, ResourceError> {
286
- Ok(self.0 == other.0)
287
- }
288
-
289
- /// Bytes don't contain nested heap references.
290
- fn py_dec_ref_ids(&mut self, _stack: &mut Vec<HeapId>) {
291
- // No-op: bytes don't hold Value references
292
- }
293
-
294
- fn py_cmp(
295
- &self,
296
- other: &Self,
297
- _vm: &mut VM<'_, '_, impl ResourceTracker>,
298
- ) -> Result<Option<Ordering>, ResourceError> {
299
- Ok(Some(self.0.cmp(&other.0)))
300
- }
301
-
302
- fn py_bool(&self, _vm: &VM<'_, '_, impl ResourceTracker>) -> bool {
303
- !self.0.is_empty()
304
- }
305
-
306
- fn py_repr_fmt(
307
- &self,
308
- f: &mut impl Write,
309
- _vm: &VM<'_, '_, impl ResourceTracker>,
310
- _heap_ids: &mut AHashSet<HeapId>,
311
- ) -> std::fmt::Result {
312
- bytes_repr_fmt(&self.0, f)
313
- }
314
-
315
- fn py_call_attr(
316
- &mut self,
317
- _self_id: HeapId,
318
- vm: &mut VM<'_, '_, impl ResourceTracker>,
319
- attr: &EitherStr,
320
- args: ArgValues,
321
- ) -> RunResult<CallResult> {
322
- let Some(method) = attr.static_string() else {
323
- args.drop_with_heap(vm.heap);
324
- return Err(ExcType::attribute_error(Type::Bytes, attr.as_str(vm.interns)));
325
- };
326
-
327
- call_bytes_method_impl(self.as_slice(), method, args, vm).map(CallResult::Value)
328
- }
329
- }
330
-
331
- /// Calls a bytes method on a byte slice by method name.
332
- ///
333
- /// This is the entry point for bytes method calls from the VM on interned bytes.
334
- /// Converts the `StringId` to `StaticStrings` and delegates to `call_bytes_method_impl`.
335
- pub fn call_bytes_method(
336
- bytes: &[u8],
337
- method_id: StringId,
338
- args: ArgValues,
339
- vm: &mut VM<'_, '_, impl ResourceTracker>,
340
- ) -> RunResult<Value> {
341
- let Some(method) = StaticStrings::from_string_id(method_id) else {
342
- args.drop_with_heap(vm.heap);
343
- return Err(ExcType::attribute_error(Type::Bytes, vm.interns.get_str(method_id)));
344
- };
345
- call_bytes_method_impl(bytes, method, args, vm)
346
- }
347
-
348
- /// Calls a bytes method on a byte slice.
349
- ///
350
- /// This is the unified implementation for bytes method calls, used by both
351
- /// heap-allocated `Bytes` (via `py_call_attr`) and interned bytes literals
352
- /// (`Value::InternBytes`).
353
- fn call_bytes_method_impl(
354
- bytes: &[u8],
355
- method: StaticStrings,
356
- args: ArgValues,
357
- vm: &mut VM<'_, '_, impl ResourceTracker>,
358
- ) -> RunResult<Value> {
359
- let heap = &mut *vm.heap;
360
- let interns = vm.interns;
361
- match method {
362
- // Decode method
363
- StaticStrings::Decode => bytes_decode(bytes, args, heap, interns),
364
- // Simple transformations (no arguments)
365
- StaticStrings::Lower => {
366
- args.check_zero_args("bytes.lower", heap)?;
367
- bytes_lower(bytes, heap)
368
- }
369
- StaticStrings::Upper => {
370
- args.check_zero_args("bytes.upper", heap)?;
371
- bytes_upper(bytes, heap)
372
- }
373
- StaticStrings::Capitalize => {
374
- args.check_zero_args("bytes.capitalize", heap)?;
375
- bytes_capitalize(bytes, heap)
376
- }
377
- StaticStrings::Title => {
378
- args.check_zero_args("bytes.title", heap)?;
379
- bytes_title(bytes, heap)
380
- }
381
- StaticStrings::Swapcase => {
382
- args.check_zero_args("bytes.swapcase", heap)?;
383
- bytes_swapcase(bytes, heap)
384
- }
385
- // Predicate methods (no arguments, return bool)
386
- StaticStrings::Isalpha => {
387
- args.check_zero_args("bytes.isalpha", heap)?;
388
- Ok(Value::Bool(bytes_isalpha(bytes)))
389
- }
390
- StaticStrings::Isdigit => {
391
- args.check_zero_args("bytes.isdigit", heap)?;
392
- Ok(Value::Bool(bytes_isdigit(bytes)))
393
- }
394
- StaticStrings::Isalnum => {
395
- args.check_zero_args("bytes.isalnum", heap)?;
396
- Ok(Value::Bool(bytes_isalnum(bytes)))
397
- }
398
- StaticStrings::Isspace => {
399
- args.check_zero_args("bytes.isspace", heap)?;
400
- Ok(Value::Bool(bytes_isspace(bytes)))
401
- }
402
- StaticStrings::Islower => {
403
- args.check_zero_args("bytes.islower", heap)?;
404
- Ok(Value::Bool(bytes_islower(bytes)))
405
- }
406
- StaticStrings::Isupper => {
407
- args.check_zero_args("bytes.isupper", heap)?;
408
- Ok(Value::Bool(bytes_isupper(bytes)))
409
- }
410
- StaticStrings::Isascii => {
411
- args.check_zero_args("bytes.isascii", heap)?;
412
- Ok(Value::Bool(bytes.iter().all(|&b| b <= 127)))
413
- }
414
- StaticStrings::Istitle => {
415
- args.check_zero_args("bytes.istitle", heap)?;
416
- Ok(Value::Bool(bytes_istitle(bytes)))
417
- }
418
- // Search methods
419
- StaticStrings::Count => bytes_count(bytes, args, heap, interns),
420
- StaticStrings::Find => bytes_find(bytes, args, heap, interns),
421
- StaticStrings::Rfind => bytes_rfind(bytes, args, heap, interns),
422
- StaticStrings::Index => bytes_index(bytes, args, heap, interns),
423
- StaticStrings::Rindex => bytes_rindex(bytes, args, heap, interns),
424
- StaticStrings::Startswith => bytes_startswith(bytes, args, heap, interns),
425
- StaticStrings::Endswith => bytes_endswith(bytes, args, heap, interns),
426
- // Strip/trim methods
427
- StaticStrings::Strip => bytes_strip(bytes, args, heap, interns),
428
- StaticStrings::Lstrip => bytes_lstrip(bytes, args, heap, interns),
429
- StaticStrings::Rstrip => bytes_rstrip(bytes, args, heap, interns),
430
- StaticStrings::Removeprefix => bytes_removeprefix(bytes, args, heap, interns),
431
- StaticStrings::Removesuffix => bytes_removesuffix(bytes, args, heap, interns),
432
- // Split methods
433
- StaticStrings::Split => bytes_split(bytes, args, heap, interns),
434
- StaticStrings::Rsplit => bytes_rsplit(bytes, args, heap, interns),
435
- StaticStrings::Splitlines => bytes_splitlines(bytes, args, vm),
436
- StaticStrings::Partition => bytes_partition(bytes, args, heap, interns),
437
- StaticStrings::Rpartition => bytes_rpartition(bytes, args, heap, interns),
438
- // Replace/padding methods
439
- StaticStrings::Replace => bytes_replace(bytes, args, heap, interns),
440
- StaticStrings::Center => bytes_center(bytes, args, heap, interns),
441
- StaticStrings::Ljust => bytes_ljust(bytes, args, heap, interns),
442
- StaticStrings::Rjust => bytes_rjust(bytes, args, heap, interns),
443
- StaticStrings::Zfill => bytes_zfill(bytes, args, heap),
444
- // Join method
445
- StaticStrings::Join => {
446
- let iterable = args.get_one_arg("bytes.join", vm.heap)?;
447
- bytes_join(bytes, iterable, vm)
448
- }
449
- // Hex method
450
- StaticStrings::Hex => bytes_hex(bytes, args, heap, interns),
451
- // fromhex is a classmethod but also accessible on instances
452
- StaticStrings::Fromhex => bytes_fromhex(args, heap, interns),
453
- _ => {
454
- args.drop_with_heap(heap);
455
- Err(ExcType::attribute_error(Type::Bytes, method.into()))
456
- }
457
- }
458
- }
459
-
460
- /// Writes a CPython-compatible repr string for bytes to a formatter.
461
- ///
462
- /// Format: `b'...'` or `b"..."` depending on content.
463
- /// - Uses single quotes by default
464
- /// - Switches to double quotes if bytes contain `'` but not `"`
465
- /// - Escapes: `\\`, `\t`, `\n`, `\r`, `\xNN` for non-printable bytes
466
- pub fn bytes_repr_fmt(bytes: &[u8], f: &mut impl Write) -> std::fmt::Result {
467
- // Determine quote character: use double quotes if single quote present but not double
468
- let has_single = bytes.contains(&b'\'');
469
- let has_double = bytes.contains(&b'"');
470
- let quote = if has_single && !has_double { '"' } else { '\'' };
471
-
472
- f.write_char('b')?;
473
- f.write_char(quote)?;
474
-
475
- for &byte in bytes {
476
- match byte {
477
- b'\\' => f.write_str("\\\\")?,
478
- b'\t' => f.write_str("\\t")?,
479
- b'\n' => f.write_str("\\n")?,
480
- b'\r' => f.write_str("\\r")?,
481
- b'\'' if quote == '\'' => f.write_str("\\'")?,
482
- b'"' if quote == '"' => f.write_str("\\\"")?,
483
- // Printable ASCII (32-126)
484
- 0x20..=0x7e => f.write_char(byte as char)?,
485
- // Non-printable: use \xNN format
486
- _ => write!(f, "\\x{byte:02x}")?,
487
- }
488
- }
489
-
490
- f.write_char(quote)
491
- }
492
-
493
- /// Returns a CPython-compatible repr string for bytes.
494
- ///
495
- /// Convenience wrapper around `bytes_repr_fmt` that returns an owned String.
496
- #[must_use]
497
- pub fn bytes_repr(bytes: &[u8]) -> String {
498
- let mut result = String::new();
499
- // Writing to String never fails
500
- bytes_repr_fmt(bytes, &mut result).unwrap();
501
- result
502
- }
503
-
504
- /// Implements Python's `bytes.decode([encoding[, errors]])` method.
505
- ///
506
- /// Converts bytes to a string. Currently only supports UTF-8 encoding.
507
- fn bytes_decode(
508
- bytes: &[u8],
509
- args: ArgValues,
510
- heap: &mut Heap<impl ResourceTracker>,
511
- interns: &Interns,
512
- ) -> RunResult<Value> {
513
- let (encoding, errors) = args.get_zero_one_two_args("bytes.decode", heap)?;
514
- defer_drop!(encoding, heap);
515
- defer_drop!(errors, heap); // NB we don't use errors argument yet
516
-
517
- // Check encoding (default UTF-8)
518
- let encoding = if let Some(enc) = encoding {
519
- get_encoding_str(enc, heap, interns)?.to_ascii_lowercase()
520
- } else {
521
- "utf-8".to_owned()
522
- };
523
-
524
- // Only support UTF-8 family
525
- if !matches!(encoding.as_str(), "utf-8" | "utf8" | "utf_8") {
526
- return Err(ExcType::lookup_error_unknown_encoding(&encoding));
527
- }
528
-
529
- // Decode as UTF-8
530
- match std::str::from_utf8(bytes) {
531
- Ok(s) => {
532
- let heap_id = heap.allocate(HeapData::Str(Str::from(s.to_owned())))?;
533
- Ok(Value::Ref(heap_id))
534
- }
535
- Err(_) => Err(ExcType::unicode_decode_error_invalid_utf8()),
536
- }
537
- }
538
-
539
- /// Helper function to extract encoding string from a value.
540
- fn get_encoding_str<'a>(
541
- encoding: &Value,
542
- heap: &'a Heap<impl ResourceTracker>,
543
- interns: &'a Interns,
544
- ) -> RunResult<&'a str> {
545
- match encoding {
546
- Value::InternString(id) => Ok(interns.get_str(*id)),
547
- Value::Ref(id) => match heap.get(*id) {
548
- HeapData::Str(s) => Ok(s.as_str()),
549
- _ => Err(ExcType::type_error(
550
- "decode() argument 'encoding' must be str, not bytes",
551
- )),
552
- },
553
- // FIXME: should use proper encoding.py_type() here
554
- _ => Err(ExcType::type_error("decode() argument 'encoding' must be str, not int")),
555
- }
556
- }
557
-
558
- /// Implements Python's `bytes.count(sub[, start[, end]])` method.
559
- ///
560
- /// Returns the number of non-overlapping occurrences of the subsequence.
561
- fn bytes_count(
562
- bytes: &[u8],
563
- args: ArgValues,
564
- heap: &mut Heap<impl ResourceTracker>,
565
- interns: &Interns,
566
- ) -> RunResult<Value> {
567
- let (sub, start, end) = parse_bytes_sub_args("bytes.count", bytes.len(), args, heap, interns)?;
568
-
569
- let slice = &bytes[start..end];
570
- let count = if sub.is_empty() {
571
- // Empty subsequence: count positions between each byte plus 1
572
- slice.len() + 1
573
- } else {
574
- count_non_overlapping(slice, &sub)
575
- };
576
-
577
- let count_i64 = i64::try_from(count).expect("count exceeds i64::MAX");
578
- Ok(Value::Int(count_i64))
579
- }
580
-
581
- /// Counts non-overlapping occurrences of needle in haystack.
582
- fn count_non_overlapping(haystack: &[u8], needle: &[u8]) -> usize {
583
- let mut count = 0;
584
- let mut pos = 0;
585
- while pos + needle.len() <= haystack.len() {
586
- if &haystack[pos..pos + needle.len()] == needle {
587
- count += 1;
588
- pos += needle.len();
589
- } else {
590
- pos += 1;
591
- }
592
- }
593
- count
594
- }
595
-
596
- /// Implements Python's `bytes.find(sub[, start[, end]])` method.
597
- ///
598
- /// Returns the lowest index where the subsequence is found, or -1 if not found.
599
- fn bytes_find(
600
- bytes: &[u8],
601
- args: ArgValues,
602
- heap: &mut Heap<impl ResourceTracker>,
603
- interns: &Interns,
604
- ) -> RunResult<Value> {
605
- let (sub, start, end) = parse_bytes_sub_args("bytes.find", bytes.len(), args, heap, interns)?;
606
-
607
- let slice = &bytes[start..end];
608
- let result = if sub.is_empty() {
609
- // Empty subsequence: always found at start position
610
- Some(0)
611
- } else {
612
- find_subsequence(slice, &sub)
613
- };
614
-
615
- let idx = match result {
616
- Some(i) => i64::try_from(start + i).expect("index exceeds i64::MAX"),
617
- None => -1,
618
- };
619
- Ok(Value::Int(idx))
620
- }
621
-
622
- /// Finds the first occurrence of needle in haystack.
623
- fn find_subsequence(haystack: &[u8], needle: &[u8]) -> Option<usize> {
624
- haystack.windows(needle.len()).position(|window| window == needle)
625
- }
626
-
627
- /// Implements Python's `bytes.index(sub[, start[, end]])` method.
628
- ///
629
- /// Like find(), but raises ValueError if the subsequence is not found.
630
- fn bytes_index(
631
- bytes: &[u8],
632
- args: ArgValues,
633
- heap: &mut Heap<impl ResourceTracker>,
634
- interns: &Interns,
635
- ) -> RunResult<Value> {
636
- let (sub, start, end) = parse_bytes_sub_args("bytes.index", bytes.len(), args, heap, interns)?;
637
-
638
- let slice = &bytes[start..end];
639
- let result = if sub.is_empty() {
640
- // Empty subsequence: always found at start position
641
- Some(0)
642
- } else {
643
- find_subsequence(slice, &sub)
644
- };
645
-
646
- match result {
647
- Some(i) => {
648
- let idx = i64::try_from(start + i).expect("index exceeds i64::MAX");
649
- Ok(Value::Int(idx))
650
- }
651
- None => Err(ExcType::value_error_subsequence_not_found()),
652
- }
653
- }
654
-
655
- /// Implements Python's `bytes.startswith(prefix[, start[, end]])` method.
656
- ///
657
- /// Returns True if bytes starts with the specified prefix.
658
- /// Accepts bytes or a tuple of bytes as prefix. If a tuple is given, returns True
659
- /// if any of the prefixes match.
660
- fn bytes_startswith(
661
- bytes: &[u8],
662
- args: ArgValues,
663
- heap: &mut Heap<impl ResourceTracker>,
664
- interns: &Interns,
665
- ) -> RunResult<Value> {
666
- let (prefix_arg, start, end) =
667
- parse_bytes_prefix_suffix_args("bytes.startswith", bytes.len(), args, heap, interns)?;
668
-
669
- let slice = &bytes[start..end];
670
- let result = match prefix_arg {
671
- PrefixSuffixArg::Single(prefix_bytes) => slice.starts_with(&prefix_bytes),
672
- PrefixSuffixArg::Multiple(prefixes) => prefixes.iter().any(|p| slice.starts_with(p)),
673
- };
674
- Ok(Value::Bool(result))
675
- }
676
-
677
- /// Implements Python's `bytes.endswith(suffix[, start[, end]])` method.
678
- ///
679
- /// Returns True if bytes ends with the specified suffix.
680
- /// Accepts bytes or a tuple of bytes as suffix. If a tuple is given, returns True
681
- /// if any of the suffixes match.
682
- fn bytes_endswith(
683
- bytes: &[u8],
684
- args: ArgValues,
685
- heap: &mut Heap<impl ResourceTracker>,
686
- interns: &Interns,
687
- ) -> RunResult<Value> {
688
- let (suffix_arg, start, end) = parse_bytes_prefix_suffix_args("bytes.endswith", bytes.len(), args, heap, interns)?;
689
-
690
- let slice = &bytes[start..end];
691
- let result = match suffix_arg {
692
- PrefixSuffixArg::Single(suffix_bytes) => slice.ends_with(&suffix_bytes),
693
- PrefixSuffixArg::Multiple(suffixes) => suffixes.iter().any(|s| slice.ends_with(s)),
694
- };
695
- Ok(Value::Bool(result))
696
- }
697
-
698
- /// Argument type for prefix/suffix matching methods.
699
- ///
700
- /// Represents either a single bytes value or a tuple of bytes values
701
- /// for matching in startswith/endswith.
702
- enum PrefixSuffixArg {
703
- /// A single bytes value to match
704
- Single(Vec<u8>),
705
- /// Multiple bytes values to match (from a tuple)
706
- Multiple(Vec<Vec<u8>>),
707
- }
708
-
709
- /// Parses arguments for bytes.startswith/endswith methods.
710
- ///
711
- /// Returns (prefix/suffix_arg, start, end) where start and end are normalized indices.
712
- /// The prefix/suffix_arg can be a single bytes value or a tuple of bytes values.
713
- /// Guarantees `start <= end` to prevent slice panics.
714
- fn parse_bytes_prefix_suffix_args(
715
- method: &str,
716
- len: usize,
717
- args: ArgValues,
718
- heap: &mut Heap<impl ResourceTracker>,
719
- interns: &Interns,
720
- ) -> RunResult<(PrefixSuffixArg, usize, usize)> {
721
- let pos = args.into_pos_only(method, heap)?;
722
- defer_drop!(pos, heap);
723
-
724
- let (prefix, start, end) = match pos.as_slice() {
725
- [prefix_value] => {
726
- let prefix = extract_bytes_for_prefix_suffix(prefix_value, method, heap, interns)?;
727
- (prefix, 0, len)
728
- }
729
- [prefix_value, start_value] => {
730
- let prefix = extract_bytes_for_prefix_suffix(prefix_value, method, heap, interns)?;
731
- let start = normalize_bytes_index(start_value.as_int(heap)?, len);
732
- (prefix, start, len)
733
- }
734
- [prefix_value, start_value, end_value] => {
735
- let prefix = extract_bytes_for_prefix_suffix(prefix_value, method, heap, interns)?;
736
- let start = normalize_bytes_index(start_value.as_int(heap)?, len);
737
- let end = normalize_bytes_index(end_value.as_int(heap)?, len);
738
- (prefix, start, end)
739
- }
740
- [] => return Err(ExcType::type_error_at_least(method, 1, 0)),
741
- _ => return Err(ExcType::type_error_at_most(method, 3, pos.len())),
742
- };
743
-
744
- // Ensure start <= end to prevent slice panics
745
- Ok((prefix, start, end.max(start)))
746
- }
747
-
748
- /// Extracts bytes (or tuple of bytes) for startswith/endswith methods.
749
- ///
750
- /// Returns `PrefixSuffixArg::Single` for a single bytes value, or
751
- /// `PrefixSuffixArg::Multiple` for a tuple of bytes values.
752
- fn extract_bytes_for_prefix_suffix(
753
- value: &Value,
754
- method: &str,
755
- heap: &Heap<impl ResourceTracker>,
756
- interns: &Interns,
757
- ) -> RunResult<PrefixSuffixArg> {
758
- // Extract the method name (e.g., "startswith" from "bytes.startswith")
759
- let method_name = method.strip_prefix("bytes.").unwrap_or(method);
760
-
761
- match value {
762
- Value::InternBytes(id) => Ok(PrefixSuffixArg::Single(interns.get_bytes(*id).to_vec())),
763
- Value::InternString(_) => Err(ExcType::type_error(format!(
764
- "{method_name} first arg must be bytes or a tuple of bytes, not str"
765
- ))),
766
- Value::Ref(id) => match heap.get(*id) {
767
- HeapData::Bytes(b) => Ok(PrefixSuffixArg::Single(b.as_slice().to_vec())),
768
- HeapData::Str(_) => Err(ExcType::type_error(format!(
769
- "{method_name} first arg must be bytes or a tuple of bytes, not str"
770
- ))),
771
- HeapData::Tuple(tuple) => {
772
- // Extract each element as bytes
773
- let items = tuple.as_slice();
774
- let mut prefixes = Vec::with_capacity(items.len());
775
- for (i, item) in items.iter().enumerate() {
776
- if let Ok(b) = extract_single_bytes_for_prefix_suffix(item, heap, interns) {
777
- prefixes.push(b);
778
- } else {
779
- let item_type = item.py_type(heap);
780
- return Err(ExcType::type_error(format!(
781
- "{method_name} first arg must be bytes or a tuple of bytes, \
782
- not tuple containing {item_type} at index {i}"
783
- )));
784
- }
785
- }
786
- Ok(PrefixSuffixArg::Multiple(prefixes))
787
- }
788
- _ => Err(ExcType::type_error(format!(
789
- "{method_name} first arg must be bytes or a tuple of bytes, not {}",
790
- value.py_type(heap)
791
- ))),
792
- },
793
- _ => Err(ExcType::type_error(format!(
794
- "{method_name} first arg must be bytes or a tuple of bytes, not {}",
795
- value.py_type(heap)
796
- ))),
797
- }
798
- }
799
-
800
- /// Extracts a single bytes value for tuple element in startswith/endswith.
801
- fn extract_single_bytes_for_prefix_suffix(
802
- value: &Value,
803
- heap: &Heap<impl ResourceTracker>,
804
- interns: &Interns,
805
- ) -> RunResult<Vec<u8>> {
806
- match value {
807
- Value::InternBytes(id) => Ok(interns.get_bytes(*id).to_vec()),
808
- Value::InternString(_) => Err(ExcType::type_error("expected bytes, not str")),
809
- Value::Ref(id) => match heap.get(*id) {
810
- HeapData::Bytes(b) => Ok(b.as_slice().to_vec()),
811
- _ => Err(ExcType::type_error("expected bytes")),
812
- },
813
- _ => Err(ExcType::type_error("expected bytes")),
814
- }
815
- }
816
-
817
- /// Extracts bytes from a Value (bytes only, NOT str - matches CPython behavior).
818
- ///
819
- /// CPython raises `TypeError: a bytes-like object is required, not 'str'` when
820
- /// a str is passed to bytes methods like find, count, index, startswith, endswith.
821
- fn extract_bytes_only<'a>(
822
- value: &Value,
823
- heap: &'a Heap<impl ResourceTracker>,
824
- interns: &'a Interns,
825
- ) -> RunResult<&'a [u8]> {
826
- match value {
827
- Value::InternBytes(id) => Ok(interns.get_bytes(*id)),
828
- Value::InternString(_) => Err(ExcType::type_error("a bytes-like object is required, not 'str'")),
829
- Value::Ref(id) => match heap.get(*id) {
830
- HeapData::Bytes(b) => Ok(b.as_slice()),
831
- HeapData::Str(_) => Err(ExcType::type_error("a bytes-like object is required, not 'str'")),
832
- _ => Err(ExcType::type_error("a bytes-like object is required")),
833
- },
834
- _ => Err(ExcType::type_error("a bytes-like object is required")),
835
- }
836
- }
837
-
838
- /// Parses arguments for bytes.find/count/index methods.
839
- ///
840
- /// Returns (sub_bytes, start, end) where start and end are normalized indices.
841
- /// Guarantees `start <= end` to prevent slice panics.
842
- fn parse_bytes_sub_args(
843
- method: &str,
844
- len: usize,
845
- args: ArgValues,
846
- heap: &mut Heap<impl ResourceTracker>,
847
- interns: &Interns,
848
- ) -> RunResult<(Vec<u8>, usize, usize)> {
849
- let pos = args.into_pos_only(method, heap)?;
850
- defer_drop!(pos, heap);
851
-
852
- let (sub, start, end) = match pos.as_slice() {
853
- [sub_value] => {
854
- let sub = extract_bytes_only(sub_value, heap, interns)?;
855
- (sub, 0, len)
856
- }
857
- [sub_value, start_value] => {
858
- let sub = extract_bytes_only(sub_value, heap, interns)?;
859
- let start = normalize_bytes_index(start_value.as_int(heap)?, len);
860
- (sub, start, len)
861
- }
862
- [sub_value, start_value, end_value] => {
863
- let sub = extract_bytes_only(sub_value, heap, interns)?;
864
- let start = normalize_bytes_index(start_value.as_int(heap)?, len);
865
- let end = normalize_bytes_index(end_value.as_int(heap)?, len);
866
- (sub, start, end)
867
- }
868
- [] => return Err(ExcType::type_error_at_least(method, 1, 0)),
869
- _ => return Err(ExcType::type_error_at_most(method, 3, pos.len())),
870
- };
871
-
872
- // Ensure start <= end to prevent slice panics (Python treats start > end as empty slice)
873
- Ok((sub.to_owned(), start, end.max(start)))
874
- }
875
-
876
- /// Normalizes a Python-style bytes index to a valid index in range [0, len].
877
- fn normalize_bytes_index(index: i64, len: usize) -> usize {
878
- if index < 0 {
879
- let abs_index = usize::try_from(-index).unwrap_or(usize::MAX);
880
- len.saturating_sub(abs_index)
881
- } else {
882
- usize::try_from(index).unwrap_or(len).min(len)
883
- }
884
- }
885
-
886
- // =============================================================================
887
- // Simple transformations (no arguments)
888
- // =============================================================================
889
-
890
- /// Implements Python's `bytes.lower()` method.
891
- ///
892
- /// Returns a copy of the bytes with all ASCII uppercase characters converted to lowercase.
893
- fn bytes_lower(bytes: &[u8], heap: &mut Heap<impl ResourceTracker>) -> RunResult<Value> {
894
- let result: Vec<u8> = bytes.iter().map(|&b| b.to_ascii_lowercase()).collect();
895
- allocate_bytes(result, heap)
896
- }
897
-
898
- /// Implements Python's `bytes.upper()` method.
899
- ///
900
- /// Returns a copy of the bytes with all ASCII lowercase characters converted to uppercase.
901
- fn bytes_upper(bytes: &[u8], heap: &mut Heap<impl ResourceTracker>) -> RunResult<Value> {
902
- let result: Vec<u8> = bytes.iter().map(|&b| b.to_ascii_uppercase()).collect();
903
- allocate_bytes(result, heap)
904
- }
905
-
906
- /// Implements Python's `bytes.capitalize()` method.
907
- ///
908
- /// Returns a copy of the bytes with the first byte capitalized (if ASCII) and
909
- /// the rest lowercased.
910
- fn bytes_capitalize(bytes: &[u8], heap: &mut Heap<impl ResourceTracker>) -> RunResult<Value> {
911
- let mut result = Vec::with_capacity(bytes.len());
912
- if let Some((&first, rest)) = bytes.split_first() {
913
- result.push(first.to_ascii_uppercase());
914
- for &b in rest {
915
- result.push(b.to_ascii_lowercase());
916
- }
917
- }
918
- allocate_bytes(result, heap)
919
- }
920
-
921
- /// Implements Python's `bytes.title()` method.
922
- ///
923
- /// Returns a titlecased version of the bytes where words start with an uppercase
924
- /// ASCII character and the remaining characters are lowercase.
925
- fn bytes_title(bytes: &[u8], heap: &mut Heap<impl ResourceTracker>) -> RunResult<Value> {
926
- let mut result = Vec::with_capacity(bytes.len());
927
- let mut prev_is_cased = false;
928
-
929
- for &b in bytes {
930
- if prev_is_cased {
931
- result.push(b.to_ascii_lowercase());
932
- } else {
933
- result.push(b.to_ascii_uppercase());
934
- }
935
- prev_is_cased = b.is_ascii_alphabetic();
936
- }
937
-
938
- allocate_bytes(result, heap)
939
- }
940
-
941
- /// Implements Python's `bytes.swapcase()` method.
942
- ///
943
- /// Returns a copy of the bytes with ASCII uppercase characters converted to
944
- /// lowercase and vice versa.
945
- fn bytes_swapcase(bytes: &[u8], heap: &mut Heap<impl ResourceTracker>) -> RunResult<Value> {
946
- let result: Vec<u8> = bytes
947
- .iter()
948
- .map(|&b| {
949
- if b.is_ascii_uppercase() {
950
- b.to_ascii_lowercase()
951
- } else if b.is_ascii_lowercase() {
952
- b.to_ascii_uppercase()
953
- } else {
954
- b
955
- }
956
- })
957
- .collect();
958
- allocate_bytes(result, heap)
959
- }
960
-
961
- // =============================================================================
962
- // Predicate methods (no arguments, return bool)
963
- // =============================================================================
964
-
965
- /// Implements Python's `bytes.isalpha()` method.
966
- ///
967
- /// Returns True if all bytes in the bytes are ASCII letters and there is at least one byte.
968
- fn bytes_isalpha(bytes: &[u8]) -> bool {
969
- !bytes.is_empty() && bytes.iter().all(|&b| b.is_ascii_alphabetic())
970
- }
971
-
972
- /// Implements Python's `bytes.isdigit()` method.
973
- ///
974
- /// Returns True if all bytes in the bytes are ASCII digits and there is at least one byte.
975
- fn bytes_isdigit(bytes: &[u8]) -> bool {
976
- !bytes.is_empty() && bytes.iter().all(|&b| b.is_ascii_digit())
977
- }
978
-
979
- /// Implements Python's `bytes.isalnum()` method.
980
- ///
981
- /// Returns True if all bytes in the bytes are ASCII alphanumeric and there is at least one byte.
982
- fn bytes_isalnum(bytes: &[u8]) -> bool {
983
- !bytes.is_empty() && bytes.iter().all(|&b| b.is_ascii_alphanumeric())
984
- }
985
-
986
- /// Implements Python's `bytes.isspace()` method.
987
- ///
988
- /// Returns True if all bytes in the bytes are ASCII whitespace and there is at least one byte.
989
- fn bytes_isspace(bytes: &[u8]) -> bool {
990
- !bytes.is_empty() && bytes.iter().all(|&b| is_py_whitespace(b))
991
- }
992
-
993
- /// Implements Python's `bytes.islower()` method.
994
- ///
995
- /// Returns True if all cased bytes are lowercase and there is at least one cased byte.
996
- fn bytes_islower(bytes: &[u8]) -> bool {
997
- let mut has_cased = false;
998
- for &b in bytes {
999
- if b.is_ascii_uppercase() {
1000
- return false;
1001
- }
1002
- if b.is_ascii_lowercase() {
1003
- has_cased = true;
1004
- }
1005
- }
1006
- has_cased
1007
- }
1008
-
1009
- /// Implements Python's `bytes.isupper()` method.
1010
- ///
1011
- /// Returns True if all cased bytes are uppercase and there is at least one cased byte.
1012
- fn bytes_isupper(bytes: &[u8]) -> bool {
1013
- let mut has_cased = false;
1014
- for &b in bytes {
1015
- if b.is_ascii_lowercase() {
1016
- return false;
1017
- }
1018
- if b.is_ascii_uppercase() {
1019
- has_cased = true;
1020
- }
1021
- }
1022
- has_cased
1023
- }
1024
-
1025
- /// Implements Python's `bytes.istitle()` method.
1026
- ///
1027
- /// Returns True if the bytes are titlecased: uppercase characters follow
1028
- /// uncased characters and lowercase characters follow cased characters.
1029
- fn bytes_istitle(bytes: &[u8]) -> bool {
1030
- if bytes.is_empty() {
1031
- return false;
1032
- }
1033
-
1034
- let mut prev_cased = false;
1035
- let mut has_cased = false;
1036
-
1037
- for &b in bytes {
1038
- if b.is_ascii_uppercase() {
1039
- if prev_cased {
1040
- return false;
1041
- }
1042
- prev_cased = true;
1043
- has_cased = true;
1044
- } else if b.is_ascii_lowercase() {
1045
- if !prev_cased {
1046
- return false;
1047
- }
1048
- prev_cased = true;
1049
- has_cased = true;
1050
- } else {
1051
- prev_cased = false;
1052
- }
1053
- }
1054
-
1055
- has_cased
1056
- }
1057
-
1058
- // =============================================================================
1059
- // Search methods
1060
- // =============================================================================
1061
-
1062
- /// Implements Python's `bytes.rfind(sub[, start[, end]])` method.
1063
- ///
1064
- /// Returns the highest index where the subsequence is found, or -1 if not found.
1065
- fn bytes_rfind(
1066
- bytes: &[u8],
1067
- args: ArgValues,
1068
- heap: &mut Heap<impl ResourceTracker>,
1069
- interns: &Interns,
1070
- ) -> RunResult<Value> {
1071
- let (sub, start, end) = parse_bytes_sub_args("bytes.rfind", bytes.len(), args, heap, interns)?;
1072
-
1073
- let slice = &bytes[start..end];
1074
- let result = if sub.is_empty() {
1075
- // Empty subsequence: always found at end position
1076
- Some(slice.len())
1077
- } else {
1078
- rfind_subsequence(slice, &sub)
1079
- };
1080
-
1081
- let idx = match result {
1082
- Some(i) => i64::try_from(start + i).expect("index exceeds i64::MAX"),
1083
- None => -1,
1084
- };
1085
- Ok(Value::Int(idx))
1086
- }
1087
-
1088
- /// Finds the last occurrence of needle in haystack.
1089
- fn rfind_subsequence(haystack: &[u8], needle: &[u8]) -> Option<usize> {
1090
- if needle.len() > haystack.len() {
1091
- return None;
1092
- }
1093
- haystack.windows(needle.len()).rposition(|window| window == needle)
1094
- }
1095
-
1096
- /// Implements Python's `bytes.rindex(sub[, start[, end]])` method.
1097
- ///
1098
- /// Like rfind(), but raises ValueError if the subsequence is not found.
1099
- fn bytes_rindex(
1100
- bytes: &[u8],
1101
- args: ArgValues,
1102
- heap: &mut Heap<impl ResourceTracker>,
1103
- interns: &Interns,
1104
- ) -> RunResult<Value> {
1105
- let (sub, start, end) = parse_bytes_sub_args("bytes.rindex", bytes.len(), args, heap, interns)?;
1106
-
1107
- let slice = &bytes[start..end];
1108
- let result = if sub.is_empty() {
1109
- Some(slice.len())
1110
- } else {
1111
- rfind_subsequence(slice, &sub)
1112
- };
1113
-
1114
- match result {
1115
- Some(i) => {
1116
- let idx = i64::try_from(start + i).expect("index exceeds i64::MAX");
1117
- Ok(Value::Int(idx))
1118
- }
1119
- None => Err(ExcType::value_error_subsequence_not_found()),
1120
- }
1121
- }
1122
-
1123
- // =============================================================================
1124
- // Strip/trim methods
1125
- // =============================================================================
1126
-
1127
- /// Implements Python's `bytes.strip([chars])` method.
1128
- ///
1129
- /// Returns a copy of the bytes with leading and trailing bytes removed.
1130
- /// If chars is not specified, ASCII whitespace bytes are removed.
1131
- fn bytes_strip(
1132
- bytes: &[u8],
1133
- args: ArgValues,
1134
- heap: &mut Heap<impl ResourceTracker>,
1135
- interns: &Interns,
1136
- ) -> RunResult<Value> {
1137
- let value = args.get_zero_one_arg("bytes.strip", heap)?;
1138
- defer_drop!(value, heap);
1139
- let result = match value {
1140
- None | Some(Value::None) => bytes_strip_whitespace_both(bytes),
1141
- Some(v) => bytes_strip_both(bytes, extract_bytes_only(v, heap, interns)?),
1142
- };
1143
- allocate_bytes(result.to_vec(), heap)
1144
- }
1145
-
1146
- /// Implements Python's `bytes.lstrip([chars])` method.
1147
- ///
1148
- /// Returns a copy of the bytes with leading bytes removed.
1149
- fn bytes_lstrip(
1150
- bytes: &[u8],
1151
- args: ArgValues,
1152
- heap: &mut Heap<impl ResourceTracker>,
1153
- interns: &Interns,
1154
- ) -> RunResult<Value> {
1155
- let value = args.get_zero_one_arg("bytes.lstrip", heap)?;
1156
- defer_drop!(value, heap);
1157
- let result = match value {
1158
- None | Some(Value::None) => bytes_strip_whitespace_start(bytes),
1159
- Some(v) => bytes_strip_start(bytes, extract_bytes_only(v, heap, interns)?),
1160
- };
1161
- allocate_bytes(result.to_vec(), heap)
1162
- }
1163
-
1164
- /// Implements Python's `bytes.rstrip([chars])` method.
1165
- ///
1166
- /// Returns a copy of the bytes with trailing bytes removed.
1167
- fn bytes_rstrip(
1168
- bytes: &[u8],
1169
- args: ArgValues,
1170
- heap: &mut Heap<impl ResourceTracker>,
1171
- interns: &Interns,
1172
- ) -> RunResult<Value> {
1173
- let value = args.get_zero_one_arg("bytes.rstrip", heap)?;
1174
- defer_drop!(value, heap);
1175
- let result = match value {
1176
- None | Some(Value::None) => bytes_strip_whitespace_end(bytes),
1177
- Some(v) => bytes_strip_end(bytes, extract_bytes_only(v, heap, interns)?),
1178
- };
1179
- allocate_bytes(result.to_vec(), heap)
1180
- }
1181
-
1182
- /// Strips bytes in `chars` from both ends of the byte slice.
1183
- fn bytes_strip_both<'a>(bytes: &'a [u8], chars: &[u8]) -> &'a [u8] {
1184
- let start = bytes.iter().position(|b| !chars.contains(b)).unwrap_or(bytes.len());
1185
- let end = bytes
1186
- .iter()
1187
- .rposition(|b| !chars.contains(b))
1188
- .map_or(start, |pos| pos + 1);
1189
- &bytes[start..end]
1190
- }
1191
-
1192
- /// Strips bytes in `chars` from the start of the byte slice.
1193
- fn bytes_strip_start<'a>(bytes: &'a [u8], chars: &[u8]) -> &'a [u8] {
1194
- let start = bytes.iter().position(|b| !chars.contains(b)).unwrap_or(bytes.len());
1195
- &bytes[start..]
1196
- }
1197
-
1198
- /// Strips bytes in `chars` from the end of the byte slice.
1199
- fn bytes_strip_end<'a>(bytes: &'a [u8], chars: &[u8]) -> &'a [u8] {
1200
- let end = bytes.iter().rposition(|b| !chars.contains(b)).map_or(0, |pos| pos + 1);
1201
- &bytes[..end]
1202
- }
1203
-
1204
- /// Strips ASCII whitespace from both ends of the byte slice.
1205
- fn bytes_strip_whitespace_both(bytes: &[u8]) -> &[u8] {
1206
- let start = bytes.iter().position(|b| !is_py_whitespace(*b)).unwrap_or(bytes.len());
1207
- let end = bytes
1208
- .iter()
1209
- .rposition(|b| !is_py_whitespace(*b))
1210
- .map_or(start, |pos| pos + 1);
1211
- &bytes[start..end]
1212
- }
1213
-
1214
- /// Strips ASCII whitespace from the start of the byte slice.
1215
- fn bytes_strip_whitespace_start(bytes: &[u8]) -> &[u8] {
1216
- let start = bytes.iter().position(|b| !is_py_whitespace(*b)).unwrap_or(bytes.len());
1217
- &bytes[start..]
1218
- }
1219
-
1220
- /// Strips ASCII whitespace from the end of the byte slice.
1221
- fn bytes_strip_whitespace_end(bytes: &[u8]) -> &[u8] {
1222
- let end = bytes
1223
- .iter()
1224
- .rposition(|b| !is_py_whitespace(*b))
1225
- .map_or(0, |pos| pos + 1);
1226
- &bytes[..end]
1227
- }
1228
-
1229
- /// Implements Python's `bytes.removeprefix(prefix)` method.
1230
- ///
1231
- /// If the bytes start with the prefix, return bytes[len(prefix):].
1232
- /// Otherwise, return a copy of the original bytes.
1233
- fn bytes_removeprefix(
1234
- bytes: &[u8],
1235
- args: ArgValues,
1236
- heap: &mut Heap<impl ResourceTracker>,
1237
- interns: &Interns,
1238
- ) -> RunResult<Value> {
1239
- let prefix_value = args.get_one_arg("bytes.removeprefix", heap)?;
1240
- defer_drop!(prefix_value, heap);
1241
- let prefix = extract_bytes_only(prefix_value, heap, interns)?;
1242
-
1243
- let result = if bytes.starts_with(prefix) {
1244
- bytes[prefix.len()..].to_vec()
1245
- } else {
1246
- bytes.to_vec()
1247
- };
1248
- allocate_bytes(result, heap)
1249
- }
1250
-
1251
- /// Implements Python's `bytes.removesuffix(suffix)` method.
1252
- ///
1253
- /// If the bytes end with the suffix, return bytes[:-len(suffix)].
1254
- /// Otherwise, return a copy of the original bytes.
1255
- fn bytes_removesuffix(
1256
- bytes: &[u8],
1257
- args: ArgValues,
1258
- heap: &mut Heap<impl ResourceTracker>,
1259
- interns: &Interns,
1260
- ) -> RunResult<Value> {
1261
- let suffix_value = args.get_one_arg("bytes.removesuffix", heap)?;
1262
- defer_drop!(suffix_value, heap);
1263
- let suffix = extract_bytes_only(suffix_value, heap, interns)?;
1264
-
1265
- let result = if bytes.ends_with(suffix) && !suffix.is_empty() {
1266
- bytes[..bytes.len() - suffix.len()].to_vec()
1267
- } else {
1268
- bytes.to_vec()
1269
- };
1270
- allocate_bytes(result, heap)
1271
- }
1272
-
1273
- // =============================================================================
1274
- // Split methods
1275
- // =============================================================================
1276
-
1277
- /// Implements Python's `bytes.split([sep[, maxsplit]])` method.
1278
- ///
1279
- /// Returns a list of the bytes split by the separator.
1280
- fn bytes_split(
1281
- bytes: &[u8],
1282
- args: ArgValues,
1283
- heap: &mut Heap<impl ResourceTracker>,
1284
- interns: &Interns,
1285
- ) -> RunResult<Value> {
1286
- let (sep, maxsplit) = parse_bytes_split_args("bytes.split", args, heap, interns)?;
1287
-
1288
- let parts: Vec<&[u8]> = match &sep {
1289
- Some(sep) => {
1290
- if sep.is_empty() {
1291
- return Err(ExcType::value_error_empty_separator());
1292
- }
1293
- if maxsplit < 0 {
1294
- bytes_split_by_seq(bytes, sep)
1295
- } else {
1296
- let max = usize::try_from(maxsplit).unwrap_or(usize::MAX);
1297
- bytes_splitn_by_seq(bytes, sep, max + 1)
1298
- }
1299
- }
1300
- None => {
1301
- if maxsplit < 0 {
1302
- bytes_split_whitespace(bytes)
1303
- } else {
1304
- let max = usize::try_from(maxsplit).unwrap_or(usize::MAX);
1305
- bytes_splitn_whitespace(bytes, max)
1306
- }
1307
- }
1308
- };
1309
-
1310
- let mut list_items = Vec::with_capacity(parts.len());
1311
- for part in parts {
1312
- heap.check_time()?;
1313
- list_items.push(allocate_bytes(part.to_vec(), heap)?);
1314
- }
1315
-
1316
- let list = List::new(list_items);
1317
- let heap_id = heap.allocate(HeapData::List(list))?;
1318
- Ok(Value::Ref(heap_id))
1319
- }
1320
-
1321
- /// Implements Python's `bytes.rsplit([sep[, maxsplit]])` method.
1322
- ///
1323
- /// Returns a list of the bytes split by the separator, splitting from the right.
1324
- fn bytes_rsplit(
1325
- bytes: &[u8],
1326
- args: ArgValues,
1327
- heap: &mut Heap<impl ResourceTracker>,
1328
- interns: &Interns,
1329
- ) -> RunResult<Value> {
1330
- let (sep, maxsplit) = parse_bytes_split_args("bytes.rsplit", args, heap, interns)?;
1331
-
1332
- let parts: Vec<&[u8]> = match &sep {
1333
- Some(sep) => {
1334
- if sep.is_empty() {
1335
- return Err(ExcType::value_error_empty_separator());
1336
- }
1337
- if maxsplit < 0 {
1338
- bytes_split_by_seq(bytes, sep)
1339
- } else {
1340
- let max = usize::try_from(maxsplit).unwrap_or(usize::MAX);
1341
- bytes_rsplitn_by_seq(bytes, sep, max + 1)
1342
- }
1343
- }
1344
- None => {
1345
- if maxsplit < 0 {
1346
- bytes_split_whitespace(bytes)
1347
- } else {
1348
- let max = usize::try_from(maxsplit).unwrap_or(usize::MAX);
1349
- bytes_rsplitn_whitespace(bytes, max)
1350
- }
1351
- }
1352
- };
1353
-
1354
- let mut list_items = Vec::with_capacity(parts.len());
1355
- for part in parts {
1356
- heap.check_time()?;
1357
- list_items.push(allocate_bytes(part.to_vec(), heap)?);
1358
- }
1359
-
1360
- let list = List::new(list_items);
1361
- let heap_id = heap.allocate(HeapData::List(list))?;
1362
- Ok(Value::Ref(heap_id))
1363
- }
1364
-
1365
- /// Parses arguments for bytes split methods.
1366
- fn parse_bytes_split_args(
1367
- method: &str,
1368
- args: ArgValues,
1369
- heap: &mut Heap<impl ResourceTracker>,
1370
- interns: &Interns,
1371
- ) -> RunResult<(Option<Vec<u8>>, i64)> {
1372
- let (pos_iter, kwargs) = args.into_parts();
1373
- defer_drop_mut!(pos_iter, heap);
1374
- let kwargs_iter = kwargs.into_iter();
1375
- defer_drop_mut!(kwargs_iter, heap);
1376
-
1377
- let sep_value = pos_iter.next();
1378
- defer_drop_mut!(sep_value, heap);
1379
- let maxsplit_value = pos_iter.next();
1380
- defer_drop_mut!(maxsplit_value, heap);
1381
-
1382
- // Check no extra positional arguments
1383
- if pos_iter.len() != 0 {
1384
- return Err(ExcType::type_error_at_most(method, 2, 3));
1385
- }
1386
-
1387
- // Process keyword arguments
1388
- for (key, value) in kwargs_iter {
1389
- defer_drop!(key, heap);
1390
- let mut value_guard = HeapGuard::new(value, heap);
1391
-
1392
- let Some(keyword_name) = key.as_either_str(value_guard.heap()) else {
1393
- return Err(ExcType::type_error("keywords must be strings"));
1394
- };
1395
-
1396
- let key_str = keyword_name.as_str(interns);
1397
- match key_str {
1398
- "sep" => {
1399
- if let Some(previous_value) = sep_value.replace(value_guard.into_inner()) {
1400
- previous_value.drop_with_heap(heap);
1401
- return Err(ExcType::type_error(format!(
1402
- "{method}() got multiple values for argument 'sep'"
1403
- )));
1404
- }
1405
- }
1406
- "maxsplit" => {
1407
- if let Some(previous_value) = maxsplit_value.replace(value_guard.into_inner()) {
1408
- previous_value.drop_with_heap(heap);
1409
- return Err(ExcType::type_error(format!(
1410
- "{method}() got multiple values for argument 'maxsplit'"
1411
- )));
1412
- }
1413
- }
1414
- _ => {
1415
- return Err(ExcType::type_error(format!(
1416
- "'{key_str}' is an invalid keyword argument for {method}()"
1417
- )));
1418
- }
1419
- }
1420
- }
1421
-
1422
- // Extract sep (default None)
1423
- let sep = if let Some(v) = sep_value {
1424
- if matches!(v, Value::None) {
1425
- None
1426
- } else {
1427
- Some(extract_bytes_only(v, heap, interns)?.to_owned())
1428
- }
1429
- } else {
1430
- None
1431
- };
1432
-
1433
- // Extract maxsplit (default -1)
1434
- let maxsplit = if let Some(v) = maxsplit_value {
1435
- v.as_int(heap)?
1436
- } else {
1437
- -1
1438
- };
1439
-
1440
- Ok((sep, maxsplit))
1441
- }
1442
-
1443
- /// Splits bytes by a separator sequence.
1444
- fn bytes_split_by_seq<'a>(bytes: &'a [u8], sep: &[u8]) -> Vec<&'a [u8]> {
1445
- let mut parts = Vec::new();
1446
- let mut start = 0;
1447
-
1448
- while let Some(pos) = find_subsequence(&bytes[start..], sep) {
1449
- parts.push(&bytes[start..start + pos]);
1450
- start = start + pos + sep.len();
1451
- }
1452
- parts.push(&bytes[start..]);
1453
-
1454
- parts
1455
- }
1456
-
1457
- /// Splits bytes by a separator sequence, returning at most n parts.
1458
- fn bytes_splitn_by_seq<'a>(bytes: &'a [u8], sep: &[u8], n: usize) -> Vec<&'a [u8]> {
1459
- let mut parts = Vec::new();
1460
- let mut start = 0;
1461
- let mut count = 0;
1462
-
1463
- while count + 1 < n {
1464
- if let Some(pos) = find_subsequence(&bytes[start..], sep) {
1465
- parts.push(&bytes[start..start + pos]);
1466
- start = start + pos + sep.len();
1467
- count += 1;
1468
- } else {
1469
- break;
1470
- }
1471
- }
1472
- parts.push(&bytes[start..]);
1473
-
1474
- parts
1475
- }
1476
-
1477
- /// Splits bytes by a separator sequence from the right, returning at most n parts.
1478
- fn bytes_rsplitn_by_seq<'a>(bytes: &'a [u8], sep: &[u8], n: usize) -> Vec<&'a [u8]> {
1479
- let mut parts = Vec::new();
1480
- let mut end = bytes.len();
1481
- let mut count = 0;
1482
-
1483
- while count + 1 < n {
1484
- if let Some(pos) = rfind_subsequence(&bytes[..end], sep) {
1485
- parts.push(&bytes[pos + sep.len()..end]);
1486
- end = pos;
1487
- count += 1;
1488
- } else {
1489
- break;
1490
- }
1491
- }
1492
- parts.push(&bytes[..end]);
1493
- parts.reverse();
1494
-
1495
- parts
1496
- }
1497
-
1498
- /// Splits bytes by ASCII whitespace, filtering empty parts.
1499
- fn bytes_split_whitespace(bytes: &[u8]) -> Vec<&[u8]> {
1500
- let mut parts = Vec::new();
1501
- let mut start = None;
1502
-
1503
- for (i, &b) in bytes.iter().enumerate() {
1504
- if is_py_whitespace(b) {
1505
- if let Some(s) = start {
1506
- parts.push(&bytes[s..i]);
1507
- start = None;
1508
- }
1509
- } else if start.is_none() {
1510
- start = Some(i);
1511
- }
1512
- }
1513
-
1514
- if let Some(s) = start {
1515
- parts.push(&bytes[s..]);
1516
- }
1517
-
1518
- parts
1519
- }
1520
-
1521
- /// Splits bytes by ASCII whitespace, returning at most maxsplit+1 parts.
1522
- fn bytes_splitn_whitespace(bytes: &[u8], maxsplit: usize) -> Vec<&[u8]> {
1523
- let mut parts = Vec::new();
1524
- let mut start = None;
1525
- let mut count = 0;
1526
-
1527
- let trimmed = bytes_strip_whitespace_start(bytes);
1528
- let offset = bytes.len() - trimmed.len();
1529
-
1530
- for (i, &b) in trimmed.iter().enumerate() {
1531
- if is_py_whitespace(b) {
1532
- if let Some(s) = start
1533
- && count < maxsplit
1534
- {
1535
- parts.push(&bytes[offset + s..offset + i]);
1536
- count += 1;
1537
- start = None;
1538
- }
1539
- } else if start.is_none() {
1540
- start = Some(i);
1541
- }
1542
- }
1543
-
1544
- if let Some(s) = start {
1545
- parts.push(&bytes[offset + s..]);
1546
- }
1547
-
1548
- parts
1549
- }
1550
-
1551
- /// Splits bytes by ASCII whitespace from the right, returning at most maxsplit+1 parts.
1552
- fn bytes_rsplitn_whitespace(bytes: &[u8], maxsplit: usize) -> Vec<&[u8]> {
1553
- let mut parts = Vec::new();
1554
- let mut end = None;
1555
- let mut count = 0;
1556
-
1557
- let trimmed = bytes_strip_whitespace_end(bytes);
1558
-
1559
- for i in (0..trimmed.len()).rev() {
1560
- let b = trimmed[i];
1561
- if is_py_whitespace(b) {
1562
- if let Some(e) = end
1563
- && count < maxsplit
1564
- {
1565
- parts.push(&trimmed[i + 1..e]);
1566
- count += 1;
1567
- end = None;
1568
- }
1569
- } else if end.is_none() {
1570
- end = Some(i + 1);
1571
- }
1572
- }
1573
-
1574
- if let Some(e) = end {
1575
- parts.push(&trimmed[..e]);
1576
- }
1577
-
1578
- parts.reverse();
1579
- parts
1580
- }
1581
-
1582
- /// Implements Python's `bytes.splitlines([keepends])` method.
1583
- ///
1584
- /// Returns a list of the lines in the bytes, breaking at line boundaries.
1585
- fn bytes_splitlines(bytes: &[u8], args: ArgValues, vm: &mut VM<'_, '_, impl ResourceTracker>) -> RunResult<Value> {
1586
- let keepends = parse_bytes_splitlines_args(args, vm)?;
1587
-
1588
- let mut lines = Vec::new();
1589
- let mut start = 0;
1590
- let len = bytes.len();
1591
-
1592
- while start < len {
1593
- vm.heap.check_time()?;
1594
-
1595
- let mut end = start;
1596
- let mut line_end = start;
1597
-
1598
- while end < len {
1599
- match bytes[end] {
1600
- b'\n' => {
1601
- line_end = end;
1602
- end += 1;
1603
- break;
1604
- }
1605
- b'\r' => {
1606
- line_end = end;
1607
- end += 1;
1608
- if end < len && bytes[end] == b'\n' {
1609
- end += 1;
1610
- }
1611
- break;
1612
- }
1613
- _ => {
1614
- end += 1;
1615
- line_end = end;
1616
- }
1617
- }
1618
- }
1619
-
1620
- let line = if keepends {
1621
- &bytes[start..end]
1622
- } else {
1623
- &bytes[start..line_end]
1624
- };
1625
- lines.push(allocate_bytes(line.to_vec(), vm.heap)?);
1626
- start = end;
1627
- }
1628
-
1629
- let list = List::new(lines);
1630
- let heap_id = vm.heap.allocate(HeapData::List(list))?;
1631
- Ok(Value::Ref(heap_id))
1632
- }
1633
-
1634
- /// Parses arguments for bytes.splitlines method.
1635
- fn parse_bytes_splitlines_args(args: ArgValues, vm: &mut VM<'_, '_, impl ResourceTracker>) -> RunResult<bool> {
1636
- let (pos_iter, kwargs) = args.into_parts();
1637
- defer_drop_mut!(pos_iter, vm);
1638
- let kwargs = kwargs.into_iter();
1639
- defer_drop_mut!(kwargs, vm);
1640
-
1641
- let keepends_value = pos_iter.next();
1642
- defer_drop_mut!(keepends_value, vm);
1643
-
1644
- // Check no extra positional arguments
1645
- if pos_iter.len() != 0 {
1646
- return Err(ExcType::type_error_at_most("bytes.splitlines", 1, 2));
1647
- }
1648
-
1649
- // Process kwargs
1650
- for (key, value) in kwargs {
1651
- defer_drop!(key, vm);
1652
- let mut value_guard = HeapGuard::new(value, vm);
1653
-
1654
- let Some(keyword_name) = key.as_either_str(value_guard.heap().heap) else {
1655
- return Err(ExcType::type_error("keywords must be strings"));
1656
- };
1657
-
1658
- let key_str = keyword_name.as_str(value_guard.heap().interns);
1659
- if key_str == "keepends" {
1660
- if let Some(previous_value) = keepends_value.replace(value_guard.into_inner()) {
1661
- previous_value.drop_with_heap(vm);
1662
- return Err(ExcType::type_error(
1663
- "bytes.splitlines() got multiple values for argument 'keepends'",
1664
- ));
1665
- }
1666
- } else {
1667
- return Err(ExcType::type_error(format!(
1668
- "'{key_str}' is an invalid keyword argument for bytes.splitlines()"
1669
- )));
1670
- }
1671
- }
1672
-
1673
- // Extract keepends (default false)
1674
- let keepends = if let Some(v) = keepends_value {
1675
- v.py_bool(vm)
1676
- } else {
1677
- false
1678
- };
1679
-
1680
- Ok(keepends)
1681
- }
1682
-
1683
- /// Implements Python's `bytes.partition(sep)` method.
1684
- ///
1685
- /// Splits the bytes at the first occurrence of sep, and returns a 3-tuple.
1686
- fn bytes_partition(
1687
- bytes: &[u8],
1688
- args: ArgValues,
1689
- heap: &mut Heap<impl ResourceTracker>,
1690
- interns: &Interns,
1691
- ) -> RunResult<Value> {
1692
- let sep_value = args.get_one_arg("bytes.partition", heap)?;
1693
- defer_drop!(sep_value, heap);
1694
- let sep = extract_bytes_only(sep_value, heap, interns)?;
1695
-
1696
- if sep.is_empty() {
1697
- return Err(ExcType::value_error_empty_separator());
1698
- }
1699
-
1700
- let (before, sep_found, after) = match find_subsequence(bytes, sep) {
1701
- Some(pos) => (bytes[..pos].to_vec(), sep.to_vec(), bytes[pos + sep.len()..].to_vec()),
1702
- None => (bytes.to_vec(), Vec::new(), Vec::new()),
1703
- };
1704
-
1705
- let before_val = allocate_bytes(before, heap)?;
1706
- let sep_val = allocate_bytes(sep_found, heap)?;
1707
- let after_val = allocate_bytes(after, heap)?;
1708
-
1709
- Ok(crate::types::allocate_tuple(
1710
- smallvec![before_val, sep_val, after_val],
1711
- heap,
1712
- )?)
1713
- }
1714
-
1715
- /// Implements Python's `bytes.rpartition(sep)` method.
1716
- ///
1717
- /// Splits the bytes at the last occurrence of sep, and returns a 3-tuple.
1718
- fn bytes_rpartition(
1719
- bytes: &[u8],
1720
- args: ArgValues,
1721
- heap: &mut Heap<impl ResourceTracker>,
1722
- interns: &Interns,
1723
- ) -> RunResult<Value> {
1724
- let sep_value = args.get_one_arg("bytes.rpartition", heap)?;
1725
- defer_drop!(sep_value, heap);
1726
- let sep = extract_bytes_only(sep_value, heap, interns)?;
1727
-
1728
- if sep.is_empty() {
1729
- return Err(ExcType::value_error_empty_separator());
1730
- }
1731
-
1732
- let (before, sep_found, after) = match rfind_subsequence(bytes, sep) {
1733
- Some(pos) => (bytes[..pos].to_vec(), sep.to_vec(), bytes[pos + sep.len()..].to_vec()),
1734
- None => (Vec::new(), Vec::new(), bytes.to_vec()),
1735
- };
1736
-
1737
- let before_val = allocate_bytes(before, heap)?;
1738
- let sep_val = allocate_bytes(sep_found, heap)?;
1739
- let after_val = allocate_bytes(after, heap)?;
1740
-
1741
- Ok(crate::types::allocate_tuple(
1742
- smallvec![before_val, sep_val, after_val],
1743
- heap,
1744
- )?)
1745
- }
1746
-
1747
- // =============================================================================
1748
- // Replace/padding methods
1749
- // =============================================================================
1750
-
1751
- /// Implements Python's `bytes.replace(old, new[, count])` method.
1752
- ///
1753
- /// Returns a copy with all occurrences of old replaced by new.
1754
- fn bytes_replace(
1755
- bytes: &[u8],
1756
- args: ArgValues,
1757
- heap: &mut Heap<impl ResourceTracker>,
1758
- interns: &Interns,
1759
- ) -> RunResult<Value> {
1760
- let (old, new, count) = parse_bytes_replace_args("bytes.replace", args, heap, interns)?;
1761
-
1762
- check_replace_size(bytes.len(), old.len(), new.len(), count, heap.tracker())?;
1763
-
1764
- let result = if count < 0 {
1765
- bytes_replace_all(bytes, &old, &new, heap)?
1766
- } else {
1767
- let n = usize::try_from(count).unwrap_or(usize::MAX);
1768
- bytes_replace_n(bytes, &old, &new, n, heap)?
1769
- };
1770
-
1771
- allocate_bytes(result, heap)
1772
- }
1773
-
1774
- /// Parses arguments for bytes.replace method.
1775
- fn parse_bytes_replace_args(
1776
- method: &str,
1777
- args: ArgValues,
1778
- heap: &mut Heap<impl ResourceTracker>,
1779
- interns: &Interns,
1780
- ) -> RunResult<(Vec<u8>, Vec<u8>, i64)> {
1781
- let (pos_iter, kwargs) = args.into_parts();
1782
- defer_drop_mut!(pos_iter, heap);
1783
- let kwargs_iter = kwargs.into_iter();
1784
- defer_drop_mut!(kwargs_iter, heap);
1785
-
1786
- let Some(old_value) = pos_iter.next() else {
1787
- return Err(ExcType::type_error_at_least(method, 2, 0));
1788
- };
1789
- defer_drop!(old_value, heap);
1790
-
1791
- let Some(new_value) = pos_iter.next() else {
1792
- return Err(ExcType::type_error_at_least(method, 2, 1));
1793
- };
1794
- defer_drop!(new_value, heap);
1795
-
1796
- let count_value = pos_iter.next();
1797
- defer_drop_mut!(count_value, heap);
1798
-
1799
- // Check no extra positional arguments
1800
- if pos_iter.len() != 0 {
1801
- return Err(ExcType::type_error_at_most(method, 3, pos_iter.len() + 3));
1802
- }
1803
-
1804
- // Process keyword arguments
1805
- for (key, value) in kwargs_iter {
1806
- defer_drop!(key, heap);
1807
- let mut value_guard = HeapGuard::new(value, heap);
1808
-
1809
- let Some(keyword_name) = key.as_either_str(value_guard.heap()) else {
1810
- return Err(ExcType::type_error("keywords must be strings"));
1811
- };
1812
-
1813
- let key_str = keyword_name.as_str(interns);
1814
- match key_str {
1815
- "count" => {
1816
- if let Some(previous_value) = count_value.replace(value_guard.into_inner()) {
1817
- previous_value.drop_with_heap(heap);
1818
- return Err(ExcType::type_error(format!(
1819
- "{method}() got multiple values for argument 'count'"
1820
- )));
1821
- }
1822
- }
1823
- _ => {
1824
- return Err(ExcType::type_error(format!(
1825
- "'{key_str}' is an invalid keyword argument for {method}()"
1826
- )));
1827
- }
1828
- }
1829
- }
1830
-
1831
- // Extract old bytes
1832
- let old = extract_bytes_only(old_value, heap, interns)?.to_owned();
1833
-
1834
- // Extract new bytes
1835
- let new = extract_bytes_only(new_value, heap, interns)?.to_owned();
1836
-
1837
- // Extract count (default -1)
1838
- let count = if let Some(v) = count_value { v.as_int(heap)? } else { -1 };
1839
-
1840
- Ok((old, new, count))
1841
- }
1842
-
1843
- /// Replaces all occurrences of `old` with `new` in bytes.
1844
- ///
1845
- /// Checks the time limit periodically to enforce `max_duration` during
1846
- /// potentially long replacement operations on large byte sequences.
1847
- fn bytes_replace_all(
1848
- bytes: &[u8],
1849
- old: &[u8],
1850
- new: &[u8],
1851
- heap: &mut Heap<impl ResourceTracker>,
1852
- ) -> Result<Vec<u8>, ResourceError> {
1853
- if old.is_empty() {
1854
- // Empty pattern: insert new before each byte and at the end
1855
- let mut result = Vec::with_capacity(bytes.len() + new.len() * (bytes.len() + 1));
1856
- for &b in bytes {
1857
- heap.check_time()?;
1858
- result.extend_from_slice(new);
1859
- result.push(b);
1860
- }
1861
- result.extend_from_slice(new);
1862
- Ok(result)
1863
- } else {
1864
- let mut result = Vec::new();
1865
- let mut start = 0;
1866
- while let Some(pos) = find_subsequence(&bytes[start..], old) {
1867
- heap.check_time()?;
1868
- result.extend_from_slice(&bytes[start..start + pos]);
1869
- result.extend_from_slice(new);
1870
- start = start + pos + old.len();
1871
- }
1872
- result.extend_from_slice(&bytes[start..]);
1873
- Ok(result)
1874
- }
1875
- }
1876
-
1877
- /// Replaces at most n occurrences of `old` with `new` in bytes.
1878
- ///
1879
- /// Checks the time limit periodically to enforce `max_duration` during
1880
- /// potentially long replacement operations on large byte sequences.
1881
- fn bytes_replace_n(
1882
- bytes: &[u8],
1883
- old: &[u8],
1884
- new: &[u8],
1885
- n: usize,
1886
- heap: &mut Heap<impl ResourceTracker>,
1887
- ) -> Result<Vec<u8>, ResourceError> {
1888
- if old.is_empty() {
1889
- // Empty pattern: insert new before each byte (up to n times)
1890
- let mut result = Vec::new();
1891
- let mut count = 0;
1892
- for &b in bytes {
1893
- heap.check_time()?;
1894
- if count < n {
1895
- result.extend_from_slice(new);
1896
- count += 1;
1897
- }
1898
- result.push(b);
1899
- }
1900
- if count < n {
1901
- result.extend_from_slice(new);
1902
- }
1903
- Ok(result)
1904
- } else {
1905
- let mut result = Vec::new();
1906
- let mut start = 0;
1907
- let mut count = 0;
1908
- while count < n {
1909
- heap.check_time()?;
1910
- if let Some(pos) = find_subsequence(&bytes[start..], old) {
1911
- result.extend_from_slice(&bytes[start..start + pos]);
1912
- result.extend_from_slice(new);
1913
- start = start + pos + old.len();
1914
- count += 1;
1915
- } else {
1916
- break;
1917
- }
1918
- }
1919
- result.extend_from_slice(&bytes[start..]);
1920
- Ok(result)
1921
- }
1922
- }
1923
-
1924
- /// Implements Python's `bytes.center(width[, fillbyte])` method.
1925
- ///
1926
- /// Returns centered in a bytes of length width.
1927
- fn bytes_center(
1928
- bytes: &[u8],
1929
- args: ArgValues,
1930
- heap: &mut Heap<impl ResourceTracker>,
1931
- interns: &Interns,
1932
- ) -> RunResult<Value> {
1933
- let (width, fillbyte) = parse_bytes_justify_args("bytes.center", args, heap, interns)?;
1934
- let len = bytes.len();
1935
-
1936
- let result = if width <= len {
1937
- bytes.to_vec()
1938
- } else {
1939
- check_repeat_size(width, 1, heap.tracker())?;
1940
- let total_pad = width - len;
1941
- let left_pad = total_pad / 2;
1942
- let right_pad = total_pad - left_pad;
1943
- let mut result = Vec::with_capacity(width);
1944
- for _ in 0..left_pad {
1945
- result.push(fillbyte);
1946
- }
1947
- result.extend_from_slice(bytes);
1948
- for _ in 0..right_pad {
1949
- result.push(fillbyte);
1950
- }
1951
- result
1952
- };
1953
-
1954
- allocate_bytes(result, heap)
1955
- }
1956
-
1957
- /// Implements Python's `bytes.ljust(width[, fillbyte])` method.
1958
- ///
1959
- /// Returns left-justified in a bytes of length width.
1960
- fn bytes_ljust(
1961
- bytes: &[u8],
1962
- args: ArgValues,
1963
- heap: &mut Heap<impl ResourceTracker>,
1964
- interns: &Interns,
1965
- ) -> RunResult<Value> {
1966
- let (width, fillbyte) = parse_bytes_justify_args("bytes.ljust", args, heap, interns)?;
1967
- let len = bytes.len();
1968
-
1969
- let result = if width <= len {
1970
- bytes.to_vec()
1971
- } else {
1972
- check_repeat_size(width, 1, heap.tracker())?;
1973
- let pad = width - len;
1974
- let mut result = Vec::with_capacity(width);
1975
- result.extend_from_slice(bytes);
1976
- for _ in 0..pad {
1977
- result.push(fillbyte);
1978
- }
1979
- result
1980
- };
1981
-
1982
- allocate_bytes(result, heap)
1983
- }
1984
-
1985
- /// Implements Python's `bytes.rjust(width[, fillbyte])` method.
1986
- ///
1987
- /// Returns right-justified in a bytes of length width.
1988
- fn bytes_rjust(
1989
- bytes: &[u8],
1990
- args: ArgValues,
1991
- heap: &mut Heap<impl ResourceTracker>,
1992
- interns: &Interns,
1993
- ) -> RunResult<Value> {
1994
- let (width, fillbyte) = parse_bytes_justify_args("bytes.rjust", args, heap, interns)?;
1995
- let len = bytes.len();
1996
-
1997
- let result = if width <= len {
1998
- bytes.to_vec()
1999
- } else {
2000
- check_repeat_size(width, 1, heap.tracker())?;
2001
- let pad = width - len;
2002
- let mut result = Vec::with_capacity(width);
2003
- for _ in 0..pad {
2004
- result.push(fillbyte);
2005
- }
2006
- result.extend_from_slice(bytes);
2007
- result
2008
- };
2009
-
2010
- allocate_bytes(result, heap)
2011
- }
2012
-
2013
- /// Parses arguments for bytes justify methods (center, ljust, rjust).
2014
- fn parse_bytes_justify_args(
2015
- method: &str,
2016
- args: ArgValues,
2017
- heap: &mut Heap<impl ResourceTracker>,
2018
- interns: &Interns,
2019
- ) -> RunResult<(usize, u8)> {
2020
- let pos = args.into_pos_only(method, heap)?;
2021
- defer_drop!(pos, heap);
2022
-
2023
- let extract_width = |v: &Value| -> RunResult<usize> {
2024
- let w = v.as_int(heap)?;
2025
- Ok(if w < 0 {
2026
- 0
2027
- } else {
2028
- usize::try_from(w).unwrap_or(usize::MAX)
2029
- })
2030
- };
2031
-
2032
- let extract_fill = |v: &Value| -> RunResult<u8> {
2033
- let fill_bytes = extract_bytes_only(v, heap, interns)?;
2034
- if fill_bytes.len() != 1 {
2035
- return Err(ExcType::type_error(format!(
2036
- "{method}() argument 2 must be a byte string of length 1, not bytes of length {}",
2037
- fill_bytes.len()
2038
- )));
2039
- }
2040
- Ok(fill_bytes[0])
2041
- };
2042
-
2043
- match pos.as_slice() {
2044
- [width_value] => Ok((extract_width(width_value)?, b' ')),
2045
- [width_value, fillbyte_value] => Ok((extract_width(width_value)?, extract_fill(fillbyte_value)?)),
2046
- [] => Err(ExcType::type_error_at_least(method, 1, 0)),
2047
- _ => Err(ExcType::type_error_at_most(method, 2, pos.len())),
2048
- }
2049
- }
2050
-
2051
- /// Implements Python's `bytes.zfill(width)` method.
2052
- ///
2053
- /// Returns a copy of the bytes left filled with ASCII '0' digits.
2054
- fn bytes_zfill(bytes: &[u8], args: ArgValues, heap: &mut Heap<impl ResourceTracker>) -> RunResult<Value> {
2055
- let width_value = args.get_one_arg("bytes.zfill", heap)?;
2056
- defer_drop!(width_value, heap);
2057
- let width_i64 = width_value.as_int(heap)?;
2058
-
2059
- let width = if width_i64 < 0 {
2060
- 0
2061
- } else {
2062
- usize::try_from(width_i64).unwrap_or(usize::MAX)
2063
- };
2064
- let len = bytes.len();
2065
-
2066
- let result = if width <= len {
2067
- bytes.to_vec()
2068
- } else {
2069
- check_repeat_size(width, 1, heap.tracker())?;
2070
- let pad = width - len;
2071
- let mut result = Vec::with_capacity(width);
2072
-
2073
- // Handle sign prefix
2074
- if !bytes.is_empty() && (bytes[0] == b'+' || bytes[0] == b'-') {
2075
- result.push(bytes[0]);
2076
- result.resize(pad + 1, b'0');
2077
- result.extend_from_slice(&bytes[1..]);
2078
- } else {
2079
- result.resize(pad, b'0');
2080
- result.extend_from_slice(bytes);
2081
- }
2082
- result
2083
- };
2084
-
2085
- allocate_bytes(result, heap)
2086
- }
2087
-
2088
- // =============================================================================
2089
- // Join method
2090
- // =============================================================================
2091
-
2092
- /// Implements Python's `bytes.join(iterable)` method.
2093
- ///
2094
- /// Joins elements of the iterable with the separator bytes.
2095
- fn bytes_join(separator: &[u8], iterable: Value, vm: &mut VM<'_, '_, impl ResourceTracker>) -> RunResult<Value> {
2096
- let Ok(iter) = MontyIter::new(iterable, vm) else {
2097
- return Err(ExcType::type_error_join_not_iterable());
2098
- };
2099
- defer_drop_mut!(iter, vm);
2100
-
2101
- let mut result = Vec::new();
2102
- let mut index = 0usize;
2103
-
2104
- while let Some(item) = iter.for_next(vm)? {
2105
- defer_drop!(item, vm);
2106
-
2107
- if index > 0 {
2108
- result.extend_from_slice(separator);
2109
- }
2110
-
2111
- // Check item is bytes and extract its content
2112
- match item {
2113
- Value::InternBytes(id) => {
2114
- result.extend_from_slice(vm.interns.get_bytes(*id));
2115
- }
2116
- Value::Ref(heap_id) => {
2117
- if let HeapData::Bytes(b) = vm.heap.get(*heap_id) {
2118
- result.extend_from_slice(b.as_slice());
2119
- } else {
2120
- let t = item.py_type(vm.heap);
2121
- return Err(ExcType::type_error(format!(
2122
- "sequence item {index}: expected a bytes-like object, {t} found"
2123
- )));
2124
- }
2125
- }
2126
- _ => {
2127
- let t = item.py_type(vm.heap);
2128
- return Err(ExcType::type_error(format!(
2129
- "sequence item {index}: expected a bytes-like object, {t} found"
2130
- )));
2131
- }
2132
- }
2133
- index += 1;
2134
- }
2135
-
2136
- allocate_bytes(result, vm.heap)
2137
- }
2138
-
2139
- // =============================================================================
2140
- // Hex method
2141
- // =============================================================================
2142
-
2143
- /// Implements Python's `bytes.hex([sep[, bytes_per_sep]])` method.
2144
- ///
2145
- /// Returns a string containing the hexadecimal representation of the bytes.
2146
- fn bytes_hex(
2147
- bytes: &[u8],
2148
- args: ArgValues,
2149
- heap: &mut Heap<impl ResourceTracker>,
2150
- interns: &Interns,
2151
- ) -> RunResult<Value> {
2152
- let (sep, bytes_per_sep) = parse_bytes_hex_args(args, heap, interns)?;
2153
-
2154
- let hex_chars: Vec<char> = bytes
2155
- .iter()
2156
- .flat_map(|b| {
2157
- let hi = (b >> 4) & 0xf;
2158
- let lo = b & 0xf;
2159
- let hi_char = if hi < 10 {
2160
- (b'0' + hi) as char
2161
- } else {
2162
- (b'a' + hi - 10) as char
2163
- };
2164
- let lo_char = if lo < 10 {
2165
- (b'0' + lo) as char
2166
- } else {
2167
- (b'a' + lo - 10) as char
2168
- };
2169
- [hi_char, lo_char]
2170
- })
2171
- .collect();
2172
-
2173
- let result = if let Some(sep) = sep {
2174
- if bytes_per_sep == 0 || bytes.is_empty() {
2175
- hex_chars.iter().collect()
2176
- } else {
2177
- // Insert separator every `bytes_per_sep` bytes (2*bytes_per_sep hex chars)
2178
- let chars_per_group = usize::try_from(bytes_per_sep.unsigned_abs()).unwrap_or(usize::MAX) * 2;
2179
- let mut result = String::new();
2180
-
2181
- if bytes_per_sep > 0 {
2182
- // Positive: count from right, so partial group is at the START
2183
- let total_len = hex_chars.len();
2184
- let first_chunk_len = total_len % chars_per_group;
2185
- let first_chunk_len = if first_chunk_len == 0 {
2186
- chars_per_group
2187
- } else {
2188
- first_chunk_len
2189
- };
2190
-
2191
- result.extend(&hex_chars[..first_chunk_len]);
2192
- for chunk in hex_chars[first_chunk_len..].chunks(chars_per_group) {
2193
- result.push(sep);
2194
- result.extend(chunk);
2195
- }
2196
- } else {
2197
- // Negative: count from left, so partial group is at the END
2198
- for (i, chunk) in hex_chars.chunks(chars_per_group).enumerate() {
2199
- if i > 0 {
2200
- result.push(sep);
2201
- }
2202
- result.extend(chunk);
2203
- }
2204
- }
2205
- result
2206
- }
2207
- } else {
2208
- hex_chars.iter().collect()
2209
- };
2210
-
2211
- crate::types::str::allocate_string(result, heap)
2212
- }
2213
-
2214
- /// Parses arguments for bytes.hex method.
2215
- fn parse_bytes_hex_args(
2216
- args: ArgValues,
2217
- heap: &mut Heap<impl ResourceTracker>,
2218
- interns: &Interns,
2219
- ) -> RunResult<(Option<char>, i64)> {
2220
- let pos = args.into_pos_only("bytes.hex", heap)?;
2221
- defer_drop!(pos, heap);
2222
-
2223
- let (sep_value, bps_value) = match pos.as_slice() {
2224
- [] => return Ok((None, 1)),
2225
- [sep_value] => (sep_value, None),
2226
- [sep_value, bps_value] => (sep_value, Some(bps_value)),
2227
- other => return Err(ExcType::type_error_at_most("bytes.hex", 2, other.len())),
2228
- };
2229
-
2230
- let sep_bytes = match sep_value {
2231
- Value::InternString(id) => interns.get_str(*id).as_bytes(),
2232
- Value::InternBytes(id) => interns.get_bytes(*id),
2233
- Value::Ref(heap_id) => match heap.get(*heap_id) {
2234
- HeapData::Str(s) => s.as_bytes(),
2235
- HeapData::Bytes(b) => b.as_slice(),
2236
- _ => return Err(ExcType::type_error("sep must be str or bytes")),
2237
- },
2238
- _ => return Err(ExcType::type_error("sep must be str or bytes")),
2239
- };
2240
-
2241
- let sep = match sep_bytes {
2242
- [b] if b.is_ascii() => *b as char,
2243
- _ => return Err(SimpleException::new_msg(ExcType::ValueError, "sep must be a single ASCII character").into()),
2244
- };
2245
-
2246
- let bytes_per_sep = if let Some(bps_value) = bps_value {
2247
- bps_value.as_int(heap)?
2248
- } else {
2249
- 1
2250
- };
2251
-
2252
- Ok((Some(sep), bytes_per_sep))
2253
- }
2254
-
2255
- // =============================================================================
2256
- // fromhex classmethod
2257
- // =============================================================================
2258
-
2259
- /// Implements Python's `bytes.fromhex(string)` classmethod.
2260
- ///
2261
- /// Creates bytes from a hexadecimal string. Whitespace is allowed between byte pairs,
2262
- /// but not between the two digits of a byte.
2263
- pub fn bytes_fromhex(args: ArgValues, heap: &mut Heap<impl ResourceTracker>, interns: &Interns) -> RunResult<Value> {
2264
- let hex_value = args.get_one_arg("bytes.fromhex", heap)?;
2265
- defer_drop!(hex_value, heap);
2266
-
2267
- let hex_str = match hex_value {
2268
- Value::InternString(id) => interns.get_str(*id),
2269
- Value::Ref(heap_id) => {
2270
- if let HeapData::Str(s) = heap.get(*heap_id) {
2271
- s.as_str()
2272
- } else {
2273
- return Err(ExcType::type_error("fromhex() argument must be str, not bytes"));
2274
- }
2275
- }
2276
- _ => {
2277
- let t = hex_value.py_type(heap);
2278
- return Err(ExcType::type_error(format!("fromhex() argument must be str, not {t}")));
2279
- }
2280
- };
2281
-
2282
- // CPython allows whitespace BETWEEN byte pairs, but NOT within a pair.
2283
- // - "de ad" is valid (whitespace between pairs)
2284
- // - "d e" or "0 1" are NOT valid (whitespace within a pair)
2285
- // - " 01 " is valid (whitespace before/after)
2286
- //
2287
- // Error messages:
2288
- // - Invalid char (including whitespace in wrong place): "non-hexadecimal number found ... at position X"
2289
- // - Odd number of valid hex digits: "must contain an even number of hexadecimal digits"
2290
-
2291
- let mut result = Vec::new();
2292
- let mut chars = hex_str.chars().enumerate().peekable();
2293
-
2294
- loop {
2295
- // Skip whitespace BETWEEN byte pairs (before the high nibble)
2296
- while chars.peek().is_some_and(|(_, c)| c.is_whitespace()) {
2297
- chars.next();
2298
- }
2299
-
2300
- // Get high nibble
2301
- let Some((hi_pos, hi_char)) = chars.next() else {
2302
- break; // End of string - we're done
2303
- };
2304
-
2305
- let Some(hi_val) = hex_char_to_value(hi_char) else {
2306
- return Err(SimpleException::new_msg(
2307
- ExcType::ValueError,
2308
- format!("non-hexadecimal number found in fromhex() arg at position {hi_pos}"),
2309
- )
2310
- .into());
2311
- };
2312
-
2313
- // Get low nibble - must be IMMEDIATELY after high nibble (no whitespace)
2314
- let Some((lo_pos, lo_char)) = chars.next() else {
2315
- // End of string after high nibble = odd number of hex digits
2316
- return Err(SimpleException::new_msg(
2317
- ExcType::ValueError,
2318
- "fromhex() arg must contain an even number of hexadecimal digits",
2319
- )
2320
- .into());
2321
- };
2322
-
2323
- let Some(lo_val) = hex_char_to_value(lo_char) else {
2324
- // Invalid character (including whitespace) in low nibble position
2325
- return Err(SimpleException::new_msg(
2326
- ExcType::ValueError,
2327
- format!("non-hexadecimal number found in fromhex() arg at position {lo_pos}"),
2328
- )
2329
- .into());
2330
- };
2331
-
2332
- result.push((hi_val << 4) | lo_val);
2333
- }
2334
-
2335
- allocate_bytes(result, heap)
2336
- }
2337
-
2338
- /// Converts a hex character to its numeric value.
2339
- fn hex_char_to_value(c: char) -> Option<u8> {
2340
- match c {
2341
- '0'..='9' => Some(c as u8 - b'0'),
2342
- 'a'..='f' => Some(c as u8 - b'a' + 10),
2343
- 'A'..='F' => Some(c as u8 - b'A' + 10),
2344
- _ => None,
2345
- }
2346
- }
2347
-
2348
- // =============================================================================
2349
- // Helper function for bytes allocation
2350
- // =============================================================================
2351
-
2352
- /// Allocates bytes on the heap.
2353
- fn allocate_bytes(bytes: Vec<u8>, heap: &mut Heap<impl ResourceTracker>) -> RunResult<Value> {
2354
- let heap_id = heap.allocate(HeapData::Bytes(Bytes::new(bytes)))?;
2355
- Ok(Value::Ref(heap_id))
2356
- }