Fork 了 PythonMonkey


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

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

于是狠下心来 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 的代码,发现它真的就只是执行 npm install。我决定可以直接把 node_modules 在 CI 中确定好,并单独用一个包分发。

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

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


最后通过将近 200 行的代码,不太优雅地实现了:patch.py

还遇到了一些坑,比如:

  • 带加号的 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,只有 2 MB 左右
  • 发布了 pythonmonkey-fork,甚至支持了 3.13(通过 patch pythonmonkey.io 上的 nightly release)
  • 一套 CI,可以很方便地 patch 新版本,或者更新 JavaScript 依赖

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

首当其冲的是把 readability 加到 m 里,甚至可以联系上翻译或者是 ask 的内容。也可以复用一部分 llm-web-reader-demo 的东西。

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

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

说起来,刚刚打一起差点打成了仪器。不过应该没有人知道这个梗,等这个项目做成了再说吧。


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

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

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