superacli 1.1.6 → 1.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1262) hide show
  1. package/README.md +77 -53
  2. package/__tests__/azd-plugin.test.js +109 -0
  3. package/__tests__/config.test.js +4 -3
  4. package/__tests__/discover.test.js +59 -0
  5. package/__tests__/goose-plugin.test.js +149 -0
  6. package/__tests__/help-json.test.js +2 -0
  7. package/__tests__/openhands-plugin.test.js +106 -0
  8. package/__tests__/plugin-cocoindex-code-uninstall.test.js +19 -0
  9. package/__tests__/plugin-cocoindex-code.test.js +37 -0
  10. package/__tests__/plugin-install-guidance.test.js +81 -0
  11. package/__tests__/plugins-registry.test.js +44 -0
  12. package/__tests__/plugins-store.test.js +40 -5
  13. package/__tests__/process-adapter.test.js +50 -1
  14. package/__tests__/server-app.test.js +1 -0
  15. package/__tests__/server-routes-commands.test.js +20 -2
  16. package/__tests__/server-routes-plugins.test.js +130 -0
  17. package/__tests__/skills.test.js +26 -0
  18. package/__tests__/squirrelscan-plugin.test.js +129 -0
  19. package/__tests__/uipath-plugin.test.js +104 -0
  20. package/__tests__/uipathcli-plugin.test.js +95 -0
  21. package/cli/adapters/mcp.js +2 -0
  22. package/cli/adapters/process.js +49 -2
  23. package/cli/config.js +240 -3
  24. package/cli/discover.js +157 -0
  25. package/cli/help-json.js +16 -1
  26. package/cli/plugin-install-guidance.js +92 -37
  27. package/cli/plugins-manager.js +1 -0
  28. package/cli/plugins-registry.js +74 -8
  29. package/cli/plugins-store.js +78 -17
  30. package/cli/skills-mcp.js +1 -1
  31. package/cli/skills.js +39 -2
  32. package/cli/supercli.js +87 -11
  33. package/docs/feature-gaps.md +8 -8
  34. package/docs/features/azd-uipath-plugins.md +43 -0
  35. package/docs/features/server-plugins.md +62 -0
  36. package/docs/features/skills.md +9 -5
  37. package/docs/{supported-harnesses.md → plugins-available.md} +4 -3
  38. package/docs/{plugin-harness-guide.md → plugins-how-to.md} +1 -1
  39. package/docs/plugins.md +26 -20
  40. package/docs/server-plugins-usage-guide.md +182 -0
  41. package/docs/skills-catalog.md +12 -10
  42. package/package.json +1 -1
  43. package/plugins/agent-browser/README.md +69 -0
  44. package/plugins/agent-browser/plugin.json +111 -0
  45. package/plugins/agent-browser/skills/quickstart/SKILL.md +66 -0
  46. package/plugins/aider/README.md +53 -0
  47. package/plugins/aider/plugin.json +105 -0
  48. package/plugins/aider/scripts/aider-wrapper.js +243 -0
  49. package/plugins/aider/scripts/setup-aider.js +37 -0
  50. package/plugins/aider/skills/dry-run-review.md +24 -0
  51. package/plugins/aider/skills/model-and-provider.md +24 -0
  52. package/plugins/aider/skills/one-shot-edits.md +30 -0
  53. package/plugins/aider/skills/quickstart/SKILL.md +51 -0
  54. package/plugins/azd/README.md +28 -0
  55. package/plugins/azd/plugin.json +87 -0
  56. package/plugins/azd/skills/quickstart/SKILL.md +41 -0
  57. package/plugins/blogwatcher/README.md +3 -3
  58. package/plugins/boxlite/Dockerfile +9 -0
  59. package/plugins/boxlite/README.md +62 -0
  60. package/plugins/boxlite/plugin.json +201 -0
  61. package/plugins/boxlite/scripts/run-boxlite.js +106 -0
  62. package/plugins/boxlite/skills/quickstart/SKILL.md +40 -0
  63. package/plugins/cass/plugin.json +150 -0
  64. package/plugins/cass/scripts/setup-cass.js +47 -0
  65. package/plugins/cass/skills/quickstart/SKILL.md +46 -0
  66. package/plugins/clever/README.md +46 -0
  67. package/plugins/clever/plugin.json +119 -0
  68. package/plugins/clever/scripts/setup-clever.js +28 -0
  69. package/plugins/clever/skills/auth-and-profile.md +29 -0
  70. package/plugins/clever/skills/passthrough-safety.md +21 -0
  71. package/plugins/clever/skills/quickstart/SKILL.md +45 -0
  72. package/plugins/clever/skills/resource-inventory.md +24 -0
  73. package/plugins/clix/README.md +4 -4
  74. package/plugins/cocoindex-code/README.md +64 -0
  75. package/plugins/cocoindex-code/plugin.json +81 -0
  76. package/plugins/cocoindex-code/scripts/__pycache__/query.cpython-310.pyc +0 -0
  77. package/plugins/cocoindex-code/scripts/__pycache__/query.cpython-311.pyc +0 -0
  78. package/plugins/cocoindex-code/scripts/post-install.js +61 -0
  79. package/plugins/cocoindex-code/scripts/post-uninstall.js +25 -0
  80. package/plugins/cocoindex-code/scripts/query.py +88 -0
  81. package/plugins/cocoindex-code/scripts/run-query.js +50 -0
  82. package/plugins/cocoindex-code/skills/quickstart/SKILL.md +73 -0
  83. package/plugins/copilot/README.md +24 -0
  84. package/plugins/copilot/plugin.json +80 -0
  85. package/plugins/copilot/skills/quickstart/SKILL.md +44 -0
  86. package/plugins/gemini/README.md +24 -0
  87. package/plugins/gemini/plugin.json +98 -0
  88. package/plugins/gemini/skills/quickstart/SKILL.md +44 -0
  89. package/plugins/gifcap/plugin.json +119 -0
  90. package/plugins/gifcap/scripts/setup-gifcap.js +44 -0
  91. package/plugins/gifcap/skills/quickstart/SKILL.md +34 -0
  92. package/plugins/gifcap/test-record-quiet.gif +0 -0
  93. package/plugins/gifcap/test-record.gif +0 -0
  94. package/plugins/goose/README.md +36 -0
  95. package/plugins/goose/plugin.json +183 -0
  96. package/plugins/goose/skills/quickstart/SKILL.md +44 -0
  97. package/plugins/json-server/README.md +58 -0
  98. package/plugins/json-server/plugin.json +113 -0
  99. package/plugins/json-server/skills/quickstart/SKILL.md +57 -0
  100. package/plugins/lightpanda/README.md +145 -0
  101. package/plugins/lightpanda/package-lock.json +1375 -0
  102. package/plugins/lightpanda/package.json +12 -0
  103. package/plugins/lightpanda/plugin.json +116 -0
  104. package/plugins/lightpanda/scripts/lightpanda-contacts.js +494 -0
  105. package/plugins/lightpanda/scripts/lightpanda-generic-extract.js +403 -0
  106. package/plugins/lightpanda/scripts/lightpanda-wrapper.js +480 -0
  107. package/plugins/lightpanda/scripts/setup-lightpanda.js +39 -0
  108. package/plugins/lightpanda/skills/contact-discovery.md +51 -0
  109. package/plugins/lightpanda/skills/generic-extraction.md +66 -0
  110. package/plugins/lightpanda/skills/quickstart/SKILL.md +103 -0
  111. package/plugins/lightpanda/skills/resilient-navigation.md +42 -0
  112. package/plugins/monty/README.md +2 -2
  113. package/plugins/nullclaw/README.md +3 -3
  114. package/plugins/offline-ai/README.md +23 -0
  115. package/plugins/offline-ai/plugin.json +82 -0
  116. package/plugins/offline-ai/skills/quickstart/SKILL.md +43 -0
  117. package/plugins/openhands/README.md +25 -0
  118. package/plugins/openhands/plugin.json +116 -0
  119. package/plugins/openhands/skills/quickstart/SKILL.md +26 -0
  120. package/plugins/plandex/README.md +25 -0
  121. package/plugins/plandex/plugin.json +130 -0
  122. package/plugins/plandex/skills/quickstart/SKILL.md +50 -0
  123. package/plugins/plugins.json +188 -0
  124. package/plugins/squirrelscan/Dockerfile +5 -0
  125. package/plugins/squirrelscan/README.md +47 -0
  126. package/plugins/squirrelscan/plugin.json +493 -0
  127. package/plugins/squirrelscan/scripts/post-install.js +33 -0
  128. package/plugins/squirrelscan/scripts/post-uninstall.js +25 -0
  129. package/plugins/squirrelscan/scripts/run-squirrel.js +73 -0
  130. package/plugins/squirrelscan/skills/audit-workflow/SKILL.md +33 -0
  131. package/plugins/squirrelscan/skills/publish-report/SKILL.md +33 -0
  132. package/plugins/squirrelscan/skills/quickstart/SKILL.md +41 -0
  133. package/plugins/uipath/README.md +27 -0
  134. package/plugins/uipath/plugin.json +86 -0
  135. package/plugins/uipath/skills/quickstart/SKILL.md +47 -0
  136. package/plugins/uipathcli/README.md +28 -0
  137. package/plugins/uipathcli/plugin.json +120 -0
  138. package/plugins/uipathcli/scripts/run-uipath-cli.js +49 -0
  139. package/plugins/uipathcli/skills/quickstart/SKILL.md +22 -0
  140. package/plugins/xurl/README.md +4 -4
  141. package/server/app.js +5 -2
  142. package/server/public/app.js +3 -0
  143. package/server/routes/commands.js +95 -12
  144. package/server/routes/plugins.js +262 -0
  145. package/server/services/pluginsService.js +303 -0
  146. package/server/views/command-edit.ejs +196 -14
  147. package/server/views/partials/head.ejs +1 -0
  148. package/server/views/plugins.ejs +264 -0
  149. package/tests/test-plugins-registry.js +30 -0
  150. package/.beads/.br_history/issues.20260308_200823_636718328.jsonl +0 -20
  151. package/.beads/.br_history/issues.20260308_200823_636718328.jsonl.meta.json +0 -1
  152. package/.beads/.br_history/issues.20260308_200827_033159453.jsonl +0 -21
  153. package/.beads/.br_history/issues.20260308_200827_033159453.jsonl.meta.json +0 -1
  154. package/.beads/.br_history/issues.20260308_200829_595900053.jsonl +0 -22
  155. package/.beads/.br_history/issues.20260308_200829_595900053.jsonl.meta.json +0 -1
  156. package/.beads/.br_history/issues.20260308_200834_079930100.jsonl +0 -23
  157. package/.beads/.br_history/issues.20260308_200834_079930100.jsonl.meta.json +0 -1
  158. package/.beads/.br_history/issues.20260308_200858_370924996.jsonl +0 -24
  159. package/.beads/.br_history/issues.20260308_200858_370924996.jsonl.meta.json +0 -1
  160. package/.beads/.br_history/issues.20260308_201031_019730855.jsonl +0 -24
  161. package/.beads/.br_history/issues.20260308_201031_019730855.jsonl.meta.json +0 -1
  162. package/.beads/.br_history/issues.20260308_201031_578974884.jsonl +0 -24
  163. package/.beads/.br_history/issues.20260308_201031_578974884.jsonl.meta.json +0 -1
  164. package/.beads/.br_history/issues.20260308_201054_780345548.jsonl +0 -24
  165. package/.beads/.br_history/issues.20260308_201054_780345548.jsonl.meta.json +0 -1
  166. package/.beads/.br_history/issues.20260308_201054_896980019.jsonl +0 -24
  167. package/.beads/.br_history/issues.20260308_201054_896980019.jsonl.meta.json +0 -1
  168. package/.beads/.br_history/issues.20260308_201128_599819688.jsonl +0 -24
  169. package/.beads/.br_history/issues.20260308_201128_599819688.jsonl.meta.json +0 -1
  170. package/.beads/.br_history/issues.20260308_201128_710221699.jsonl +0 -24
  171. package/.beads/.br_history/issues.20260308_201128_710221699.jsonl.meta.json +0 -1
  172. package/.beads/.br_history/issues.20260308_201204_745649213.jsonl +0 -24
  173. package/.beads/.br_history/issues.20260308_201204_745649213.jsonl.meta.json +0 -1
  174. package/.beads/.br_history/issues.20260308_201338_908436144.jsonl +0 -24
  175. package/.beads/.br_history/issues.20260308_201338_908436144.jsonl.meta.json +0 -1
  176. package/.beads/.br_history/issues.20260308_201344_734860714.jsonl +0 -25
  177. package/.beads/.br_history/issues.20260308_201344_734860714.jsonl.meta.json +0 -1
  178. package/.beads/.br_history/issues.20260308_201630_819282295.jsonl +0 -25
  179. package/.beads/.br_history/issues.20260308_201630_819282295.jsonl.meta.json +0 -1
  180. package/.beads/.br_history/issues.20260308_203538_054279699.jsonl +0 -25
  181. package/.beads/.br_history/issues.20260308_203538_054279699.jsonl.meta.json +0 -1
  182. package/.beads/.br_history/issues.20260308_203547_597113070.jsonl +0 -26
  183. package/.beads/.br_history/issues.20260308_203547_597113070.jsonl.meta.json +0 -1
  184. package/.beads/.br_history/issues.20260308_203547_775139216.jsonl +0 -27
  185. package/.beads/.br_history/issues.20260308_203547_775139216.jsonl.meta.json +0 -1
  186. package/.beads/.br_history/issues.20260308_203547_950724773.jsonl +0 -28
  187. package/.beads/.br_history/issues.20260308_203547_950724773.jsonl.meta.json +0 -1
  188. package/.beads/.br_history/issues.20260308_203548_107684523.jsonl +0 -29
  189. package/.beads/.br_history/issues.20260308_203548_107684523.jsonl.meta.json +0 -1
  190. package/.beads/.br_history/issues.20260308_203548_310389993.jsonl +0 -30
  191. package/.beads/.br_history/issues.20260308_203548_310389993.jsonl.meta.json +0 -1
  192. package/.beads/.br_history/issues.20260308_203825_953337320.jsonl +0 -31
  193. package/.beads/.br_history/issues.20260308_203825_953337320.jsonl.meta.json +0 -1
  194. package/.beads/.br_history/issues.20260308_204056_071377736.jsonl +0 -32
  195. package/.beads/.br_history/issues.20260308_204056_071377736.jsonl.meta.json +0 -1
  196. package/.beads/.br_history/issues.20260308_205141_517616844.jsonl +0 -32
  197. package/.beads/.br_history/issues.20260308_205141_517616844.jsonl.meta.json +0 -1
  198. package/.beads/.br_history/issues.20260308_205141_648994024.jsonl +0 -32
  199. package/.beads/.br_history/issues.20260308_205141_648994024.jsonl.meta.json +0 -1
  200. package/.beads/.br_history/issues.20260308_205141_867598036.jsonl +0 -32
  201. package/.beads/.br_history/issues.20260308_205141_867598036.jsonl.meta.json +0 -1
  202. package/.beads/.br_history/issues.20260308_205142_094157355.jsonl +0 -32
  203. package/.beads/.br_history/issues.20260308_205142_094157355.jsonl.meta.json +0 -1
  204. package/.beads/.br_history/issues.20260308_205142_327315677.jsonl +0 -32
  205. package/.beads/.br_history/issues.20260308_205142_327315677.jsonl.meta.json +0 -1
  206. package/.beads/.br_history/issues.20260308_205142_545563822.jsonl +0 -32
  207. package/.beads/.br_history/issues.20260308_205142_545563822.jsonl.meta.json +0 -1
  208. package/.beads/.br_history/issues.20260308_205213_061989333.jsonl +0 -32
  209. package/.beads/.br_history/issues.20260308_205213_061989333.jsonl.meta.json +0 -1
  210. package/.beads/.br_history/issues.20260308_205213_181103364.jsonl +0 -32
  211. package/.beads/.br_history/issues.20260308_205213_181103364.jsonl.meta.json +0 -1
  212. package/.beads/.br_history/issues.20260308_205213_408872234.jsonl +0 -32
  213. package/.beads/.br_history/issues.20260308_205213_408872234.jsonl.meta.json +0 -1
  214. package/.beads/.br_history/issues.20260308_205213_616681652.jsonl +0 -32
  215. package/.beads/.br_history/issues.20260308_205213_616681652.jsonl.meta.json +0 -1
  216. package/.beads/.br_history/issues.20260308_205213_821507069.jsonl +0 -32
  217. package/.beads/.br_history/issues.20260308_205213_821507069.jsonl.meta.json +0 -1
  218. package/.beads/.br_history/issues.20260308_205214_026661112.jsonl +0 -32
  219. package/.beads/.br_history/issues.20260308_205214_026661112.jsonl.meta.json +0 -1
  220. package/.beads/.br_history/issues.20260308_205454_955250554.jsonl +0 -32
  221. package/.beads/.br_history/issues.20260308_205454_955250554.jsonl.meta.json +0 -1
  222. package/.beads/.br_history/issues.20260308_205556_337800392.jsonl +0 -33
  223. package/.beads/.br_history/issues.20260308_205556_337800392.jsonl.meta.json +0 -1
  224. package/.beads/.br_history/issues.20260308_205824_274686694.jsonl +0 -33
  225. package/.beads/.br_history/issues.20260308_205824_274686694.jsonl.meta.json +0 -1
  226. package/.beads/.br_history/issues.20260308_210240_583768328.jsonl +0 -34
  227. package/.beads/.br_history/issues.20260308_210240_583768328.jsonl.meta.json +0 -1
  228. package/.beads/.br_history/issues.20260308_212223_641541494.jsonl +0 -34
  229. package/.beads/.br_history/issues.20260308_212223_641541494.jsonl.meta.json +0 -1
  230. package/.beads/.br_history/issues.20260308_212227_735550996.jsonl +0 -35
  231. package/.beads/.br_history/issues.20260308_212227_735550996.jsonl.meta.json +0 -1
  232. package/.beads/.br_history/issues.20260308_212232_547298548.jsonl +0 -36
  233. package/.beads/.br_history/issues.20260308_212232_547298548.jsonl.meta.json +0 -1
  234. package/.beads/.br_history/issues.20260308_212528_843628125.jsonl +0 -37
  235. package/.beads/.br_history/issues.20260308_212528_843628125.jsonl.meta.json +0 -1
  236. package/.beads/.br_history/issues.20260308_212529_094530502.jsonl +0 -38
  237. package/.beads/.br_history/issues.20260308_212529_094530502.jsonl.meta.json +0 -1
  238. package/.beads/.br_history/issues.20260308_212529_331000853.jsonl +0 -39
  239. package/.beads/.br_history/issues.20260308_212529_331000853.jsonl.meta.json +0 -1
  240. package/.beads/.br_history/issues.20260308_212529_587925652.jsonl +0 -40
  241. package/.beads/.br_history/issues.20260308_212529_587925652.jsonl.meta.json +0 -1
  242. package/.beads/.br_history/issues.20260308_212804_927764103.jsonl +0 -41
  243. package/.beads/.br_history/issues.20260308_212804_927764103.jsonl.meta.json +0 -1
  244. package/.beads/.br_history/issues.20260308_212805_153673453.jsonl +0 -42
  245. package/.beads/.br_history/issues.20260308_212805_153673453.jsonl.meta.json +0 -1
  246. package/.beads/.br_history/issues.20260308_212805_415982363.jsonl +0 -43
  247. package/.beads/.br_history/issues.20260308_212805_415982363.jsonl.meta.json +0 -1
  248. package/.beads/.br_history/issues.20260308_212805_657497741.jsonl +0 -44
  249. package/.beads/.br_history/issues.20260308_212805_657497741.jsonl.meta.json +0 -1
  250. package/.beads/.br_history/issues.20260308_212805_952838724.jsonl +0 -45
  251. package/.beads/.br_history/issues.20260308_212805_952838724.jsonl.meta.json +0 -1
  252. package/.beads/.br_history/issues.20260308_212806_325433779.jsonl +0 -46
  253. package/.beads/.br_history/issues.20260308_212806_325433779.jsonl.meta.json +0 -1
  254. package/.beads/.br_history/issues.20260308_212806_584685598.jsonl +0 -47
  255. package/.beads/.br_history/issues.20260308_212806_584685598.jsonl.meta.json +0 -1
  256. package/.beads/.br_history/issues.20260308_212806_827817208.jsonl +0 -48
  257. package/.beads/.br_history/issues.20260308_212806_827817208.jsonl.meta.json +0 -1
  258. package/.beads/.br_history/issues.20260308_212807_111320451.jsonl +0 -49
  259. package/.beads/.br_history/issues.20260308_212807_111320451.jsonl.meta.json +0 -1
  260. package/.beads/.br_history/issues.20260308_212807_409545536.jsonl +0 -50
  261. package/.beads/.br_history/issues.20260308_212807_409545536.jsonl.meta.json +0 -1
  262. package/.beads/.br_history/issues.20260308_212807_625063294.jsonl +0 -51
  263. package/.beads/.br_history/issues.20260308_212807_625063294.jsonl.meta.json +0 -1
  264. package/.beads/.br_history/issues.20260308_212807_843906551.jsonl +0 -52
  265. package/.beads/.br_history/issues.20260308_212807_843906551.jsonl.meta.json +0 -1
  266. package/.beads/.br_history/issues.20260308_212808_100304073.jsonl +0 -53
  267. package/.beads/.br_history/issues.20260308_212808_100304073.jsonl.meta.json +0 -1
  268. package/.beads/.br_history/issues.20260308_212808_324723976.jsonl +0 -54
  269. package/.beads/.br_history/issues.20260308_212808_324723976.jsonl.meta.json +0 -1
  270. package/.beads/.br_history/issues.20260308_212808_557513104.jsonl +0 -55
  271. package/.beads/.br_history/issues.20260308_212808_557513104.jsonl.meta.json +0 -1
  272. package/.beads/.br_history/issues.20260308_212808_788048322.jsonl +0 -56
  273. package/.beads/.br_history/issues.20260308_212808_788048322.jsonl.meta.json +0 -1
  274. package/.beads/.br_history/issues.20260308_213702_613249728.jsonl +0 -57
  275. package/.beads/.br_history/issues.20260308_213702_613249728.jsonl.meta.json +0 -1
  276. package/.beads/.br_history/issues.20260308_213715_115792063.jsonl +0 -57
  277. package/.beads/.br_history/issues.20260308_213715_115792063.jsonl.meta.json +0 -1
  278. package/.beads/.br_history/issues.20260308_213715_462220666.jsonl +0 -57
  279. package/.beads/.br_history/issues.20260308_213715_462220666.jsonl.meta.json +0 -1
  280. package/.beads/.br_history/issues.20260308_213727_191258923.jsonl +0 -57
  281. package/.beads/.br_history/issues.20260308_213727_191258923.jsonl.meta.json +0 -1
  282. package/.beads/.br_history/issues.20260308_213727_684383652.jsonl +0 -57
  283. package/.beads/.br_history/issues.20260308_213727_684383652.jsonl.meta.json +0 -1
  284. package/.beads/.br_history/issues.20260308_213735_751882991.jsonl +0 -57
  285. package/.beads/.br_history/issues.20260308_213735_751882991.jsonl.meta.json +0 -1
  286. package/.beads/.br_history/issues.20260308_222052_279844960.jsonl +0 -57
  287. package/.beads/.br_history/issues.20260308_222052_279844960.jsonl.meta.json +0 -1
  288. package/.beads/.br_history/issues.20260308_222056_873282114.jsonl +0 -57
  289. package/.beads/.br_history/issues.20260308_222056_873282114.jsonl.meta.json +0 -1
  290. package/.beads/.br_history/issues.20260308_222103_402410761.jsonl +0 -57
  291. package/.beads/.br_history/issues.20260308_222103_402410761.jsonl.meta.json +0 -1
  292. package/.beads/.br_history/issues.20260308_235202_180577215.jsonl +0 -57
  293. package/.beads/.br_history/issues.20260308_235202_180577215.jsonl.meta.json +0 -1
  294. package/.beads/.br_history/issues.20260308_235202_387414163.jsonl +0 -57
  295. package/.beads/.br_history/issues.20260308_235202_387414163.jsonl.meta.json +0 -1
  296. package/.beads/.br_history/issues.20260308_235202_564422794.jsonl +0 -57
  297. package/.beads/.br_history/issues.20260308_235202_564422794.jsonl.meta.json +0 -1
  298. package/.beads/.br_history/issues.20260308_235202_742600597.jsonl +0 -57
  299. package/.beads/.br_history/issues.20260308_235202_742600597.jsonl.meta.json +0 -1
  300. package/.beads/.br_history/issues.20260308_235208_133360069.jsonl +0 -57
  301. package/.beads/.br_history/issues.20260308_235208_133360069.jsonl.meta.json +0 -1
  302. package/.beads/.br_history/issues.20260308_235505_473406307.jsonl +0 -57
  303. package/.beads/.br_history/issues.20260308_235505_473406307.jsonl.meta.json +0 -1
  304. package/.beads/.br_history/issues.20260308_235505_662360489.jsonl +0 -57
  305. package/.beads/.br_history/issues.20260308_235505_662360489.jsonl.meta.json +0 -1
  306. package/.beads/.br_history/issues.20260308_235505_843935624.jsonl +0 -57
  307. package/.beads/.br_history/issues.20260308_235505_843935624.jsonl.meta.json +0 -1
  308. package/.beads/.br_history/issues.20260308_235506_044530221.jsonl +0 -57
  309. package/.beads/.br_history/issues.20260308_235506_044530221.jsonl.meta.json +0 -1
  310. package/.beads/.br_history/issues.20260309_002618_115728731.jsonl +0 -57
  311. package/.beads/.br_history/issues.20260309_002618_115728731.jsonl.meta.json +0 -1
  312. package/.beads/.br_history/issues.20260309_003748_878174586.jsonl +0 -57
  313. package/.beads/.br_history/issues.20260309_003748_878174586.jsonl.meta.json +0 -1
  314. package/.beads/.br_history/issues.20260309_004057_868755623.jsonl +0 -57
  315. package/.beads/.br_history/issues.20260309_004057_868755623.jsonl.meta.json +0 -1
  316. package/.beads/.br_history/issues.20260309_004058_512842163.jsonl +0 -57
  317. package/.beads/.br_history/issues.20260309_004058_512842163.jsonl.meta.json +0 -1
  318. package/.beads/.br_history/issues.20260309_004058_994445226.jsonl +0 -57
  319. package/.beads/.br_history/issues.20260309_004058_994445226.jsonl.meta.json +0 -1
  320. package/.beads/.br_history/issues.20260309_004059_475988596.jsonl +0 -57
  321. package/.beads/.br_history/issues.20260309_004059_475988596.jsonl.meta.json +0 -1
  322. package/.beads/.br_history/issues.20260309_161902_566857851.jsonl +0 -57
  323. package/.beads/.br_history/issues.20260309_161902_566857851.jsonl.meta.json +0 -1
  324. package/.beads/.br_history/issues.20260309_170512_277017739.jsonl +0 -57
  325. package/.beads/.br_history/issues.20260309_170512_277017739.jsonl.meta.json +0 -1
  326. package/.beads/.br_history/issues.20260309_170512_477876921.jsonl +0 -57
  327. package/.beads/.br_history/issues.20260309_170512_477876921.jsonl.meta.json +0 -1
  328. package/.beads/.br_history/issues.20260309_170512_664382701.jsonl +0 -57
  329. package/.beads/.br_history/issues.20260309_170512_664382701.jsonl.meta.json +0 -1
  330. package/.beads/.br_history/issues.20260309_170512_859400333.jsonl +0 -57
  331. package/.beads/.br_history/issues.20260309_170512_859400333.jsonl.meta.json +0 -1
  332. package/.beads/.br_history/issues.20260309_212326_082771164.jsonl +0 -57
  333. package/.beads/.br_history/issues.20260309_212326_082771164.jsonl.meta.json +0 -1
  334. package/.beads/.br_history/issues.20260309_212326_245619716.jsonl +0 -58
  335. package/.beads/.br_history/issues.20260309_212326_245619716.jsonl.meta.json +0 -1
  336. package/.beads/.br_history/issues.20260309_212326_403198317.jsonl +0 -59
  337. package/.beads/.br_history/issues.20260309_212326_403198317.jsonl.meta.json +0 -1
  338. package/.beads/.br_history/issues.20260309_212332_539197678.jsonl +0 -60
  339. package/.beads/.br_history/issues.20260309_212332_539197678.jsonl.meta.json +0 -1
  340. package/.beads/.br_history/issues.20260309_212332_731373599.jsonl +0 -60
  341. package/.beads/.br_history/issues.20260309_212332_731373599.jsonl.meta.json +0 -1
  342. package/.beads/.br_history/issues.20260309_212332_928710953.jsonl +0 -60
  343. package/.beads/.br_history/issues.20260309_212332_928710953.jsonl.meta.json +0 -1
  344. package/.beads/.br_history/issues.20260309_213021_341505240.jsonl +0 -60
  345. package/.beads/.br_history/issues.20260309_213021_341505240.jsonl.meta.json +0 -1
  346. package/.beads/.br_history/issues.20260309_213022_023136934.jsonl +0 -60
  347. package/.beads/.br_history/issues.20260309_213022_023136934.jsonl.meta.json +0 -1
  348. package/.beads/.br_history/issues.20260309_213022_400050719.jsonl +0 -60
  349. package/.beads/.br_history/issues.20260309_213022_400050719.jsonl.meta.json +0 -1
  350. package/.beads/config.yaml +0 -4
  351. package/.beads/issues.jsonl +0 -60
  352. package/.beads/metadata.json +0 -4
  353. package/docs/mcp-cheatsheet.md +0 -324
  354. package/docs/visual-overview.md +0 -21
  355. package/ref-monty/.cargo/config.toml +0 -3
  356. package/ref-monty/.claude/settings.json +0 -60
  357. package/ref-monty/.claude/skills/fastmod/SKILL.md +0 -22
  358. package/ref-monty/.claude/skills/python-playground/SKILL.md +0 -47
  359. package/ref-monty/.codecov.yml +0 -12
  360. package/ref-monty/.github/actions/build-pgo-wheel/action.yml +0 -72
  361. package/ref-monty/.github/workflows/ci.yml +0 -776
  362. package/ref-monty/.github/workflows/codspeed.yml +0 -45
  363. package/ref-monty/.github/workflows/init-npm-packages.yml +0 -82
  364. package/ref-monty/.pre-commit-config.yaml +0 -47
  365. package/ref-monty/.python-version +0 -1
  366. package/ref-monty/.rustfmt.toml +0 -4
  367. package/ref-monty/.zed/settings.json +0 -11
  368. package/ref-monty/CLAUDE.md +0 -535
  369. package/ref-monty/Cargo.lock +0 -3798
  370. package/ref-monty/Cargo.toml +0 -87
  371. package/ref-monty/LICENSE +0 -21
  372. package/ref-monty/Makefile +0 -216
  373. package/ref-monty/README.md +0 -430
  374. package/ref-monty/RELEASING.md +0 -47
  375. package/ref-monty/crates/fuzz/Cargo.toml +0 -30
  376. package/ref-monty/crates/fuzz/fuzz_targets/string_input_panic.rs +0 -37
  377. package/ref-monty/crates/fuzz/fuzz_targets/tokens_input_panic.rs +0 -552
  378. package/ref-monty/crates/monty/Cargo.toml +0 -68
  379. package/ref-monty/crates/monty/benches/main.rs +0 -247
  380. package/ref-monty/crates/monty/build.rs +0 -10
  381. package/ref-monty/crates/monty/src/args.rs +0 -733
  382. package/ref-monty/crates/monty/src/asyncio.rs +0 -179
  383. package/ref-monty/crates/monty/src/builtins/abs.rs +0 -55
  384. package/ref-monty/crates/monty/src/builtins/all.rs +0 -30
  385. package/ref-monty/crates/monty/src/builtins/any.rs +0 -30
  386. package/ref-monty/crates/monty/src/builtins/bin.rs +0 -59
  387. package/ref-monty/crates/monty/src/builtins/chr.rs +0 -46
  388. package/ref-monty/crates/monty/src/builtins/divmod.rs +0 -164
  389. package/ref-monty/crates/monty/src/builtins/enumerate.rs +0 -52
  390. package/ref-monty/crates/monty/src/builtins/filter.rs +0 -67
  391. package/ref-monty/crates/monty/src/builtins/getattr.rs +0 -65
  392. package/ref-monty/crates/monty/src/builtins/hash.rs +0 -28
  393. package/ref-monty/crates/monty/src/builtins/hex.rs +0 -58
  394. package/ref-monty/crates/monty/src/builtins/id.rs +0 -24
  395. package/ref-monty/crates/monty/src/builtins/isinstance.rs +0 -68
  396. package/ref-monty/crates/monty/src/builtins/len.rs +0 -25
  397. package/ref-monty/crates/monty/src/builtins/map.rs +0 -98
  398. package/ref-monty/crates/monty/src/builtins/min_max.rs +0 -113
  399. package/ref-monty/crates/monty/src/builtins/mod.rs +0 -246
  400. package/ref-monty/crates/monty/src/builtins/next.rs +0 -21
  401. package/ref-monty/crates/monty/src/builtins/oct.rs +0 -59
  402. package/ref-monty/crates/monty/src/builtins/ord.rs +0 -67
  403. package/ref-monty/crates/monty/src/builtins/pow.rs +0 -365
  404. package/ref-monty/crates/monty/src/builtins/print.rs +0 -141
  405. package/ref-monty/crates/monty/src/builtins/repr.rs +0 -16
  406. package/ref-monty/crates/monty/src/builtins/reversed.rs +0 -28
  407. package/ref-monty/crates/monty/src/builtins/round.rs +0 -174
  408. package/ref-monty/crates/monty/src/builtins/sorted.rs +0 -151
  409. package/ref-monty/crates/monty/src/builtins/sum.rs +0 -66
  410. package/ref-monty/crates/monty/src/builtins/type_.rs +0 -16
  411. package/ref-monty/crates/monty/src/builtins/zip.rs +0 -77
  412. package/ref-monty/crates/monty/src/bytecode/builder.rs +0 -699
  413. package/ref-monty/crates/monty/src/bytecode/code.rs +0 -310
  414. package/ref-monty/crates/monty/src/bytecode/compiler.rs +0 -3206
  415. package/ref-monty/crates/monty/src/bytecode/mod.rs +0 -24
  416. package/ref-monty/crates/monty/src/bytecode/op.rs +0 -617
  417. package/ref-monty/crates/monty/src/bytecode/vm/async_exec.rs +0 -1058
  418. package/ref-monty/crates/monty/src/bytecode/vm/attr.rs +0 -63
  419. package/ref-monty/crates/monty/src/bytecode/vm/binary.rs +0 -487
  420. package/ref-monty/crates/monty/src/bytecode/vm/call.rs +0 -767
  421. package/ref-monty/crates/monty/src/bytecode/vm/collections.rs +0 -741
  422. package/ref-monty/crates/monty/src/bytecode/vm/compare.rs +0 -147
  423. package/ref-monty/crates/monty/src/bytecode/vm/exceptions.rs +0 -297
  424. package/ref-monty/crates/monty/src/bytecode/vm/format.rs +0 -132
  425. package/ref-monty/crates/monty/src/bytecode/vm/mod.rs +0 -1958
  426. package/ref-monty/crates/monty/src/bytecode/vm/scheduler.rs +0 -620
  427. package/ref-monty/crates/monty/src/exception_private.rs +0 -1513
  428. package/ref-monty/crates/monty/src/exception_public.rs +0 -346
  429. package/ref-monty/crates/monty/src/expressions.rs +0 -694
  430. package/ref-monty/crates/monty/src/fstring.rs +0 -854
  431. package/ref-monty/crates/monty/src/function.rs +0 -119
  432. package/ref-monty/crates/monty/src/heap.rs +0 -1073
  433. package/ref-monty/crates/monty/src/heap_data.rs +0 -985
  434. package/ref-monty/crates/monty/src/heap_traits.rs +0 -312
  435. package/ref-monty/crates/monty/src/intern.rs +0 -837
  436. package/ref-monty/crates/monty/src/io.rs +0 -106
  437. package/ref-monty/crates/monty/src/lib.rs +0 -52
  438. package/ref-monty/crates/monty/src/modules/asyncio.rs +0 -144
  439. package/ref-monty/crates/monty/src/modules/math.rs +0 -1453
  440. package/ref-monty/crates/monty/src/modules/mod.rs +0 -120
  441. package/ref-monty/crates/monty/src/modules/os.rs +0 -116
  442. package/ref-monty/crates/monty/src/modules/pathlib.rs +0 -33
  443. package/ref-monty/crates/monty/src/modules/re.rs +0 -606
  444. package/ref-monty/crates/monty/src/modules/sys.rs +0 -60
  445. package/ref-monty/crates/monty/src/modules/typing.rs +0 -70
  446. package/ref-monty/crates/monty/src/namespace.rs +0 -21
  447. package/ref-monty/crates/monty/src/object.rs +0 -1040
  448. package/ref-monty/crates/monty/src/os.rs +0 -215
  449. package/ref-monty/crates/monty/src/parse.rs +0 -1730
  450. package/ref-monty/crates/monty/src/prepare.rs +0 -3015
  451. package/ref-monty/crates/monty/src/repl.rs +0 -1109
  452. package/ref-monty/crates/monty/src/resource.rs +0 -559
  453. package/ref-monty/crates/monty/src/run.rs +0 -457
  454. package/ref-monty/crates/monty/src/run_progress.rs +0 -821
  455. package/ref-monty/crates/monty/src/signature.rs +0 -651
  456. package/ref-monty/crates/monty/src/sorting.rs +0 -100
  457. package/ref-monty/crates/monty/src/types/bytes.rs +0 -2356
  458. package/ref-monty/crates/monty/src/types/dataclass.rs +0 -345
  459. package/ref-monty/crates/monty/src/types/dict.rs +0 -879
  460. package/ref-monty/crates/monty/src/types/dict_view.rs +0 -619
  461. package/ref-monty/crates/monty/src/types/iter.rs +0 -799
  462. package/ref-monty/crates/monty/src/types/list.rs +0 -929
  463. package/ref-monty/crates/monty/src/types/long_int.rs +0 -211
  464. package/ref-monty/crates/monty/src/types/mod.rs +0 -48
  465. package/ref-monty/crates/monty/src/types/module.rs +0 -146
  466. package/ref-monty/crates/monty/src/types/namedtuple.rs +0 -261
  467. package/ref-monty/crates/monty/src/types/path.rs +0 -596
  468. package/ref-monty/crates/monty/src/types/property.rs +0 -35
  469. package/ref-monty/crates/monty/src/types/py_trait.rs +0 -322
  470. package/ref-monty/crates/monty/src/types/range.rs +0 -285
  471. package/ref-monty/crates/monty/src/types/re_match.rs +0 -522
  472. package/ref-monty/crates/monty/src/types/re_pattern.rs +0 -726
  473. package/ref-monty/crates/monty/src/types/set.rs +0 -1373
  474. package/ref-monty/crates/monty/src/types/slice.rs +0 -257
  475. package/ref-monty/crates/monty/src/types/str.rs +0 -2051
  476. package/ref-monty/crates/monty/src/types/tuple.rs +0 -376
  477. package/ref-monty/crates/monty/src/types/type.rs +0 -407
  478. package/ref-monty/crates/monty/src/value.rs +0 -2558
  479. package/ref-monty/crates/monty/test_cases/args__dict_get_no_args.py +0 -3
  480. package/ref-monty/crates/monty/test_cases/args__dict_get_too_many.py +0 -3
  481. package/ref-monty/crates/monty/test_cases/args__dict_items_with_args.py +0 -3
  482. package/ref-monty/crates/monty/test_cases/args__dict_keys_with_args.py +0 -3
  483. package/ref-monty/crates/monty/test_cases/args__dict_pop_no_args.py +0 -3
  484. package/ref-monty/crates/monty/test_cases/args__dict_pop_too_many.py +0 -3
  485. package/ref-monty/crates/monty/test_cases/args__dict_values_with_args.py +0 -3
  486. package/ref-monty/crates/monty/test_cases/args__id_too_many.py +0 -2
  487. package/ref-monty/crates/monty/test_cases/args__len_no_args.py +0 -2
  488. package/ref-monty/crates/monty/test_cases/args__len_too_many.py +0 -2
  489. package/ref-monty/crates/monty/test_cases/args__len_type_error_int.py +0 -9
  490. package/ref-monty/crates/monty/test_cases/args__len_type_error_none.py +0 -9
  491. package/ref-monty/crates/monty/test_cases/args__list_append_no_args.py +0 -3
  492. package/ref-monty/crates/monty/test_cases/args__list_append_too_many.py +0 -3
  493. package/ref-monty/crates/monty/test_cases/args__list_insert_too_few.py +0 -3
  494. package/ref-monty/crates/monty/test_cases/args__list_insert_too_many.py +0 -3
  495. package/ref-monty/crates/monty/test_cases/args__repr_no_args.py +0 -2
  496. package/ref-monty/crates/monty/test_cases/arith__div_zero_float.py +0 -2
  497. package/ref-monty/crates/monty/test_cases/arith__div_zero_int.py +0 -2
  498. package/ref-monty/crates/monty/test_cases/arith__floordiv_zero_float.py +0 -2
  499. package/ref-monty/crates/monty/test_cases/arith__floordiv_zero_int.py +0 -2
  500. package/ref-monty/crates/monty/test_cases/arith__pow_zero_neg.py +0 -2
  501. package/ref-monty/crates/monty/test_cases/arith__pow_zero_neg_builtin.py +0 -9
  502. package/ref-monty/crates/monty/test_cases/assert__expr_fail.py +0 -2
  503. package/ref-monty/crates/monty/test_cases/assert__fail.py +0 -2
  504. package/ref-monty/crates/monty/test_cases/assert__fail_msg.py +0 -2
  505. package/ref-monty/crates/monty/test_cases/assert__fn_fail.py +0 -3
  506. package/ref-monty/crates/monty/test_cases/assert__ops.py +0 -11
  507. package/ref-monty/crates/monty/test_cases/async__asyncio_run.py +0 -47
  508. package/ref-monty/crates/monty/test_cases/async__basic.py +0 -10
  509. package/ref-monty/crates/monty/test_cases/async__closure.py +0 -14
  510. package/ref-monty/crates/monty/test_cases/async__double_await_coroutine.py +0 -16
  511. package/ref-monty/crates/monty/test_cases/async__exception.py +0 -10
  512. package/ref-monty/crates/monty/test_cases/async__ext_call.py +0 -73
  513. package/ref-monty/crates/monty/test_cases/async__gather_all.py +0 -85
  514. package/ref-monty/crates/monty/test_cases/async__nested_await.py +0 -15
  515. package/ref-monty/crates/monty/test_cases/async__nested_gather_ext.py +0 -37
  516. package/ref-monty/crates/monty/test_cases/async__not_awaitable.py +0 -10
  517. package/ref-monty/crates/monty/test_cases/async__not_imported.py +0 -14
  518. package/ref-monty/crates/monty/test_cases/async__recursion_depth_isolation.py +0 -27
  519. package/ref-monty/crates/monty/test_cases/async__return_types.py +0 -31
  520. package/ref-monty/crates/monty/test_cases/async__sequential.py +0 -16
  521. package/ref-monty/crates/monty/test_cases/async__traceback.py +0 -19
  522. package/ref-monty/crates/monty/test_cases/async__with_args.py +0 -14
  523. package/ref-monty/crates/monty/test_cases/attr__get_int_error.py +0 -9
  524. package/ref-monty/crates/monty/test_cases/attr__get_list_error.py +0 -9
  525. package/ref-monty/crates/monty/test_cases/attr__set_frozen_nonfield.py +0 -12
  526. package/ref-monty/crates/monty/test_cases/attr__set_int_error.py +0 -10
  527. package/ref-monty/crates/monty/test_cases/attr__set_list_error.py +0 -10
  528. package/ref-monty/crates/monty/test_cases/bench__kitchen_sink.py +0 -68
  529. package/ref-monty/crates/monty/test_cases/bool__ops.py +0 -20
  530. package/ref-monty/crates/monty/test_cases/builtin__add_type_error.py +0 -2
  531. package/ref-monty/crates/monty/test_cases/builtin__filter.py +0 -62
  532. package/ref-monty/crates/monty/test_cases/builtin__filter_not_iterable.py +0 -11
  533. package/ref-monty/crates/monty/test_cases/builtin__getattr.py +0 -84
  534. package/ref-monty/crates/monty/test_cases/builtin__iter_funcs.py +0 -42
  535. package/ref-monty/crates/monty/test_cases/builtin__iter_next.py +0 -66
  536. package/ref-monty/crates/monty/test_cases/builtin__map.py +0 -74
  537. package/ref-monty/crates/monty/test_cases/builtin__map_not_iterable.py +0 -11
  538. package/ref-monty/crates/monty/test_cases/builtin__math_funcs.py +0 -154
  539. package/ref-monty/crates/monty/test_cases/builtin__more_iter_funcs.py +0 -148
  540. package/ref-monty/crates/monty/test_cases/builtin__next_stop_iteration.py +0 -10
  541. package/ref-monty/crates/monty/test_cases/builtin__print_invalid_kwarg.py +0 -9
  542. package/ref-monty/crates/monty/test_cases/builtin__print_kwargs.py +0 -12
  543. package/ref-monty/crates/monty/test_cases/builtin__repr.py +0 -3
  544. package/ref-monty/crates/monty/test_cases/builtin__string_funcs.py +0 -73
  545. package/ref-monty/crates/monty/test_cases/bytes__decode_invalid_utf8.py +0 -18
  546. package/ref-monty/crates/monty/test_cases/bytes__endswith_str_error.py +0 -10
  547. package/ref-monty/crates/monty/test_cases/bytes__getitem_index_error.py +0 -10
  548. package/ref-monty/crates/monty/test_cases/bytes__index_start_gt_end.py +0 -10
  549. package/ref-monty/crates/monty/test_cases/bytes__methods.py +0 -394
  550. package/ref-monty/crates/monty/test_cases/bytes__negative_count.py +0 -9
  551. package/ref-monty/crates/monty/test_cases/bytes__ops.py +0 -90
  552. package/ref-monty/crates/monty/test_cases/bytes__startswith_str_error.py +0 -10
  553. package/ref-monty/crates/monty/test_cases/call_object.py +0 -3
  554. package/ref-monty/crates/monty/test_cases/chain_comparison__all.py +0 -79
  555. package/ref-monty/crates/monty/test_cases/closure__param_shadows_outer.py +0 -81
  556. package/ref-monty/crates/monty/test_cases/closure__pep448.py +0 -203
  557. package/ref-monty/crates/monty/test_cases/closure__undefined_nonlocal.py +0 -13
  558. package/ref-monty/crates/monty/test_cases/compare__mixed_types.py +0 -120
  559. package/ref-monty/crates/monty/test_cases/comprehension__all.py +0 -208
  560. package/ref-monty/crates/monty/test_cases/comprehension__scope.py +0 -7
  561. package/ref-monty/crates/monty/test_cases/comprehension__unbound_local.py +0 -14
  562. package/ref-monty/crates/monty/test_cases/dataclass__basic.py +0 -238
  563. package/ref-monty/crates/monty/test_cases/dataclass__call_field_error.py +0 -12
  564. package/ref-monty/crates/monty/test_cases/dataclass__frozen_set_error.py +0 -12
  565. package/ref-monty/crates/monty/test_cases/dataclass__get_missing_attr_error.py +0 -11
  566. package/ref-monty/crates/monty/test_cases/dict__get_unhashable_key.py +0 -3
  567. package/ref-monty/crates/monty/test_cases/dict__literal_unhashable_key.py +0 -2
  568. package/ref-monty/crates/monty/test_cases/dict__method_pop_missing_error.py +0 -3
  569. package/ref-monty/crates/monty/test_cases/dict__methods.py +0 -151
  570. package/ref-monty/crates/monty/test_cases/dict__ops.py +0 -133
  571. package/ref-monty/crates/monty/test_cases/dict__pop_unhashable_key.py +0 -4
  572. package/ref-monty/crates/monty/test_cases/dict__popitem_empty.py +0 -9
  573. package/ref-monty/crates/monty/test_cases/dict__subscript_missing_key.py +0 -3
  574. package/ref-monty/crates/monty/test_cases/dict__unhashable_dict_key.py +0 -2
  575. package/ref-monty/crates/monty/test_cases/dict__unhashable_list_key.py +0 -2
  576. package/ref-monty/crates/monty/test_cases/dict__unpack_type_error.py +0 -2
  577. package/ref-monty/crates/monty/test_cases/dict__views.py +0 -165
  578. package/ref-monty/crates/monty/test_cases/edge__all.py +0 -26
  579. package/ref-monty/crates/monty/test_cases/edge__float_int_mod.py +0 -2
  580. package/ref-monty/crates/monty/test_cases/edge__int_float_mod.py +0 -2
  581. package/ref-monty/crates/monty/test_cases/exc__args.py +0 -16
  582. package/ref-monty/crates/monty/test_cases/exc__str.py +0 -15
  583. package/ref-monty/crates/monty/test_cases/execute_ok__all.py +0 -54
  584. package/ref-monty/crates/monty/test_cases/execute_raise__error_instance_str.py +0 -2
  585. package/ref-monty/crates/monty/test_cases/execute_raise__error_no_args.py +0 -2
  586. package/ref-monty/crates/monty/test_cases/execute_raise__error_string_arg.py +0 -2
  587. package/ref-monty/crates/monty/test_cases/execute_raise__error_string_arg_quotes.py +0 -2
  588. package/ref-monty/crates/monty/test_cases/execute_raise__error_type.py +0 -2
  589. package/ref-monty/crates/monty/test_cases/execute_raise__raise_instance_via_var.py +0 -4
  590. package/ref-monty/crates/monty/test_cases/execute_raise__raise_list.py +0 -2
  591. package/ref-monty/crates/monty/test_cases/execute_raise__raise_number.py +0 -2
  592. package/ref-monty/crates/monty/test_cases/execute_raise__raise_type_call_via_var.py +0 -4
  593. package/ref-monty/crates/monty/test_cases/execute_raise__raise_type_direct.py +0 -3
  594. package/ref-monty/crates/monty/test_cases/execute_raise__raise_type_via_var.py +0 -4
  595. package/ref-monty/crates/monty/test_cases/ext_call__arg_side_effect_bug.py +0 -22
  596. package/ref-monty/crates/monty/test_cases/ext_call__augmented.py +0 -17
  597. package/ref-monty/crates/monty/test_cases/ext_call__augmented_refcount_bug.py +0 -7
  598. package/ref-monty/crates/monty/test_cases/ext_call__bare_raise_after_resume.py +0 -34
  599. package/ref-monty/crates/monty/test_cases/ext_call__basic.py +0 -99
  600. package/ref-monty/crates/monty/test_cases/ext_call__boolean.py +0 -37
  601. package/ref-monty/crates/monty/test_cases/ext_call__boolean_side_effect_hang.py +0 -17
  602. package/ref-monty/crates/monty/test_cases/ext_call__closure_bug.py +0 -16
  603. package/ref-monty/crates/monty/test_cases/ext_call__comparison.py +0 -26
  604. package/ref-monty/crates/monty/test_cases/ext_call__deep_call_stack.py +0 -18
  605. package/ref-monty/crates/monty/test_cases/ext_call__elif.py +0 -171
  606. package/ref-monty/crates/monty/test_cases/ext_call__exc.py +0 -4
  607. package/ref-monty/crates/monty/test_cases/ext_call__exc_deep_stack.py +0 -39
  608. package/ref-monty/crates/monty/test_cases/ext_call__exc_in_function.py +0 -17
  609. package/ref-monty/crates/monty/test_cases/ext_call__exc_nested_functions.py +0 -31
  610. package/ref-monty/crates/monty/test_cases/ext_call__ext_exc.py +0 -171
  611. package/ref-monty/crates/monty/test_cases/ext_call__for.py +0 -114
  612. package/ref-monty/crates/monty/test_cases/ext_call__fstring.py +0 -12
  613. package/ref-monty/crates/monty/test_cases/ext_call__if.py +0 -135
  614. package/ref-monty/crates/monty/test_cases/ext_call__if_condition.py +0 -37
  615. package/ref-monty/crates/monty/test_cases/ext_call__in_closure.py +0 -14
  616. package/ref-monty/crates/monty/test_cases/ext_call__in_function.py +0 -40
  617. package/ref-monty/crates/monty/test_cases/ext_call__in_function_simple.py +0 -7
  618. package/ref-monty/crates/monty/test_cases/ext_call__literals.py +0 -17
  619. package/ref-monty/crates/monty/test_cases/ext_call__multi_in_func.py +0 -32
  620. package/ref-monty/crates/monty/test_cases/ext_call__name_lookup.py +0 -69
  621. package/ref-monty/crates/monty/test_cases/ext_call__name_lookup_undefined.py +0 -4
  622. package/ref-monty/crates/monty/test_cases/ext_call__nested_calls.py +0 -14
  623. package/ref-monty/crates/monty/test_cases/ext_call__recursion_bug.py +0 -19
  624. package/ref-monty/crates/monty/test_cases/ext_call__return.py +0 -28
  625. package/ref-monty/crates/monty/test_cases/ext_call__side_effects.py +0 -25
  626. package/ref-monty/crates/monty/test_cases/ext_call__subscript.py +0 -7
  627. package/ref-monty/crates/monty/test_cases/ext_call__ternary.py +0 -28
  628. package/ref-monty/crates/monty/test_cases/ext_call__try.py +0 -280
  629. package/ref-monty/crates/monty/test_cases/ext_call__try_simple.py +0 -10
  630. package/ref-monty/crates/monty/test_cases/ext_call__unary.py +0 -13
  631. package/ref-monty/crates/monty/test_cases/frozenset__ops.py +0 -178
  632. package/ref-monty/crates/monty/test_cases/fstring__all.py +0 -236
  633. package/ref-monty/crates/monty/test_cases/fstring__error_eq_align_on_str.py +0 -3
  634. package/ref-monty/crates/monty/test_cases/fstring__error_float_f_on_str.py +0 -3
  635. package/ref-monty/crates/monty/test_cases/fstring__error_int_d_on_float.py +0 -3
  636. package/ref-monty/crates/monty/test_cases/fstring__error_int_d_on_str.py +0 -3
  637. package/ref-monty/crates/monty/test_cases/fstring__error_invalid_spec.py +0 -4
  638. package/ref-monty/crates/monty/test_cases/fstring__error_invalid_spec_dynamic.py +0 -4
  639. package/ref-monty/crates/monty/test_cases/fstring__error_invalid_spec_str.py +0 -4
  640. package/ref-monty/crates/monty/test_cases/fstring__error_str_s_on_int.py +0 -3
  641. package/ref-monty/crates/monty/test_cases/function__call_duplicate_kwargs.py +0 -6
  642. package/ref-monty/crates/monty/test_cases/function__call_unpack.py +0 -42
  643. package/ref-monty/crates/monty/test_cases/function__defaults.py +0 -117
  644. package/ref-monty/crates/monty/test_cases/function__err_duplicate_arg.py +0 -7
  645. package/ref-monty/crates/monty/test_cases/function__err_duplicate_first_arg.py +0 -7
  646. package/ref-monty/crates/monty/test_cases/function__err_duplicate_kwarg_cleanup.py +0 -9
  647. package/ref-monty/crates/monty/test_cases/function__err_kwonly_as_positional.py +0 -7
  648. package/ref-monty/crates/monty/test_cases/function__err_missing_all_posonly.py +0 -7
  649. package/ref-monty/crates/monty/test_cases/function__err_missing_heap_cleanup.py +0 -9
  650. package/ref-monty/crates/monty/test_cases/function__err_missing_kwonly.py +0 -7
  651. package/ref-monty/crates/monty/test_cases/function__err_missing_posonly_with_kwarg.py +0 -7
  652. package/ref-monty/crates/monty/test_cases/function__err_missing_with_posonly.py +0 -7
  653. package/ref-monty/crates/monty/test_cases/function__err_posonly_as_kwarg.py +0 -7
  654. package/ref-monty/crates/monty/test_cases/function__err_posonly_first_as_kwarg.py +0 -7
  655. package/ref-monty/crates/monty/test_cases/function__err_too_many_posonly.py +0 -7
  656. package/ref-monty/crates/monty/test_cases/function__err_too_many_with_kwonly.py +0 -7
  657. package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg.py +0 -7
  658. package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg_cleanup.py +0 -9
  659. package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg_quote.py +0 -13
  660. package/ref-monty/crates/monty/test_cases/function__err_unexpected_kwarg_simple.py +0 -7
  661. package/ref-monty/crates/monty/test_cases/function__err_unpack_duplicate_arg.py +0 -6
  662. package/ref-monty/crates/monty/test_cases/function__err_unpack_duplicate_heap.py +0 -8
  663. package/ref-monty/crates/monty/test_cases/function__err_unpack_int.py +0 -6
  664. package/ref-monty/crates/monty/test_cases/function__err_unpack_nonstring_key.py +0 -6
  665. package/ref-monty/crates/monty/test_cases/function__err_unpack_not_mapping.py +0 -6
  666. package/ref-monty/crates/monty/test_cases/function__kwargs_unpacking.py +0 -173
  667. package/ref-monty/crates/monty/test_cases/function__ops.py +0 -294
  668. package/ref-monty/crates/monty/test_cases/function__return_none.py +0 -42
  669. package/ref-monty/crates/monty/test_cases/function__signatures.py +0 -47
  670. package/ref-monty/crates/monty/test_cases/function__too_few_args_all.py +0 -6
  671. package/ref-monty/crates/monty/test_cases/function__too_few_args_one.py +0 -6
  672. package/ref-monty/crates/monty/test_cases/function__too_few_args_two.py +0 -6
  673. package/ref-monty/crates/monty/test_cases/function__too_many_args_one.py +0 -6
  674. package/ref-monty/crates/monty/test_cases/function__too_many_args_two.py +0 -6
  675. package/ref-monty/crates/monty/test_cases/function__too_many_args_zero.py +0 -6
  676. package/ref-monty/crates/monty/test_cases/global__error_assigned_before.py +0 -7
  677. package/ref-monty/crates/monty/test_cases/global__ops.py +0 -163
  678. package/ref-monty/crates/monty/test_cases/hash__dict_unhashable.py +0 -2
  679. package/ref-monty/crates/monty/test_cases/hash__list_unhashable.py +0 -2
  680. package/ref-monty/crates/monty/test_cases/hash__ops.py +0 -153
  681. package/ref-monty/crates/monty/test_cases/id__bytes_literals_distinct.py +0 -3
  682. package/ref-monty/crates/monty/test_cases/id__int_copy_distinct.py +0 -5
  683. package/ref-monty/crates/monty/test_cases/id__is_number_is_number.py +0 -3
  684. package/ref-monty/crates/monty/test_cases/id__non_overlapping_lifetimes_distinct_types.py +0 -10
  685. package/ref-monty/crates/monty/test_cases/id__non_overlapping_lifetimes_same_types.py +0 -6
  686. package/ref-monty/crates/monty/test_cases/id__ops.py +0 -97
  687. package/ref-monty/crates/monty/test_cases/id__str_literals_same.py +0 -3
  688. package/ref-monty/crates/monty/test_cases/if__elif_else.py +0 -207
  689. package/ref-monty/crates/monty/test_cases/if__raise_elif.py +0 -11
  690. package/ref-monty/crates/monty/test_cases/if__raise_else.py +0 -13
  691. package/ref-monty/crates/monty/test_cases/if__raise_if.py +0 -9
  692. package/ref-monty/crates/monty/test_cases/if__raise_in_elif_condition.py +0 -18
  693. package/ref-monty/crates/monty/test_cases/if__raise_in_if_condition.py +0 -16
  694. package/ref-monty/crates/monty/test_cases/if_else_expr__all.py +0 -55
  695. package/ref-monty/crates/monty/test_cases/import__error_cannot_import.py +0 -9
  696. package/ref-monty/crates/monty/test_cases/import__error_module_not_found.py +0 -9
  697. package/ref-monty/crates/monty/test_cases/import__local_scope.py +0 -68
  698. package/ref-monty/crates/monty/test_cases/import__os.py +0 -25
  699. package/ref-monty/crates/monty/test_cases/import__relative_error.py +0 -9
  700. package/ref-monty/crates/monty/test_cases/import__relative_no_module_error.py +0 -9
  701. package/ref-monty/crates/monty/test_cases/import__runtime_error_when_executed.py +0 -14
  702. package/ref-monty/crates/monty/test_cases/import__star_error.py +0 -11
  703. package/ref-monty/crates/monty/test_cases/import__sys.py +0 -47
  704. package/ref-monty/crates/monty/test_cases/import__sys_monty.py +0 -28
  705. package/ref-monty/crates/monty/test_cases/import__type_checking_guard.py +0 -37
  706. package/ref-monty/crates/monty/test_cases/import__typing.py +0 -25
  707. package/ref-monty/crates/monty/test_cases/import__typing_type_ignore.py +0 -4
  708. package/ref-monty/crates/monty/test_cases/int__bigint.py +0 -467
  709. package/ref-monty/crates/monty/test_cases/int__bigint_errors.py +0 -260
  710. package/ref-monty/crates/monty/test_cases/int__ops.py +0 -219
  711. package/ref-monty/crates/monty/test_cases/int__overflow_division.py +0 -84
  712. package/ref-monty/crates/monty/test_cases/is_variant__all.py +0 -36
  713. package/ref-monty/crates/monty/test_cases/isinstance__arg2_list_error.py +0 -2
  714. package/ref-monty/crates/monty/test_cases/isinstance__arg2_type_error.py +0 -2
  715. package/ref-monty/crates/monty/test_cases/iter__dict_mutation.py +0 -4
  716. package/ref-monty/crates/monty/test_cases/iter__for.py +0 -243
  717. package/ref-monty/crates/monty/test_cases/iter__for_loop_unpacking.py +0 -66
  718. package/ref-monty/crates/monty/test_cases/iter__generator_expr.py +0 -20
  719. package/ref-monty/crates/monty/test_cases/iter__generator_expr_type.py +0 -7
  720. package/ref-monty/crates/monty/test_cases/iter__not_iterable.py +0 -3
  721. package/ref-monty/crates/monty/test_cases/lambda__all.py +0 -145
  722. package/ref-monty/crates/monty/test_cases/list__extend_not_iterable.py +0 -7
  723. package/ref-monty/crates/monty/test_cases/list__getitem_out_of_bounds.py +0 -3
  724. package/ref-monty/crates/monty/test_cases/list__index_not_found.py +0 -9
  725. package/ref-monty/crates/monty/test_cases/list__index_start_gt_end.py +0 -10
  726. package/ref-monty/crates/monty/test_cases/list__ops.py +0 -473
  727. package/ref-monty/crates/monty/test_cases/list__pop_empty.py +0 -9
  728. package/ref-monty/crates/monty/test_cases/list__pop_out_of_range.py +0 -9
  729. package/ref-monty/crates/monty/test_cases/list__pop_type_error.py +0 -9
  730. package/ref-monty/crates/monty/test_cases/list__remove_not_found.py +0 -9
  731. package/ref-monty/crates/monty/test_cases/list__setitem_dict_index.py +0 -13
  732. package/ref-monty/crates/monty/test_cases/list__setitem_huge_int_index.py +0 -13
  733. package/ref-monty/crates/monty/test_cases/list__setitem_index_error.py +0 -10
  734. package/ref-monty/crates/monty/test_cases/list__setitem_type_error.py +0 -10
  735. package/ref-monty/crates/monty/test_cases/list__unpack_type_error.py +0 -2
  736. package/ref-monty/crates/monty/test_cases/longint__index_error.py +0 -3
  737. package/ref-monty/crates/monty/test_cases/longint__repeat_error.py +0 -3
  738. package/ref-monty/crates/monty/test_cases/loop__break_continue.py +0 -113
  739. package/ref-monty/crates/monty/test_cases/loop__break_finally.py +0 -69
  740. package/ref-monty/crates/monty/test_cases/loop__break_in_function_error.py +0 -13
  741. package/ref-monty/crates/monty/test_cases/loop__break_in_if_error.py +0 -11
  742. package/ref-monty/crates/monty/test_cases/loop__break_nested_except_clears.py +0 -55
  743. package/ref-monty/crates/monty/test_cases/loop__break_outside_error.py +0 -9
  744. package/ref-monty/crates/monty/test_cases/loop__continue_finally.py +0 -81
  745. package/ref-monty/crates/monty/test_cases/loop__continue_in_function_error.py +0 -13
  746. package/ref-monty/crates/monty/test_cases/loop__continue_in_if_error.py +0 -11
  747. package/ref-monty/crates/monty/test_cases/loop__continue_nested_except_clears.py +0 -60
  748. package/ref-monty/crates/monty/test_cases/loop__continue_outside_error.py +0 -9
  749. package/ref-monty/crates/monty/test_cases/math__acos_domain_error.py +0 -11
  750. package/ref-monty/crates/monty/test_cases/math__acosh_domain_error.py +0 -11
  751. package/ref-monty/crates/monty/test_cases/math__asin_domain_error.py +0 -11
  752. package/ref-monty/crates/monty/test_cases/math__atanh_domain_error.py +0 -11
  753. package/ref-monty/crates/monty/test_cases/math__cos_inf_error.py +0 -11
  754. package/ref-monty/crates/monty/test_cases/math__cosh_overflow_error.py +0 -11
  755. package/ref-monty/crates/monty/test_cases/math__exp_overflow_error.py +0 -11
  756. package/ref-monty/crates/monty/test_cases/math__factorial_float_error.py +0 -11
  757. package/ref-monty/crates/monty/test_cases/math__factorial_negative_error.py +0 -11
  758. package/ref-monty/crates/monty/test_cases/math__floor_inf_error.py +0 -11
  759. package/ref-monty/crates/monty/test_cases/math__floor_nan_error.py +0 -11
  760. package/ref-monty/crates/monty/test_cases/math__floor_str_error.py +0 -11
  761. package/ref-monty/crates/monty/test_cases/math__fmod_inf_error.py +0 -11
  762. package/ref-monty/crates/monty/test_cases/math__gamma_neg_int_error.py +0 -11
  763. package/ref-monty/crates/monty/test_cases/math__gcd_float_error.py +0 -11
  764. package/ref-monty/crates/monty/test_cases/math__isqrt_negative_error.py +0 -11
  765. package/ref-monty/crates/monty/test_cases/math__ldexp_overflow_error.py +0 -11
  766. package/ref-monty/crates/monty/test_cases/math__log1p_domain_error.py +0 -11
  767. package/ref-monty/crates/monty/test_cases/math__log_base1_error.py +0 -11
  768. package/ref-monty/crates/monty/test_cases/math__log_zero_error.py +0 -11
  769. package/ref-monty/crates/monty/test_cases/math__module.py +0 -1432
  770. package/ref-monty/crates/monty/test_cases/math__pow_domain_error.py +0 -11
  771. package/ref-monty/crates/monty/test_cases/math__sin_inf_error.py +0 -11
  772. package/ref-monty/crates/monty/test_cases/math__sqrt_negative_error.py +0 -11
  773. package/ref-monty/crates/monty/test_cases/math__tan_inf_error.py +0 -11
  774. package/ref-monty/crates/monty/test_cases/math__trunc_str_error.py +0 -11
  775. package/ref-monty/crates/monty/test_cases/method__args_kwargs_unpacking.py +0 -259
  776. package/ref-monty/crates/monty/test_cases/name_error__unbound_local_func.py +0 -19
  777. package/ref-monty/crates/monty/test_cases/name_error__unbound_local_module.py +0 -12
  778. package/ref-monty/crates/monty/test_cases/name_error__undefined_call_chained.py +0 -9
  779. package/ref-monty/crates/monty/test_cases/name_error__undefined_call_in_expr.py +0 -9
  780. package/ref-monty/crates/monty/test_cases/name_error__undefined_call_in_function.py +0 -16
  781. package/ref-monty/crates/monty/test_cases/name_error__undefined_call_with_args.py +0 -9
  782. package/ref-monty/crates/monty/test_cases/name_error__undefined_global.py +0 -10
  783. package/ref-monty/crates/monty/test_cases/namedtuple__missing_attr.py +0 -11
  784. package/ref-monty/crates/monty/test_cases/namedtuple__ops.py +0 -34
  785. package/ref-monty/crates/monty/test_cases/nonlocal__error_module_level.py +0 -3
  786. package/ref-monty/crates/monty/test_cases/nonlocal__ops.py +0 -353
  787. package/ref-monty/crates/monty/test_cases/os__environ.py +0 -40
  788. package/ref-monty/crates/monty/test_cases/os__getenv_key_list_error.py +0 -5
  789. package/ref-monty/crates/monty/test_cases/os__getenv_key_type_error.py +0 -5
  790. package/ref-monty/crates/monty/test_cases/parse_error__complex.py +0 -3
  791. package/ref-monty/crates/monty/test_cases/pathlib__import.py +0 -11
  792. package/ref-monty/crates/monty/test_cases/pathlib__os.py +0 -136
  793. package/ref-monty/crates/monty/test_cases/pathlib__os_read_error.py +0 -12
  794. package/ref-monty/crates/monty/test_cases/pathlib__pure.py +0 -81
  795. package/ref-monty/crates/monty/test_cases/pyobject__cycle_dict_self.py +0 -5
  796. package/ref-monty/crates/monty/test_cases/pyobject__cycle_list_dict.py +0 -6
  797. package/ref-monty/crates/monty/test_cases/pyobject__cycle_list_self.py +0 -5
  798. package/ref-monty/crates/monty/test_cases/pyobject__cycle_multiple_refs.py +0 -6
  799. package/ref-monty/crates/monty/test_cases/range__error_no_args.py +0 -2
  800. package/ref-monty/crates/monty/test_cases/range__error_step_zero.py +0 -2
  801. package/ref-monty/crates/monty/test_cases/range__error_too_many_args.py +0 -2
  802. package/ref-monty/crates/monty/test_cases/range__getitem_index_error.py +0 -10
  803. package/ref-monty/crates/monty/test_cases/range__ops.py +0 -236
  804. package/ref-monty/crates/monty/test_cases/re__basic.py +0 -756
  805. package/ref-monty/crates/monty/test_cases/re__grouping.py +0 -241
  806. package/ref-monty/crates/monty/test_cases/re__match.py +0 -148
  807. package/ref-monty/crates/monty/test_cases/recursion__deep_drop.py +0 -26
  808. package/ref-monty/crates/monty/test_cases/recursion__deep_eq.py +0 -23
  809. package/ref-monty/crates/monty/test_cases/recursion__deep_hash.py +0 -46
  810. package/ref-monty/crates/monty/test_cases/recursion__deep_repr.py +0 -12
  811. package/ref-monty/crates/monty/test_cases/recursion__function_depth.py +0 -13
  812. package/ref-monty/crates/monty/test_cases/refcount__cycle_mutual_reference.py +0 -18
  813. package/ref-monty/crates/monty/test_cases/refcount__cycle_self_reference.py +0 -12
  814. package/ref-monty/crates/monty/test_cases/refcount__dict_basic.py +0 -5
  815. package/ref-monty/crates/monty/test_cases/refcount__dict_get.py +0 -5
  816. package/ref-monty/crates/monty/test_cases/refcount__dict_keys_and.py +0 -14
  817. package/ref-monty/crates/monty/test_cases/refcount__dict_overwrite.py +0 -6
  818. package/ref-monty/crates/monty/test_cases/refcount__gather_cleanup.py +0 -16
  819. package/ref-monty/crates/monty/test_cases/refcount__gather_exception.py +0 -18
  820. package/ref-monty/crates/monty/test_cases/refcount__gather_nested_cancel.py +0 -25
  821. package/ref-monty/crates/monty/test_cases/refcount__immediate_skipped.py +0 -4
  822. package/ref-monty/crates/monty/test_cases/refcount__kwargs_unpacking.py +0 -27
  823. package/ref-monty/crates/monty/test_cases/refcount__list_append_multiple.py +0 -6
  824. package/ref-monty/crates/monty/test_cases/refcount__list_append_ref.py +0 -5
  825. package/ref-monty/crates/monty/test_cases/refcount__list_concat.py +0 -5
  826. package/ref-monty/crates/monty/test_cases/refcount__list_getitem.py +0 -5
  827. package/ref-monty/crates/monty/test_cases/refcount__list_iadd.py +0 -5
  828. package/ref-monty/crates/monty/test_cases/refcount__nested_list.py +0 -4
  829. package/ref-monty/crates/monty/test_cases/refcount__re_pattern_sub_error_paths.py +0 -37
  830. package/ref-monty/crates/monty/test_cases/refcount__re_search_match.py +0 -34
  831. package/ref-monty/crates/monty/test_cases/refcount__re_sub_error_paths.py +0 -31
  832. package/ref-monty/crates/monty/test_cases/refcount__shared_reference.py +0 -4
  833. package/ref-monty/crates/monty/test_cases/refcount__single_list.py +0 -3
  834. package/ref-monty/crates/monty/test_cases/repr__cycle_detection.py +0 -24
  835. package/ref-monty/crates/monty/test_cases/set__ops.py +0 -191
  836. package/ref-monty/crates/monty/test_cases/set__review_bugs.py +0 -35
  837. package/ref-monty/crates/monty/test_cases/set__unpack_type_error.py +0 -2
  838. package/ref-monty/crates/monty/test_cases/slice__invalid_indices.py +0 -2
  839. package/ref-monty/crates/monty/test_cases/slice__kwargs.py +0 -9
  840. package/ref-monty/crates/monty/test_cases/slice__no_args.py +0 -9
  841. package/ref-monty/crates/monty/test_cases/slice__ops.py +0 -149
  842. package/ref-monty/crates/monty/test_cases/slice__step_zero.py +0 -9
  843. package/ref-monty/crates/monty/test_cases/slice__step_zero_bytes.py +0 -9
  844. package/ref-monty/crates/monty/test_cases/slice__step_zero_range.py +0 -9
  845. package/ref-monty/crates/monty/test_cases/slice__step_zero_str.py +0 -9
  846. package/ref-monty/crates/monty/test_cases/slice__step_zero_tuple.py +0 -9
  847. package/ref-monty/crates/monty/test_cases/slice__too_many_args.py +0 -9
  848. package/ref-monty/crates/monty/test_cases/str__getitem_index_error.py +0 -10
  849. package/ref-monty/crates/monty/test_cases/str__index_not_found.py +0 -9
  850. package/ref-monty/crates/monty/test_cases/str__join_no_args.py +0 -9
  851. package/ref-monty/crates/monty/test_cases/str__join_non_string.py +0 -9
  852. package/ref-monty/crates/monty/test_cases/str__join_not_iterable.py +0 -9
  853. package/ref-monty/crates/monty/test_cases/str__join_too_many_args.py +0 -9
  854. package/ref-monty/crates/monty/test_cases/str__methods.py +0 -327
  855. package/ref-monty/crates/monty/test_cases/str__ops.py +0 -162
  856. package/ref-monty/crates/monty/test_cases/str__partition_empty.py +0 -9
  857. package/ref-monty/crates/monty/test_cases/str__rsplit_empty_sep.py +0 -9
  858. package/ref-monty/crates/monty/test_cases/str__split_empty_sep.py +0 -9
  859. package/ref-monty/crates/monty/test_cases/sys__types.py +0 -7
  860. package/ref-monty/crates/monty/test_cases/traceback__division_error.py +0 -30
  861. package/ref-monty/crates/monty/test_cases/traceback__index_error.py +0 -17
  862. package/ref-monty/crates/monty/test_cases/traceback__insert_as_int.py +0 -10
  863. package/ref-monty/crates/monty/test_cases/traceback__nested_call.py +0 -29
  864. package/ref-monty/crates/monty/test_cases/traceback__nonlocal_module_scope.py +0 -10
  865. package/ref-monty/crates/monty/test_cases/traceback__nonlocal_unbound.py +0 -24
  866. package/ref-monty/crates/monty/test_cases/traceback__range_as_int.py +0 -9
  867. package/ref-monty/crates/monty/test_cases/traceback__recursion_error.py +0 -23
  868. package/ref-monty/crates/monty/test_cases/traceback__set_mutation.py +0 -11
  869. package/ref-monty/crates/monty/test_cases/traceback__undefined_attr_call.py +0 -16
  870. package/ref-monty/crates/monty/test_cases/traceback__undefined_call.py +0 -16
  871. package/ref-monty/crates/monty/test_cases/traceback__undefined_raise.py +0 -16
  872. package/ref-monty/crates/monty/test_cases/try_except__all.py +0 -472
  873. package/ref-monty/crates/monty/test_cases/try_except__bare_raise_no_context.py +0 -2
  874. package/ref-monty/crates/monty/test_cases/try_except__invalid_type.py +0 -5
  875. package/ref-monty/crates/monty/test_cases/tuple__getitem_out_of_bounds.py +0 -3
  876. package/ref-monty/crates/monty/test_cases/tuple__index_not_found.py +0 -9
  877. package/ref-monty/crates/monty/test_cases/tuple__index_start_gt_end.py +0 -10
  878. package/ref-monty/crates/monty/test_cases/tuple__methods.py +0 -19
  879. package/ref-monty/crates/monty/test_cases/tuple__ops.py +0 -133
  880. package/ref-monty/crates/monty/test_cases/tuple__unpack_type_error.py +0 -2
  881. package/ref-monty/crates/monty/test_cases/type__builtin_attr_error.py +0 -9
  882. package/ref-monty/crates/monty/test_cases/type__bytes_negative.py +0 -2
  883. package/ref-monty/crates/monty/test_cases/type__cell_not_builtin.py +0 -9
  884. package/ref-monty/crates/monty/test_cases/type__exception_attr_error.py +0 -11
  885. package/ref-monty/crates/monty/test_cases/type__float_conversion_error.py +0 -2
  886. package/ref-monty/crates/monty/test_cases/type__float_repr_both_quotes.py +0 -9
  887. package/ref-monty/crates/monty/test_cases/type__float_repr_newline.py +0 -9
  888. package/ref-monty/crates/monty/test_cases/type__float_repr_single_quote.py +0 -9
  889. package/ref-monty/crates/monty/test_cases/type__int_conversion_error.py +0 -2
  890. package/ref-monty/crates/monty/test_cases/type__list_not_iterable.py +0 -2
  891. package/ref-monty/crates/monty/test_cases/type__non_builtin_name_error.py +0 -9
  892. package/ref-monty/crates/monty/test_cases/type__ops.py +0 -200
  893. package/ref-monty/crates/monty/test_cases/type__shadow_exc.py +0 -3
  894. package/ref-monty/crates/monty/test_cases/type__shadow_int.py +0 -9
  895. package/ref-monty/crates/monty/test_cases/type__shadow_len.py +0 -3
  896. package/ref-monty/crates/monty/test_cases/type__tuple_not_iterable.py +0 -2
  897. package/ref-monty/crates/monty/test_cases/type_error__int_add_list.py +0 -2
  898. package/ref-monty/crates/monty/test_cases/type_error__int_div_str.py +0 -2
  899. package/ref-monty/crates/monty/test_cases/type_error__int_floordiv_str.py +0 -2
  900. package/ref-monty/crates/monty/test_cases/type_error__int_iadd_str.py +0 -3
  901. package/ref-monty/crates/monty/test_cases/type_error__int_mod_str.py +0 -2
  902. package/ref-monty/crates/monty/test_cases/type_error__int_pow_str.py +0 -2
  903. package/ref-monty/crates/monty/test_cases/type_error__int_sub_str.py +0 -2
  904. package/ref-monty/crates/monty/test_cases/type_error__list_add_int.py +0 -2
  905. package/ref-monty/crates/monty/test_cases/type_error__list_add_str.py +0 -2
  906. package/ref-monty/crates/monty/test_cases/type_error__list_iadd_int.py +0 -6
  907. package/ref-monty/crates/monty/test_cases/type_error__str_add_int.py +0 -2
  908. package/ref-monty/crates/monty/test_cases/type_error__str_iadd_int.py +0 -3
  909. package/ref-monty/crates/monty/test_cases/type_error__unary_invert_str.py +0 -3
  910. package/ref-monty/crates/monty/test_cases/type_error__unary_minus_str.py +0 -4
  911. package/ref-monty/crates/monty/test_cases/type_error__unary_neg_str.py +0 -3
  912. package/ref-monty/crates/monty/test_cases/type_error__unary_plus_str.py +0 -4
  913. package/ref-monty/crates/monty/test_cases/typing__types.py +0 -24
  914. package/ref-monty/crates/monty/test_cases/unpack__nested.py +0 -48
  915. package/ref-monty/crates/monty/test_cases/unpack__non_sequence.py +0 -9
  916. package/ref-monty/crates/monty/test_cases/unpack__not_enough.py +0 -9
  917. package/ref-monty/crates/monty/test_cases/unpack__ops.py +0 -153
  918. package/ref-monty/crates/monty/test_cases/unpack__star_not_enough.py +0 -9
  919. package/ref-monty/crates/monty/test_cases/unpack__too_many.py +0 -9
  920. package/ref-monty/crates/monty/test_cases/version__cpython.py +0 -4
  921. package/ref-monty/crates/monty/test_cases/walrus__all.py +0 -178
  922. package/ref-monty/crates/monty/test_cases/while__all.py +0 -206
  923. package/ref-monty/crates/monty/tests/asyncio.rs +0 -764
  924. package/ref-monty/crates/monty/tests/binary_serde.rs +0 -185
  925. package/ref-monty/crates/monty/tests/bytecode_limits.rs +0 -248
  926. package/ref-monty/crates/monty/tests/datatest_runner.rs +0 -2029
  927. package/ref-monty/crates/monty/tests/inputs.rs +0 -420
  928. package/ref-monty/crates/monty/tests/json_serde.rs +0 -250
  929. package/ref-monty/crates/monty/tests/main.rs +0 -71
  930. package/ref-monty/crates/monty/tests/math_module.rs +0 -114
  931. package/ref-monty/crates/monty/tests/name_lookup.rs +0 -482
  932. package/ref-monty/crates/monty/tests/os_tests.rs +0 -459
  933. package/ref-monty/crates/monty/tests/parse_errors.rs +0 -441
  934. package/ref-monty/crates/monty/tests/print_writer.rs +0 -238
  935. package/ref-monty/crates/monty/tests/py_object.rs +0 -121
  936. package/ref-monty/crates/monty/tests/regex.rs +0 -90
  937. package/ref-monty/crates/monty/tests/repl.rs +0 -344
  938. package/ref-monty/crates/monty/tests/resource_limits.rs +0 -1826
  939. package/ref-monty/crates/monty/tests/try_from.rs +0 -167
  940. package/ref-monty/crates/monty-cli/Cargo.toml +0 -25
  941. package/ref-monty/crates/monty-cli/src/main.rs +0 -541
  942. package/ref-monty/crates/monty-js/.cargo/config.toml +0 -2
  943. package/ref-monty/crates/monty-js/.prettierignore +0 -8
  944. package/ref-monty/crates/monty-js/Cargo.toml +0 -32
  945. package/ref-monty/crates/monty-js/README.md +0 -207
  946. package/ref-monty/crates/monty-js/__test__/async.spec.ts +0 -350
  947. package/ref-monty/crates/monty-js/__test__/basic.spec.ts +0 -114
  948. package/ref-monty/crates/monty-js/__test__/exceptions.spec.ts +0 -427
  949. package/ref-monty/crates/monty-js/__test__/external.spec.ts +0 -354
  950. package/ref-monty/crates/monty-js/__test__/inputs.spec.ts +0 -143
  951. package/ref-monty/crates/monty-js/__test__/limits.spec.ts +0 -162
  952. package/ref-monty/crates/monty-js/__test__/package.json +0 -3
  953. package/ref-monty/crates/monty-js/__test__/print.spec.ts +0 -229
  954. package/ref-monty/crates/monty-js/__test__/repl.spec.ts +0 -34
  955. package/ref-monty/crates/monty-js/__test__/serialize.spec.ts +0 -205
  956. package/ref-monty/crates/monty-js/__test__/start.spec.ts +0 -443
  957. package/ref-monty/crates/monty-js/__test__/type_check.spec.ts +0 -147
  958. package/ref-monty/crates/monty-js/__test__/types.spec.ts +0 -319
  959. package/ref-monty/crates/monty-js/build.rs +0 -61
  960. package/ref-monty/crates/monty-js/index-header.d.ts +0 -3
  961. package/ref-monty/crates/monty-js/package-lock.json +0 -4694
  962. package/ref-monty/crates/monty-js/package.json +0 -100
  963. package/ref-monty/crates/monty-js/scripts/smoke-test.sh +0 -69
  964. package/ref-monty/crates/monty-js/smoke-test/package.json +0 -17
  965. package/ref-monty/crates/monty-js/smoke-test/test.ts +0 -171
  966. package/ref-monty/crates/monty-js/smoke-test/tsconfig.json +0 -11
  967. package/ref-monty/crates/monty-js/src/convert.rs +0 -648
  968. package/ref-monty/crates/monty-js/src/exceptions.rs +0 -293
  969. package/ref-monty/crates/monty-js/src/lib.rs +0 -41
  970. package/ref-monty/crates/monty-js/src/limits.rs +0 -53
  971. package/ref-monty/crates/monty-js/src/monty_cls.rs +0 -1407
  972. package/ref-monty/crates/monty-js/tsconfig.json +0 -17
  973. package/ref-monty/crates/monty-js/wrapper.ts +0 -701
  974. package/ref-monty/crates/monty-python/Cargo.toml +0 -38
  975. package/ref-monty/crates/monty-python/README.md +0 -134
  976. package/ref-monty/crates/monty-python/build.rs +0 -4
  977. package/ref-monty/crates/monty-python/example.py +0 -40
  978. package/ref-monty/crates/monty-python/exercise.py +0 -46
  979. package/ref-monty/crates/monty-python/pyproject.toml +0 -57
  980. package/ref-monty/crates/monty-python/python/pydantic_monty/__init__.py +0 -281
  981. package/ref-monty/crates/monty-python/python/pydantic_monty/_monty.pyi +0 -677
  982. package/ref-monty/crates/monty-python/python/pydantic_monty/os_access.py +0 -933
  983. package/ref-monty/crates/monty-python/python/pydantic_monty/py.typed +0 -0
  984. package/ref-monty/crates/monty-python/src/convert.rs +0 -273
  985. package/ref-monty/crates/monty-python/src/dataclass.rs +0 -461
  986. package/ref-monty/crates/monty-python/src/exceptions.rs +0 -557
  987. package/ref-monty/crates/monty-python/src/external.rs +0 -165
  988. package/ref-monty/crates/monty-python/src/lib.rs +0 -77
  989. package/ref-monty/crates/monty-python/src/limits.rs +0 -142
  990. package/ref-monty/crates/monty-python/src/monty_cls.rs +0 -1650
  991. package/ref-monty/crates/monty-python/src/repl.rs +0 -470
  992. package/ref-monty/crates/monty-python/src/serialization.rs +0 -761
  993. package/ref-monty/crates/monty-python/tests/test_async.py +0 -1201
  994. package/ref-monty/crates/monty-python/tests/test_basic.py +0 -66
  995. package/ref-monty/crates/monty-python/tests/test_dataclasses.py +0 -971
  996. package/ref-monty/crates/monty-python/tests/test_exceptions.py +0 -361
  997. package/ref-monty/crates/monty-python/tests/test_external.py +0 -367
  998. package/ref-monty/crates/monty-python/tests/test_inputs.py +0 -126
  999. package/ref-monty/crates/monty-python/tests/test_limits.py +0 -257
  1000. package/ref-monty/crates/monty-python/tests/test_os_access.py +0 -1286
  1001. package/ref-monty/crates/monty-python/tests/test_os_access_compat.py +0 -731
  1002. package/ref-monty/crates/monty-python/tests/test_os_access_raw.py +0 -483
  1003. package/ref-monty/crates/monty-python/tests/test_os_calls.py +0 -819
  1004. package/ref-monty/crates/monty-python/tests/test_print.py +0 -208
  1005. package/ref-monty/crates/monty-python/tests/test_re.py +0 -170
  1006. package/ref-monty/crates/monty-python/tests/test_readme_examples.py +0 -20
  1007. package/ref-monty/crates/monty-python/tests/test_repl.py +0 -749
  1008. package/ref-monty/crates/monty-python/tests/test_serialize.py +0 -284
  1009. package/ref-monty/crates/monty-python/tests/test_start.py +0 -346
  1010. package/ref-monty/crates/monty-python/tests/test_threading.py +0 -163
  1011. package/ref-monty/crates/monty-python/tests/test_type_check.py +0 -344
  1012. package/ref-monty/crates/monty-python/tests/test_types.py +0 -553
  1013. package/ref-monty/crates/monty-type-checking/Cargo.toml +0 -32
  1014. package/ref-monty/crates/monty-type-checking/src/db.rs +0 -116
  1015. package/ref-monty/crates/monty-type-checking/src/lib.rs +0 -4
  1016. package/ref-monty/crates/monty-type-checking/src/type_check.rs +0 -280
  1017. package/ref-monty/crates/monty-type-checking/tests/bad_types.py +0 -109
  1018. package/ref-monty/crates/monty-type-checking/tests/bad_types_output.txt +0 -21
  1019. package/ref-monty/crates/monty-type-checking/tests/good_types.py +0 -475
  1020. package/ref-monty/crates/monty-type-checking/tests/main.rs +0 -205
  1021. package/ref-monty/crates/monty-type-checking/tests/reveal_types.py +0 -56
  1022. package/ref-monty/crates/monty-type-checking/tests/reveal_types_output.txt +0 -41
  1023. package/ref-monty/crates/monty-typeshed/Cargo.toml +0 -29
  1024. package/ref-monty/crates/monty-typeshed/README.md +0 -11
  1025. package/ref-monty/crates/monty-typeshed/build.rs +0 -101
  1026. package/ref-monty/crates/monty-typeshed/custom/README.md +0 -1
  1027. package/ref-monty/crates/monty-typeshed/custom/asyncio.pyi +0 -138
  1028. package/ref-monty/crates/monty-typeshed/custom/os.pyi +0 -87
  1029. package/ref-monty/crates/monty-typeshed/custom/sys.pyi +0 -33
  1030. package/ref-monty/crates/monty-typeshed/src/lib.rs +0 -56
  1031. package/ref-monty/crates/monty-typeshed/update.py +0 -321
  1032. package/ref-monty/crates/monty-typeshed/vendor/typeshed/source_commit.txt +0 -1
  1033. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/VERSIONS +0 -20
  1034. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/_collections_abc.pyi +0 -105
  1035. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/_typeshed/__init__.pyi +0 -394
  1036. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/asyncio.pyi +0 -138
  1037. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/builtins.pyi +0 -1434
  1038. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/collections/__init__.pyi +0 -527
  1039. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/collections/abc.pyi +0 -2
  1040. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/dataclasses.pyi +0 -502
  1041. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/enum.pyi +0 -376
  1042. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/math.pyi +0 -149
  1043. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/os.pyi +0 -87
  1044. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/pathlib/__init__.pyi +0 -395
  1045. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/pathlib/types.pyi +0 -8
  1046. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/re.pyi +0 -337
  1047. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/sys.pyi +0 -33
  1048. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/types.pyi +0 -741
  1049. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/typing.pyi +0 -1217
  1050. package/ref-monty/crates/monty-typeshed/vendor/typeshed/stdlib/typing_extensions.pyi +0 -716
  1051. package/ref-monty/docs/usage-guide.md +0 -117
  1052. package/ref-monty/examples/README.md +0 -3
  1053. package/ref-monty/examples/expense_analysis/README.md +0 -3
  1054. package/ref-monty/examples/expense_analysis/data.py +0 -124
  1055. package/ref-monty/examples/expense_analysis/main.py +0 -115
  1056. package/ref-monty/examples/sql_playground/README.md +0 -20
  1057. package/ref-monty/examples/sql_playground/external_functions.py +0 -129
  1058. package/ref-monty/examples/sql_playground/main.py +0 -81
  1059. package/ref-monty/examples/sql_playground/sandbox_code.py +0 -82
  1060. package/ref-monty/examples/sql_playground/type_stubs.pyi +0 -14
  1061. package/ref-monty/examples/web_scraper/README.md +0 -15
  1062. package/ref-monty/examples/web_scraper/browser.py +0 -56
  1063. package/ref-monty/examples/web_scraper/example_code.py +0 -59
  1064. package/ref-monty/examples/web_scraper/external_functions.py +0 -324
  1065. package/ref-monty/examples/web_scraper/main.py +0 -193
  1066. package/ref-monty/examples/web_scraper/sub_agent.py +0 -79
  1067. package/ref-monty/monty-npm.md +0 -235
  1068. package/ref-monty/pyproject.toml +0 -162
  1069. package/ref-monty/scripts/check_imports.py +0 -91
  1070. package/ref-monty/scripts/codecov_diff.py +0 -412
  1071. package/ref-monty/scripts/complete_tests.py +0 -146
  1072. package/ref-monty/scripts/flamegraph_to_text.py +0 -208
  1073. package/ref-monty/scripts/iter_test_methods.py +0 -540
  1074. package/ref-monty/scripts/run_traceback.py +0 -180
  1075. package/ref-monty/scripts/startup_performance.py +0 -130
  1076. package/ref-monty/uv.lock +0 -1779
  1077. package/temp_resend_cli/repo/.github/scripts/pr-title-check.js +0 -34
  1078. package/temp_resend_cli/repo/.github/workflows/ci.yml +0 -67
  1079. package/temp_resend_cli/repo/.github/workflows/post-release.yml +0 -51
  1080. package/temp_resend_cli/repo/.github/workflows/pr-title-check.yml +0 -13
  1081. package/temp_resend_cli/repo/.github/workflows/release.yml +0 -175
  1082. package/temp_resend_cli/repo/.github/workflows/test-install-unix.yml +0 -34
  1083. package/temp_resend_cli/repo/.github/workflows/test-install-windows.yml +0 -48
  1084. package/temp_resend_cli/repo/CHANGELOG.md +0 -31
  1085. package/temp_resend_cli/repo/LICENSE +0 -21
  1086. package/temp_resend_cli/repo/README.md +0 -450
  1087. package/temp_resend_cli/repo/biome.json +0 -36
  1088. package/temp_resend_cli/repo/install.ps1 +0 -141
  1089. package/temp_resend_cli/repo/install.sh +0 -301
  1090. package/temp_resend_cli/repo/package.json +0 -61
  1091. package/temp_resend_cli/repo/pnpm-lock.yaml +0 -2439
  1092. package/temp_resend_cli/repo/renovate.json +0 -4
  1093. package/temp_resend_cli/repo/src/cli.ts +0 -98
  1094. package/temp_resend_cli/repo/src/commands/api-keys/create.ts +0 -114
  1095. package/temp_resend_cli/repo/src/commands/api-keys/delete.ts +0 -47
  1096. package/temp_resend_cli/repo/src/commands/api-keys/index.ts +0 -26
  1097. package/temp_resend_cli/repo/src/commands/api-keys/list.ts +0 -35
  1098. package/temp_resend_cli/repo/src/commands/api-keys/utils.ts +0 -8
  1099. package/temp_resend_cli/repo/src/commands/auth/index.ts +0 -20
  1100. package/temp_resend_cli/repo/src/commands/auth/login.ts +0 -234
  1101. package/temp_resend_cli/repo/src/commands/auth/logout.ts +0 -105
  1102. package/temp_resend_cli/repo/src/commands/broadcasts/create.ts +0 -196
  1103. package/temp_resend_cli/repo/src/commands/broadcasts/delete.ts +0 -46
  1104. package/temp_resend_cli/repo/src/commands/broadcasts/get.ts +0 -59
  1105. package/temp_resend_cli/repo/src/commands/broadcasts/index.ts +0 -43
  1106. package/temp_resend_cli/repo/src/commands/broadcasts/list.ts +0 -60
  1107. package/temp_resend_cli/repo/src/commands/broadcasts/send.ts +0 -56
  1108. package/temp_resend_cli/repo/src/commands/broadcasts/update.ts +0 -95
  1109. package/temp_resend_cli/repo/src/commands/broadcasts/utils.ts +0 -35
  1110. package/temp_resend_cli/repo/src/commands/contact-properties/create.ts +0 -118
  1111. package/temp_resend_cli/repo/src/commands/contact-properties/delete.ts +0 -48
  1112. package/temp_resend_cli/repo/src/commands/contact-properties/get.ts +0 -46
  1113. package/temp_resend_cli/repo/src/commands/contact-properties/index.ts +0 -48
  1114. package/temp_resend_cli/repo/src/commands/contact-properties/list.ts +0 -68
  1115. package/temp_resend_cli/repo/src/commands/contact-properties/update.ts +0 -88
  1116. package/temp_resend_cli/repo/src/commands/contact-properties/utils.ts +0 -17
  1117. package/temp_resend_cli/repo/src/commands/contacts/add-segment.ts +0 -78
  1118. package/temp_resend_cli/repo/src/commands/contacts/create.ts +0 -122
  1119. package/temp_resend_cli/repo/src/commands/contacts/delete.ts +0 -49
  1120. package/temp_resend_cli/repo/src/commands/contacts/get.ts +0 -53
  1121. package/temp_resend_cli/repo/src/commands/contacts/index.ts +0 -58
  1122. package/temp_resend_cli/repo/src/commands/contacts/list.ts +0 -57
  1123. package/temp_resend_cli/repo/src/commands/contacts/remove-segment.ts +0 -48
  1124. package/temp_resend_cli/repo/src/commands/contacts/segments.ts +0 -39
  1125. package/temp_resend_cli/repo/src/commands/contacts/topics.ts +0 -45
  1126. package/temp_resend_cli/repo/src/commands/contacts/update-topics.ts +0 -90
  1127. package/temp_resend_cli/repo/src/commands/contacts/update.ts +0 -77
  1128. package/temp_resend_cli/repo/src/commands/contacts/utils.ts +0 -119
  1129. package/temp_resend_cli/repo/src/commands/doctor.ts +0 -216
  1130. package/temp_resend_cli/repo/src/commands/domains/create.ts +0 -83
  1131. package/temp_resend_cli/repo/src/commands/domains/delete.ts +0 -42
  1132. package/temp_resend_cli/repo/src/commands/domains/get.ts +0 -47
  1133. package/temp_resend_cli/repo/src/commands/domains/index.ts +0 -35
  1134. package/temp_resend_cli/repo/src/commands/domains/list.ts +0 -53
  1135. package/temp_resend_cli/repo/src/commands/domains/update.ts +0 -75
  1136. package/temp_resend_cli/repo/src/commands/domains/utils.ts +0 -44
  1137. package/temp_resend_cli/repo/src/commands/domains/verify.ts +0 -38
  1138. package/temp_resend_cli/repo/src/commands/emails/batch.ts +0 -140
  1139. package/temp_resend_cli/repo/src/commands/emails/get.ts +0 -44
  1140. package/temp_resend_cli/repo/src/commands/emails/index.ts +0 -30
  1141. package/temp_resend_cli/repo/src/commands/emails/list.ts +0 -84
  1142. package/temp_resend_cli/repo/src/commands/emails/receiving/attachment.ts +0 -55
  1143. package/temp_resend_cli/repo/src/commands/emails/receiving/attachments.ts +0 -68
  1144. package/temp_resend_cli/repo/src/commands/emails/receiving/get.ts +0 -58
  1145. package/temp_resend_cli/repo/src/commands/emails/receiving/index.ts +0 -28
  1146. package/temp_resend_cli/repo/src/commands/emails/receiving/list.ts +0 -59
  1147. package/temp_resend_cli/repo/src/commands/emails/receiving/utils.ts +0 -38
  1148. package/temp_resend_cli/repo/src/commands/emails/send.ts +0 -189
  1149. package/temp_resend_cli/repo/src/commands/open.ts +0 -27
  1150. package/temp_resend_cli/repo/src/commands/segments/create.ts +0 -50
  1151. package/temp_resend_cli/repo/src/commands/segments/delete.ts +0 -47
  1152. package/temp_resend_cli/repo/src/commands/segments/get.ts +0 -38
  1153. package/temp_resend_cli/repo/src/commands/segments/index.ts +0 -36
  1154. package/temp_resend_cli/repo/src/commands/segments/list.ts +0 -58
  1155. package/temp_resend_cli/repo/src/commands/segments/utils.ts +0 -7
  1156. package/temp_resend_cli/repo/src/commands/teams/index.ts +0 -10
  1157. package/temp_resend_cli/repo/src/commands/teams/list.ts +0 -35
  1158. package/temp_resend_cli/repo/src/commands/teams/remove.ts +0 -86
  1159. package/temp_resend_cli/repo/src/commands/teams/switch.ts +0 -76
  1160. package/temp_resend_cli/repo/src/commands/topics/create.ts +0 -73
  1161. package/temp_resend_cli/repo/src/commands/topics/delete.ts +0 -47
  1162. package/temp_resend_cli/repo/src/commands/topics/get.ts +0 -42
  1163. package/temp_resend_cli/repo/src/commands/topics/index.ts +0 -42
  1164. package/temp_resend_cli/repo/src/commands/topics/list.ts +0 -34
  1165. package/temp_resend_cli/repo/src/commands/topics/update.ts +0 -59
  1166. package/temp_resend_cli/repo/src/commands/topics/utils.ts +0 -16
  1167. package/temp_resend_cli/repo/src/commands/webhooks/create.ts +0 -128
  1168. package/temp_resend_cli/repo/src/commands/webhooks/delete.ts +0 -49
  1169. package/temp_resend_cli/repo/src/commands/webhooks/get.ts +0 -42
  1170. package/temp_resend_cli/repo/src/commands/webhooks/index.ts +0 -42
  1171. package/temp_resend_cli/repo/src/commands/webhooks/list.ts +0 -55
  1172. package/temp_resend_cli/repo/src/commands/webhooks/listen.ts +0 -379
  1173. package/temp_resend_cli/repo/src/commands/webhooks/update.ts +0 -83
  1174. package/temp_resend_cli/repo/src/commands/webhooks/utils.ts +0 -36
  1175. package/temp_resend_cli/repo/src/commands/whoami.ts +0 -71
  1176. package/temp_resend_cli/repo/src/lib/actions.ts +0 -157
  1177. package/temp_resend_cli/repo/src/lib/client.ts +0 -37
  1178. package/temp_resend_cli/repo/src/lib/config.ts +0 -217
  1179. package/temp_resend_cli/repo/src/lib/files.ts +0 -15
  1180. package/temp_resend_cli/repo/src/lib/help-text.ts +0 -38
  1181. package/temp_resend_cli/repo/src/lib/output.ts +0 -56
  1182. package/temp_resend_cli/repo/src/lib/pagination.ts +0 -36
  1183. package/temp_resend_cli/repo/src/lib/prompts.ts +0 -149
  1184. package/temp_resend_cli/repo/src/lib/spinner.ts +0 -100
  1185. package/temp_resend_cli/repo/src/lib/table.ts +0 -57
  1186. package/temp_resend_cli/repo/src/lib/tty.ts +0 -28
  1187. package/temp_resend_cli/repo/src/lib/update-check.ts +0 -169
  1188. package/temp_resend_cli/repo/src/lib/version.ts +0 -4
  1189. package/temp_resend_cli/repo/tests/commands/api-keys/create.test.ts +0 -196
  1190. package/temp_resend_cli/repo/tests/commands/api-keys/delete.test.ts +0 -157
  1191. package/temp_resend_cli/repo/tests/commands/api-keys/list.test.ts +0 -134
  1192. package/temp_resend_cli/repo/tests/commands/auth/login.test.ts +0 -153
  1193. package/temp_resend_cli/repo/tests/commands/auth/logout.test.ts +0 -153
  1194. package/temp_resend_cli/repo/tests/commands/broadcasts/create.test.ts +0 -454
  1195. package/temp_resend_cli/repo/tests/commands/broadcasts/delete.test.ts +0 -183
  1196. package/temp_resend_cli/repo/tests/commands/broadcasts/get.test.ts +0 -147
  1197. package/temp_resend_cli/repo/tests/commands/broadcasts/list.test.ts +0 -199
  1198. package/temp_resend_cli/repo/tests/commands/broadcasts/send.test.ts +0 -162
  1199. package/temp_resend_cli/repo/tests/commands/broadcasts/update.test.ts +0 -288
  1200. package/temp_resend_cli/repo/tests/commands/contact-properties/create.test.ts +0 -251
  1201. package/temp_resend_cli/repo/tests/commands/contact-properties/delete.test.ts +0 -184
  1202. package/temp_resend_cli/repo/tests/commands/contact-properties/get.test.ts +0 -145
  1203. package/temp_resend_cli/repo/tests/commands/contact-properties/list.test.ts +0 -181
  1204. package/temp_resend_cli/repo/tests/commands/contact-properties/update.test.ts +0 -217
  1205. package/temp_resend_cli/repo/tests/commands/contacts/add-segment.test.ts +0 -189
  1206. package/temp_resend_cli/repo/tests/commands/contacts/create.test.ts +0 -271
  1207. package/temp_resend_cli/repo/tests/commands/contacts/delete.test.ts +0 -193
  1208. package/temp_resend_cli/repo/tests/commands/contacts/get.test.ts +0 -149
  1209. package/temp_resend_cli/repo/tests/commands/contacts/list.test.ts +0 -176
  1210. package/temp_resend_cli/repo/tests/commands/contacts/remove-segment.test.ts +0 -167
  1211. package/temp_resend_cli/repo/tests/commands/contacts/segments.test.ts +0 -168
  1212. package/temp_resend_cli/repo/tests/commands/contacts/topics.test.ts +0 -164
  1213. package/temp_resend_cli/repo/tests/commands/contacts/update-topics.test.ts +0 -248
  1214. package/temp_resend_cli/repo/tests/commands/contacts/update.test.ts +0 -206
  1215. package/temp_resend_cli/repo/tests/commands/doctor.test.ts +0 -164
  1216. package/temp_resend_cli/repo/tests/commands/domains/create.test.ts +0 -193
  1217. package/temp_resend_cli/repo/tests/commands/domains/delete.test.ts +0 -157
  1218. package/temp_resend_cli/repo/tests/commands/domains/get.test.ts +0 -138
  1219. package/temp_resend_cli/repo/tests/commands/domains/list.test.ts +0 -165
  1220. package/temp_resend_cli/repo/tests/commands/domains/update.test.ts +0 -224
  1221. package/temp_resend_cli/repo/tests/commands/domains/verify.test.ts +0 -118
  1222. package/temp_resend_cli/repo/tests/commands/emails/batch.test.ts +0 -324
  1223. package/temp_resend_cli/repo/tests/commands/emails/get.test.ts +0 -132
  1224. package/temp_resend_cli/repo/tests/commands/emails/receiving/attachment.test.ts +0 -141
  1225. package/temp_resend_cli/repo/tests/commands/emails/receiving/attachments.test.ts +0 -169
  1226. package/temp_resend_cli/repo/tests/commands/emails/receiving/get.test.ts +0 -141
  1227. package/temp_resend_cli/repo/tests/commands/emails/receiving/list.test.ts +0 -182
  1228. package/temp_resend_cli/repo/tests/commands/emails/send.test.ts +0 -312
  1229. package/temp_resend_cli/repo/tests/commands/segments/create.test.ts +0 -164
  1230. package/temp_resend_cli/repo/tests/commands/segments/delete.test.ts +0 -183
  1231. package/temp_resend_cli/repo/tests/commands/segments/get.test.ts +0 -138
  1232. package/temp_resend_cli/repo/tests/commands/segments/list.test.ts +0 -174
  1233. package/temp_resend_cli/repo/tests/commands/teams/list.test.ts +0 -62
  1234. package/temp_resend_cli/repo/tests/commands/teams/remove.test.ts +0 -110
  1235. package/temp_resend_cli/repo/tests/commands/teams/switch.test.ts +0 -103
  1236. package/temp_resend_cli/repo/tests/commands/topics/create.test.ts +0 -192
  1237. package/temp_resend_cli/repo/tests/commands/topics/delete.test.ts +0 -157
  1238. package/temp_resend_cli/repo/tests/commands/topics/get.test.ts +0 -126
  1239. package/temp_resend_cli/repo/tests/commands/topics/list.test.ts +0 -125
  1240. package/temp_resend_cli/repo/tests/commands/topics/update.test.ts +0 -178
  1241. package/temp_resend_cli/repo/tests/commands/webhooks/create.test.ts +0 -225
  1242. package/temp_resend_cli/repo/tests/commands/webhooks/delete.test.ts +0 -157
  1243. package/temp_resend_cli/repo/tests/commands/webhooks/get.test.ts +0 -126
  1244. package/temp_resend_cli/repo/tests/commands/webhooks/list.test.ts +0 -178
  1245. package/temp_resend_cli/repo/tests/commands/webhooks/update.test.ts +0 -207
  1246. package/temp_resend_cli/repo/tests/commands/whoami.test.ts +0 -98
  1247. package/temp_resend_cli/repo/tests/e2e/smoke.test.ts +0 -93
  1248. package/temp_resend_cli/repo/tests/helpers.ts +0 -86
  1249. package/temp_resend_cli/repo/tests/lib/client.test.ts +0 -71
  1250. package/temp_resend_cli/repo/tests/lib/config.test.ts +0 -451
  1251. package/temp_resend_cli/repo/tests/lib/files.test.ts +0 -73
  1252. package/temp_resend_cli/repo/tests/lib/help-text.test.ts +0 -97
  1253. package/temp_resend_cli/repo/tests/lib/output.test.ts +0 -136
  1254. package/temp_resend_cli/repo/tests/lib/prompts.test.ts +0 -185
  1255. package/temp_resend_cli/repo/tests/lib/spinner.test.ts +0 -166
  1256. package/temp_resend_cli/repo/tests/lib/table.test.ts +0 -63
  1257. package/temp_resend_cli/repo/tests/lib/tty.test.ts +0 -89
  1258. package/temp_resend_cli/repo/tests/lib/update-check.test.ts +0 -179
  1259. package/temp_resend_cli/repo/tsconfig.json +0 -14
  1260. package/temp_resend_cli/repo/vitest.config.e2e.ts +0 -8
  1261. package/temp_resend_cli/repo/vitest.config.ts +0 -10
  1262. /package/docs/{plugin-examples.md → plugins-examples.md} +0 -0
@@ -1,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
- }