在浏览器中使用 Pyodide、PyScript 和 JupyterLite 在 Python 中运行 DuckDB
TL;DR: 在浏览器内的 Python 环境中运行 DuckDB,以实现对远程文件的简单查询、交互式文档和易于使用的培训材料。
“Hello World”时间
首次使用新库时,最重要的事情是如何快速地达到“Hello World”。
注意 想要查看“Hello World”吗?跳转到完全交互式的示例!
同样,如果有人访问您编写的任何文档,您会希望他们能够快速轻松地启动并运行您的工具。在演示时,您希望避免“演示地狱”,并确保它第一次就成功!
如果您想尝试“专家模式”,请尝试带领整个会议室的人完成这些设置步骤!教室或会议研讨会环境使得安装的“防弹”性变得至关重要。
Python 是我们使用 DuckDB 最喜欢的方式之一,但 Python 的设置出了名的困难——对于新手程序员来说更是如此。虚拟环境到底是什么鬼?您是在 Windows、Linux 还是 Mac 上?Pip 还是 Conda?新来的 uv 呢?
经验丰富的 Python 程序员也无法幸免!许多人,包括我,都曾被迫遵循那项历史悠久、xkcd 记载的传统:彻底清除所有与 Python 相关的东西,然后从头开始。
我们如何才能尽可能简单和快速地测试 Python 中的 DuckDB?
服务器端 Python 的困难
应对这一挑战的一种方法是为每个用户在服务器上托管一个 Python 环境。这存在许多问题。
自己托管 Python 服务器不是免费的。如果您有许多用户,那费用可能相当可观。
如果您想使用 Google Colab 等免费解决方案,每个访问者都需要一个 Google 帐户,并且您需要接受 Google 访问您的数据。此外,它很难嵌入到现有网页中以提供无缝体验。
Pyodide 登场
Pyodide 借助 WebAssembly 的强大功能,让您无需安装、无需设置,即可直接在浏览器中运行 Python。这使得它成为启动和运行 Python 环境最简单、最快捷的方式——只需加载一个网页!所有计算都在本地进行,因此它可以像任何静态网站一样通过 GitHub Pages 等工具进行服务。无需服务器端 Python!
另一个好处是 Pyodide 在浏览器环境中得到了很好的沙盒化。每个用户都有自己的工作区,而且由于所有内容都是本地的,因此非常安全。
Pyodide 与其他浏览器内 Python 方法的区别在于,它甚至可以运行用 C、C++ 甚至 Fortran 编写的库,包括大部分 Python 数据科学堆栈。这意味着您现在也可以在 Pyodide 中使用 DuckDB 了!您甚至可以将其与 NumPy、SciPy 和 Pandas(以及许多纯 Python 库)结合使用。PyArrow 和 Ibis 也提供实验性支持。
Pyodide DuckDB 的用例
想快速使用 Python 或 DuckDB 分析一些远程数据吗?
Pyodide 是使用 Python 回答问题的最快方式。
想快速分析一些本地数据吗?
Pyodide 也可以查询本地文件!
想让您的文档具有交互性吗?
让您的用户轻松测试由 DuckDB 支持的库。我们将在下面看到一个示例,演示了 magic-duckdb
Jupyter 插件如何启用 SQL 单元格。
正在主持一场 DuckDB 和 Python 的培训课程吗?
跳过本地安装的麻烦。无需一对一地为观众中那 15% 遇到奇葩设置问题的人提供帮助!每个人都可以在几秒钟内第一次就成功运行,这样您就可以专注于您想教授的内容。此外,它是免费的,无需任何注册!
Pyodide 示例
我们将介绍多种将 Pyodide 支持的 Python 直接嵌入到您网站中的方法,以便您的用户只需单击一下即可试用您新的 DuckDB 支持的工具!
- PyScript 编辑器
- 一个具有良好语法高亮的编辑器
- JupyterLite Notebook
- 一个经典的 Notebook 环境
- JupyterLite Lab IDE
- 一个完整的开发环境
PyScript 编辑器
此 HTML 片段将可运行的 PyScript 编辑器嵌入到任何页面中!
<script type="module" src="https://pyscript.net/releases/2024.8.2/core.js"></script>
<script type="py-editor" config='{"packages":["duckdb"]}'>
import duckdb
print(duckdb.sql("SELECT '42 in an editor' AS s").fetchall())
</script>
只需单击播放按钮,您就可以直接在浏览器中执行 DuckDB 查询。您可以编辑代码,添加新行等等。试试看!
JupyterLite Notebook
这是一个使用指向部署到 GitHub Pages 的 JupyterLite 环境的 iframe
的示例!
<iframe src="https://alex-monahan.github.io/jupyterlite_duckdb_demo/notebooks/index.html?path=hello_duckdb.ipynb" style="height: 600px; width: 100%;"></iframe>
这是一个完全交互式的 Python Notebook 环境,其中运行着 DuckDB。请随意运行!
配置完整的 JupyterLite 环境只需几个步骤!JupyterLite 团队已经构建了一个用作模板的演示页面,并提供了一些很棒的文档。主要步骤是:
- 使用 JupyterLite 演示模板创建您自己的仓库
- 为该仓库启用 GitHub Pages
- 在
content
文件夹中添加并提交一个 .ipynb 文件 - 访问
https://your_github_username.github.io/YOUR_REPOSITORY_NAME/notebooks/index.html?path=your_notebook_name.ipynb
请注意,GitHub Pages 的部署可能需要几分钟。您可以在 GitHub 的 Actions 选项卡中监控进度。
JupyterLite Lab IDE
在完成 JupterLite Notebook 设置中的步骤后,如果您将 URL 从 /notebooks/
更改为 /lab/
,您就可以获得完整的 IDE 体验!这种形式更难嵌入到其他页面中,但非常适合交互式使用。
此示例使用了 magic-duckdb
Jupyter 扩展,它允许我们使用 %%dql
创建 SQL 单元格。
点击此链接查看 Lab IDE 界面,或尝试下面的 Notebook 样式版本。
<iframe src="https://alex-monahan.github.io/jupyterlite_duckdb_demo/notebooks/index.html?path=magic_duckdb.ipynb" style="height: 600px; width: 100%;"></iframe>
Pyodide 中的 DuckDB 架构
那么 DuckDB 在 Pyodide 中究竟是如何工作的呢?DuckDB Python 客户端是完整地编译为 WebAssembly (Wasm) 的。这与现有的 DuckDB Wasm 方法不同,因为后者只编译库的 C++ 部分并用 JavaScript API 进行封装。两种方法都使用 Emscripten 工具链进行 Wasm 编译。正是 DuckDB 避免依赖的设计决策以及之前对 DuckDB-Wasm 的投入,使得在如此短的时间内构建此功能成为可能!
Pyodide 团队已将 DuckDB 添加到他们托管的库仓库中,甚至设置了 DuckDB 作为其 CI/CD 工作流程的一部分运行。这使得 JupyterLite 可以简单地运行 %pip install duckdb
,并且 PyScript 可以在 py-editor config
参数或 <py-config>
标签中将 DuckDB 指定为一个包。然后 Pyodide 会从 Pyodide 的仓库下载 Wasm 编译版本的 DuckDB 库。我们非常感谢 Pyodide 团队,包括 Hood Chatham 和 Gyeongjae Choi,以及 Voltron Data 团队,包括 Phillip Cloud,他们领导了这项工作使其得以实现。
限制
在浏览器中运行是一个限制更严格的环境(出于安全目的),因此在 Pyodide 中使用 DuckDB 时存在一些限制。没有免费的午餐!
- 单线程
- Pyodide 目前将执行限制为单线程
- 查询远程文件需要一些额外的步骤
- 远程文件无法由 DuckDB 直接访问
- 相反,首先使用 Pyodide 将文件拉取到本地
- DuckDB-Wasm 有自定义增强功能可以实现这一点,但这些在 DuckDB 的 Python 客户端中不存在
- 不支持运行时加载的扩展
- 几个扩展会自动包含:
parquet
、json
、icu
、tpcds
和tpch
。
- 几个扩展会自动包含:
- 发布节奏与 Pyodide 对齐
- 截至撰写本文时,duckdb-pyodide 版本为 1.0.0,而非 1.1.1
结论
Pyodide 现在是结合使用 Python 和 DuckDB 最快的方式!它也是一种可以扩展到任意数量用户的方法,因为 Pyodide 的计算完全在本地进行。
我们已经看到了如何以多种方式将 Pyodide 嵌入到静态站点中,以及如何读取远程文件。
如果您对 Pyodide 中的 DuckDB 感到兴奋,请随时加入我们的 Discord。我们有一个 #show-and-tell
频道,您可以在其中与社区分享您构建的作品。也欢迎您探索 duckdb-pyodide 仓库并报告您发现的任何问题。我们也非常需要启用运行时加载扩展的帮助——如果您能提供帮助,请与我们联系!
祝您使用愉快!