# Fork 了 PythonMonkey (November 24, 2024)

<img src="/nlark/yuque/0/2024/png/26070246/1732452458406-daefb64f-d071-4c03-a73f-4aed0342b917.png" width="911.3333333333334" title="" crop="0,0,1,1" id="u34590d67" class="ne-image">

PythonMonkey 一个多月没动了。3.13 适配遥遥无期。

另外，之前跟他们聊的去除在 post install 阶段 npm install 的事情，我也终于忍不了了

<img src="/nlark/yuque/0/2024/png/26070246/1732452637924-cba21ddf-0d21-4cab-b851-9445565e35ab.png" width="1169.3333333333333" title="" crop="0,0,1,1" id="ube4a19db" class="ne-image">

于是狠下心来 fork 了 PythonMonkey。但是我在 CodeSpaces 里发现 build 很久而且好像会失败，CI 也运行不起来（似乎他们还有一些环境变量要配置）

### 实现
于是就只好施展魔法了。以前都不敢想这种思路。首先看看原本的 pythonmonkey 是怎么安装的：

1. pythonmonkey 包是 spidermonkey 的分支的 build 产物，加上一些 python 胶水和类型定义，它提供了全面的 wheel distribution
2. 但是 pythonmonkey 要用到一些（应该主要目的是 polyfill 的）JavaScript 库，所以他们搞了一个 pminit 包，只提供 sdist，在 builld 的时候往 pythonmonkey 包的文件夹里运行 npm install

我的第一个目标就是，去掉这个 npm install 的过程，因为：

1. 很慢，尤其是在国内，我如果不开全局代理或者用镜像源就会失败
2. 对 nodejs 有依赖。这很可笑。凭什么我安装一个 JavaScript 运行时还需要另一个 JavaScript 运行时

看了看 [pminit 的代码](https://github.com/Distributive-Network/PythonMonkey/blob/main/python/pminit/pminit/cli.py)，发现它真的就只是执行 npm install。我决定可以直接把 node_modules 在 CI 中确定好，并单独用一个包分发。

这个不难，虽然在一些细节的抉择上花了不少时间，但总之是很简单的事。

但是由于我没法构建 pythonmonkey 啊，所以我没法去掉 pminit 的 requirements，更没法支持 3.13 了。这不是白费工夫嘛。于是我就咬咬牙，决定用 monkey patch 已有的 wheel 文件，来替换掉依赖

---

最后通过将近 200 行的代码，不太优雅地实现了：[patch.py](https://github.com/CNSeniorious000/PythonMonkey/blob/main/patch.py)

<img src="https://opengraph.githubassets.com/5509e1d2f5cf2aa3d8764409517cb24ca9d1180ca8b2ea094f4e8eba7e067938/CNSeniorious000/PythonMonkey" width="1200" title="null" crop="0,0,1,1" id="qCSU8" class="ne-image">

还遇到了一些坑，比如：

+ 带加号的 version 是不能上传到 PyPI 的，怪不得 torch 啊什么的得有自己的 index
+ http1.1 有时比 http2 快，而且 http2 比 http3 也快。我怀疑是因为都是下载不多个大文件。但是其实这个结果也蛮反常的，我不太清楚为什么
+ Python 的 ZipFile 可以以 append 模式打开 zip，但是只能 append，不能 update，另外 TarFile 二者都不能
+ Windows 下的 `tar` 命令和 Linux 上的还蛮兼容的，但是 `.tar.gz` 文件都不能 append 或 update
+ 很奇怪的是，我用 `zip` 命令打的 zip 包比原本的 whl 文件大。不过没研究了，可能是带了一些元数据吧

---

### 结果
+ 发布了 [pythonmonkey_node_modules](https://pypi.org/project/pythonmonkey_node_modules/)，只有 2 MB 左右
+ 发布了 [pythonmonkey-fork](https://pypi.org/project/pythonmonkey-fork/)，甚至支持了 3.13（通过 patch pythonmonkey.io 上的 nightly release）
+ 一套 CI，可以很方便地 patch 新版本，或者更新 JavaScript 依赖

接下来准备把各种 JavaScript 库引入 python 了！

首当其冲的是把 readability 加到 m 里，甚至可以联系上翻译或者是 ask 的内容。也可以复用一部分 [llm-web-reader-demo](https://github.com/CNSeniorious000/llm-web-reader-demo) 的东西。

<img src="https://opengraph.githubassets.com/5cb8fd41bd2852c811e2178d7057e72f3f7afc11a73ac652a320e596ec08fd74/CNSeniorious000/llm-web-reader-demo" width="1200" title="null" crop="0,0,1,1" id="r8uac" class="ne-image">

另外，最近也一直在尝试各种 JavaScript 库能不能移植过来。以下是一些点子：

+ 在 python 中用 unocss 来渲染邮件
+ 在 python 中用 shiki 来高亮代码，用于渲染邮件 / 渲染 OG 图，或者给 mkdocs 做插件，支持 pygments 不支持的语言（比如 Svelte）
+ 用 remark 做 markdown AST 解析，比如用在 [pyth-on-line](https://github.com/promplate/pyth-on-line) 中，实现 js 和 py 侧一样的 markdown AST 解析
+ 用 [showdown](https://github.com/promplate/pyth-on-line) 或者 [turndown](https://github.com/mixmark-io/turndown) 做 html 转 markdown，加上 python 系的 markdownify 和 html2text 搞个同台竞技（类似 [markdownify-demo](https://markdownify-demo.vercel.app/) 这样）（甚至可以和 [llm-web-reader-demo](https://github.com/CNSeniorious000/llm-web-reader-demo) 也比一比）

---

说起来，刚刚打**一起**差点打成了**仪器**。不过应该没有人知道这个梗，等[这个项目](https://comments-generation-mock-ui.vercel.app/slides/charts/pie)做成了再说吧。

---

<img src="/nlark/yuque/0/2024/png/26070246/1732454650678-fa788f86-2e56-4934-ba82-3b36f7a26453.png" width="1107.3333333333333" title="" crop="0,0,1,1" id="uc48dd6dc" class="ne-image">

有点好笑，昨天调试这个 patch 的时候可能下载了很多次，给他们刷出了 4K 的下载量

<img src="/nlark/yuque/0/2024/png/26070246/1732454764191-90c9ae73-4738-42c9-b148-fc79daf55d62.png" width="936.6666666666666" title="" crop="0,0,1,1" id="u7e35da09" class="ne-image">

在测 HTTP/2 啊 HTTP/3 那些的时候也给 vercel 这儿的服务刷了十几 GB 的流量账单（之前的都是百 MB 级别的）

<img src="/nlark/yuque/0/2024/png/26070246/1732454874277-c2ab25c4-39c7-41ec-8f72-582eb109b4cb.png" width="1197.3333333333333" title="" crop="0,0,1,1" id="uc5ea1ab7" class="ne-image">

Netlify 这儿的服务刷了差不多等量的……