Pyodide 314.0:Python 包现在可以将 WebAssembly wheels 发布到 PyPI
摘要
Pyodide 314.0 版本标志着 PEP 783 的接受,这是一个里程碑,使得 Python 包能够直接将 WebAssembly wheels 发布到 PyPI,从而减轻了维护者的负担,并简化了 Python 在浏览器生态系统中的分发。
暂无内容
查看缓存全文
缓存时间: 2026/06/13 23:15
# Pyodide 314.0 发布
来源:https://blog.pyodide.org/posts/314-release/
我们很高兴地宣布 Pyodide 314.0 版本发布。
本次发布聚焦于标准化和打包,标志着浏览器中运行 Python 的生态系统迎来了一个重要里程碑。
## PEP 783 已接受:这意味着什么?
PEP 783:Emscripten 打包(https://peps.python.org/pep-0783/)的接受,或许标志着浏览器中运行 Python 生态系统历史上最激动人心的变化。Pyodide 的维护者们——尤其是 @hoodmane(https://github.com/hoodmane)——为此付出了巨大的努力,历时许久。实现这一长期目标将成倍地扩展我们的生态系统。
这在实践中意味着什么?你现在可以将为 Pyodide(或任何与 PEP 783 中定义的 PyEmscripten 平台(https://pyodide.org/en/stable/development/abi.html)兼容的 Python 运行时)构建的 Python 包直接发布到 PyPI,并在运行时安装。
此前,Pyodide 维护者需要自行维护、构建和托管超过 300 个包。这给我们的维护者带来了巨大负担,并成为社区的主要瓶颈,因为每个新包都需要人工审查。
展望未来,包维护者可以像为 Linux、macOS 或 Windows 构建原生 wheel 一样,简单地构建并将 Pyodide wheel 发布到 PyPI。在你阅读本文时,cibuildwheel v4.0(https://iscinumpy.dev/post/cibuildwheel-4-0-0/)已经支持为 PyEmscripten 2025 和 2026 ABI 进行构建。2026 ABI 目前仅适用于我们的预发布版本,因此需要通过 `pyodide-prerelease` 选项启用,但我们很快会更新 cibuildwheel,并在 v4.1.0 版本中提供稳定的 314.0 支持。
我们编写了一份关于构建和发布 Pyodide wheel 到 PyPI 的详细指南。你可以在 `pyodide-build` 文档(https://pyodide-build.readthedocs.io/en/latest/)中找到它。
如果你是使用 PyO3 或 maturin 的 Python 包维护者,还有一篇由 Pydantic 团队的 Victorien Plot(https://github.com/Viicos)撰写的优秀文章,解释了如何构建和发布 PyEmscripten wheel(https://pydantic.dev/articles/emscripten-wheels-pydantic)。
随着 PEP 783 现已正式接受,平台标签现在使用 `pyemscripten_*` 前缀:Python 3.13(Pyodide 0.29.x)对应 `pyemscripten_2025_0`,Python 3.14(Pyodide 314.x)对应 `pyemscripten_2026_0`。如果你为这些版本中的任何一个构建 wheel,请相应更新你的构建设置和 `pyodide-build` 版本。
## 新的版本号方案
你可能在想:上一个版本不是 0.29,现在怎么变成 314.0 了?
是的,我们正在更新 Pyodide 的版本号方案,以符合这些新的打包标准。
为了在 PEP 783 下完全标准化打包过程,我们希望稳定包的平台兼容性,使其不会因每个 Pyodide 版本而破坏。因此,我们正在过渡到基于 Python 版本的版本号方案。例如,Pyodide 314.x 直接对应 Python 3.14。
每当我们进行二进制不兼容的更改时,这些更改现在将严格与上游 Python 更新(通常每年一次)对齐。这意味着你可以在多个 Pyodide 版本中安全地使用为相同 Python 版本构建的现有包。我们计划每年发布一个新的 Pyodide 主版本,与 Python 更新同步。
这个新方案下的第一个版本搭载了 Python 3.14.2 和 Emscripten 5.0.3。
另请参阅:Pyodide 问题 #6084(https://github.com/pyodide/pyodide/issues/6084)以获取更多背景信息。
## 标准库变更
最初,Pyodide “去捆绑” 了几个 Python 标准库,包括 `ssl`、`sqlite3` 和 `lzma`。
这样做是为了减小 Pyodide 发行版的大小,从而实现更快的启动时间,同时允许用户在加载 Pyodide 后按需安装这些包。
例如,如果你的应用或包需要 `sqlite3`,你可以在加载 Pyodide 后安装它:
```javascript
await pyodide.loadPackage("sqlite3");
```
然而,随着 Pyodide 现在支持 PEP 783,我们决定将这些库恢复到标准库中,以提供更好的用户体验。这引入了一个权衡:虽然初始下载大小增加,但用户不再需要单独安装这些包,从而创造了更无缝的体验。
作为这次清理的一部分,`pydecimal` 和 `test` 包已从发行版中移除,并且 `loadPyodide()` 中的 `fullstdlib` 选项现已弃用且无效。
我们还决定从标准库中移除 `OpenSSL`,因为捆绑它会带来显著的体积增加。这导致了两个破坏性变更:
1. `ssl` 模块不再依赖 OpenSSL。我们实现了一个自定义的 SSL 实现,提供与标准库 `ssl` 模块兼容的基本功能,但没有实际的 SSL/TLS 支持。请注意,即使在此更改之前,大多数 `ssl` 模块的功能也无法工作,因为我们不支持浏览器中的 socket 操作。
2. `hashlib` 模块不再支持之前通过 OpenSSL 提供的一些加密哈希函数。
由于此版本搭载了 Python 3.14,新的 `compression.zstd` 模块现已内置在 Pyodide 中,提供了对 zstd 压缩和解压缩的原生支持。
## Pyodide 现为原生 ES 模块
`pyodide.asm.js` 已重命名为 `pyodide.asm.mjs`,以正确反映它是一个 ES 模块。大多数用户无需更改任何内容,因为 `loadPyodide()` 会在内部处理。但是,如果你直接引用该文件,请注意以下破坏性变更:
- **经典(非模块)Worker** 不再受支持。你必须改用模块 Worker(`type: "module"`)。
- **Service Worker** 如果静态导入 `pyodide.asm.js`,现在必须从 `pyodide.asm.mjs` 导入 `createPyodideModule`,并将结果作为参数传递给 `loadPyodide`:
```javascript
import createPyodideModule from "./pyodide.asm.mjs";
import { loadPyodide } from "./pyodide.mjs";
loadPyodide({ createPyodideModule }).then((pyodide) => {
// ...
});
```
- **打包工具**:更新任何显式引用 `pyodide.asm.js` 的配置,改为使用 `pyodide.asm.mjs`。
## Node.js 中 Socket 操作的实验性支持
我们为 Node.js 中的 socket 操作添加了实验性支持。这允许你在 Node.js 环境中运行 Pyodide 时使用 `socket` 模块,从而创建 TCP socket 并进行通信,例如连接到远程数据库服务器。它涵盖了带有 TLS 的 TCP socket、用于 webloop 的异步 socket 函数以及非阻塞模式。我们已经用几个数据库驱动程序进行了测试:`pymysql`(MySQL)、`pg8000`(PostgreSQL)和 `redis-py`。
这可以通过运行 `pyodide.useNodeSockFS()` 来启用:
```javascript
const pyodide = await loadPyodide();
await pyodide.useNodeSockFS();
```
在 Node.js <= v24 上,你还需要传递 `--experimental-wasm-stack-switching` 以启用 JSPI。
## JavaScript 互操作改进
本次发布为 JavaScript 互操作层带来了几项改进:
### `JsBigInt`:正确的 `bigint` 往返
我们添加了 `pyodide.ffi.JsBigInt`,这是一个新的 `int` 子类型,使得 JavaScript 的 `bigint` 类型在 Python 中能够正确往返。在此之前,进入 Python 的 `bigint` 会被转换为 `int`,但将其转换回 JavaScript 会产生一个 `number`,对于大于 2^53 的值会静默丢失精度。大于 2^53 的 Python 整数也存在同样的问题。现在,这两种情况都会产生一个 `JsBigInt`,它在 JavaScript 端会转换回 `bigint`。由于 `JsBigInt` 支持所有与 `int` 相同的操作,大多数现有代码无需任何更改。
### JavaScript 资源管理与 Python 上下文管理器
Pyodide 现在可以在语言边界的两侧与 JavaScript/ECMAScript 显式资源管理提案(https://github.com/tc39/proposal-explicit-resource-management)(`using` 声明)协同工作。
在 JavaScript 端,`PyProxy` 和 `PyBufferView` 现在实现了 `[Symbol.dispose]`,因此你可以使用 `using` 来确保 Python 对象在离开作用域时被清理:
```javascript
{
using proxy = pyodide.runPython("some_object()");
// proxy 在代码块结束时自动销毁
}
```
在 Python 端,如果 JavaScript 对象具有 `[Symbol.dispose]()` 方法,你可以将其 `JsProxy` 与 `with` 一起用作上下文管理器。同样,`[Symbol.asyncDispose]()` 用于异步上下文管理器:
```python
with js_object as x:
... # 退出时调用 x[Symbol.dispose]()
```
### 更好的 `JsProxy` 类数组支持
以前,只有真正的 JavaScript 数组(`Array.isArray()` 返回 true)以及少数已知类型(如 `HTMLCollection` 和 `NodeList`)会在其 `JsProxy` 中获得下标支持。现在,任何可迭代且具有 `length` 属性的 JavaScript 对象都会被当作类数组处理,因此对于更广泛的对象集合,`proxy[i]` 也能正常工作。
此外,现在也支持切片下标:
```javascript
proxy[1:4] // 返回一个新的类数组对象,包含索引 1 到 3
proxy[::2] // 每隔一个元素
```
## 致谢
衷心感谢 Python 指导委员会成员以及更广泛的 Python 社区对 PEP 783 及相关标准的支持和反馈。也感谢 cibuildwheel(https://cibuildwheel.pypa.io/)团队添加 PyEmscripten 支持,以及 Victorien Plot(https://github.com/Viicos)在 Pydantic 博客上撰写关于构建和发布 PyEmscripten wheel 的指南。
感谢所有使这次发布成为可能的贡献者:
Agriya Khetarpal, Amir Tadrisi, Andrej730, BOMIN LYU, Chanho Lee, Christian Clauss, Copilot, Daniel Chambers, Darshan, Gyeongjae Choi, Hanjeong Lee, Hood Chatham, hyoinandout, Juniper Tyree, kaif ansari, Maddy Guthridge, MisterNox, Pepijn de Vos, Qiaochu Hu, Raj Kumar Gupta, SATHVIK V SHETTY, Seungheon Lee, SongYoungUk, Victorien
相似文章
浏览器中的 Numba:在 JupyterLite 中开启全新科学 Python 技术栈
本文宣布了 Numba JIT 编译器的首个可运行版本,该版本可完全在浏览器中运行,借助 JupyterLite 和 WebAssembly,比标准 Python 快约 250 倍,并可在静态网站上启用完整的科学 Python 技术栈。
Patronus Ark,一个用于AI代理的本地安全扫描器
Patronus Ark 是一个新的 Rust 和 Python 库,用于本地扫描 AI 代理的文本和工具活动,覆盖提示注入、PII、数据泄露和与工具相关的风险,无需将数据发送到外部 API。
@Gas1688: 还在为爬虫被网站各种反制而头疼?Scrapling这个框架堪称规则颠覆者。 它最核心的优势在于:几乎能无障碍抓取任何目标网站,原生绕过Cloudflare等防护,且解析速度轻松超越BeautifulSoup达百倍以上。 它的硬核实力体现在…
介绍开源爬虫框架 Scrapling,号称能原生绕过 Cloudflare 等防护,解析速度远超 BeautifulSoup,内置 StealthyFetcher 和 CloakBrowser,并支持 MCP 服务器集成 AI Agent。
Show HN:Mcptoon – 将工具发现 token 消耗降低 97% 的 MCP CLI 客户端
mcptoon 是一个零依赖的 Python CLI 客户端,用于 MCP 服务器。它采用紧凑的 TOON 格式,将工具发现的 token 消耗减少高达 97%,从而为 AI 代理节省上下文窗口空间。
拆行难
深入探讨在 Python 中拆分多行文本的复杂性,涵盖众多 Unicode 换行字符以及 ASCII 中换行表示的历史渊源。