PyGWalker 贡献者开发指南:从环境搭建到一键热重载与 CI 验证的完整工作流
【免费下载链接】pygwalkerPyGWalker: Turn your dataframe into an interactive UI for visual analysis项目地址: https://gitcode.com/GitHub_Trending/py/pygwalker
PyGWalker 是一个把 pandas/polars/pyarrow 等 DataFrame 转换为可交互可视化 UI 的 Python 库,其仓库由 Python 包(pygwalker/)与 React 前端(app/)两个半区组成并打包进同一个 wheel。本文基于仓库根目录的 CONTRIBUTING.md 与其详细版本 docs/CONTRIBUTING.md,完整梳理本地开发环境搭建、前后端双栈构建、python scripts/dev.py一键热重载开发栈、以及提交前验证与 CI 对齐的全部命令与参数;读完本文,你将掌握一套可直接复现的 PyGWalker 本地贡献流程,并理解其底层构建与加载机制。
贡献指南的入口设计:一份短入口,一份权威详述
仓库将贡献者工作流拆成两层文档,避免重复维护:
- 根目录 CONTRIBUTING.md 是面向新贡献者(包括编码 Agent)的入口,它把读者引向 AGENTS.md——后者提供仓库地图、Python 与前端两半区的构建方式,以及"一条命令"的开发栈
python scripts/dev.py(带前端实时重载与集中日志)。 - 详细的贡献者工作流统一维护在 docs/CONTRIBUTING.md,覆盖:
- Python 可编辑安装与测试命令;
- 前端依赖安装、构建、类型检查与 Playwright smoke 测试;
- 通过
app的dev:preinstall脚本可选地构建本地 Graphic Walker 源码; - 热重载开发工作流(docs/DEVELOPMENT.md)与项目架构(docs/ARCHITECTURE.md);
- CI 与包构建的预期行为。
这种"短入口 + 单一权威详述"的设计让开发笔记与故障排查页可以统一链接到一份维护中的真源文档。
环境准备:版本对齐是第一步
在开始前,请确保本机满足以下版本要求(与 CI 保持一致):
| 依赖 | 版本要求 | 说明 |
|---|---|---|
| Python | 3.10 或更新 | 仓库pyproject.toml中requires-python = ">=3.10"与之对应 |
| Node.js | 22.x | 必须与 CI 使用的版本一致(见下文 CI 说明) |
| Yarn | 1.x | 经典版 Yarn |
从源码看,scripts/dev.py 在执行时会用_resolve_exe依次查找可执行文件:优先使用当前 Python 解释器同目录下的同名可执行文件(即 venv 内的yarn/jupyter),再回退到PATH搜索;找不到时直接退出并给出安装提示。这提醒我们:确保 Node.js 22.x 与 Yarn 1.x 在当前 shell 的PATH中,是后续所有命令能跑通的前提。
Python 环境搭建:可编辑安装 + dev 依赖
从仓库根目录执行:
python -m venv venv source venv/bin/activate pip install -e ".[dev]"Windows 下激活环境使用:
venv\Scripts\activate要点说明:
pip install -e ".[dev]"采用可编辑安装(editable install),代码改动即时生效,无需重复安装;[dev]是pyproject.toml中定义的开发依赖组,包含测试、lint、notebook 运行等工具(如pytest、ruff、nbmake);- 在
pyproject.toml的 Hatch 配置中,editable 构建同样会走hatch-jupyter-builder钩子并执行前端dev命令(build_cmd = "dev"),因此 venv 创建完成后建议紧接着完成下一步的前端依赖安装,保证pygwalker/templates/dist/中有可用 bundle。
前端环境搭建:依赖、构建与产物
进入app/目录安装前端依赖:
cd app yarn install构建全部前端 bundle:
yarn build如果只想快速重建主应用 bundle(适合只改app/src时的本地迭代):
yarn build:app关于这两个命令的差异,app/package.json 中的脚本定义给出了精确答案:
"build": "yarn typecheck && vite build && vite build --mode=dsl_to_workflow && vite build --mode=vega_to_dsl", "build:app": "vite build"即yarn build会先跑 TypeScript 类型检查(tsc --noEmit),再依次产出四个产物;而yarn build:app只执行一次vite build,不做类型检查,也不构建 DSL 转换辅助 bundle,因此只适合本地快速迭代,不能用于 CI 或最终提交流程(详见"验证"一节)。
构建产物会写入pygwalker/templates/dist/。这些是生成产物,已被 git 忽略,除非发布流程明确要求,否则不应提交(详见 AGENTS.md 与 docs/ARCHITECTURE.md 中的说明)。四个 bundle 与用途如下:
| Bundle | 构建入口 | 加载方 |
|---|---|---|
pygwalker-app.es.js | app/src/index.tsx | anywidget 传输(默认pyg.walk路径) |
pygwalker-app.iife.js | app/src/index.tsx | iframe 传输 / 静态to_html() |
dsl-to-workflow.umd.js | app/src/lib/dslToWorkflow.ts | 内核侧 DSL→workflow 转换 |
vega-to-dsl.umd.js | app/src/lib/vegaToDsl.ts | 内核侧 Vega→DSL 转换 |
使用本地 Graphic Walker 源码进行联调
npm 包@kanaries/graphic-walker默认从app/yarn.lock安装。如果你需要针对本地 Graphic Walker checkout 测试 PyGWalker,需把它放在 PyGWalker 仓库根目录下,使其成为app/的兄弟目录:
pygwalker/ +-- app/ +-- graphic-walker/ +-- packages/ +-- graphic-walker/然后在启动 PyGWalker 前端之前先构建 Graphic Walker:
cd app yarn dev:preinstalldev:preinstall实际执行的内容(见 app/package.json):
cd ../graphic-walker/packages/graphic-walker yarn --frozen-lockfile yarn build如果../graphic-walker/packages/graphic-walker目录不存在,则跳过此命令,回退到 lockfile 锁定的 npm 依赖即可。
开发服务器 / 热重载:一条命令的完整开发栈
针对前端迭代,项目提供了一键开发栈:每次改动都会重建应用并借助 anywidget HMR 把新代码热重载进已打开的 notebook widget 中:
python scripts/dev.py这条命令会同时启动两个长驻进程,并把两者的输出同时"分流(tee)"到终端与logs/目录下的独立文件(详见 scripts/dev.py 的实现):
- frontend:
cd app && yarn dev:build,即vite build --watch,每次你编辑app/src就会重建pygwalker/templates/dist/pygwalker-app.es.js,输出到logs/frontend.log; - jupyter:以
PYGWALKER_DEV=1与ANYWIDGET_HMR=1环境变量启动jupyter lab(内核会继承这些变量),输出到logs/jupyter.log。
scripts/dev.py还会通过PYGWALKER_LOG_FILE把内核侧的 PyGWalker Python 日志集中到logs/pygwalker.log(通过env.setdefault设置,不覆盖用户显式选择)。启动时脚本会先等待前端首次构建完成(在日志中匹配 Vite 的built in完成标记,见_wait_for_first_build),再拉起 JupyterLab,避免内核找不到 bundle。
两个进程都启动后,在 notebook 单元里无需任何特殊设置,直接正常使用 PyGWalker:
import pandas as pd, pygwalker as pyg pyg.walk(pd.DataFrame({"x": [1, 2, 3], "y": [4, 5, 6]}))随后编辑app/src下的任意文件,等logs/frontend.log中出现built in …表示重建完成,widget 就会就地热重载——通常无需重跑单元;改动较大时重跑单元即可。按Ctrl+C可干净地停掉整套服务。
热重载为什么能工作
其原理记录在 docs/DEVELOPMENT.md 与 docs/ARCHITECTURE.md 中,关键在pygwalker/services/anywidget_widget.py:
- 正常安装:
WalkerAnyWidget._esm是pygwalker-app.es.js的内容字符串(导入时内嵌),与历史行为完全一致; - 开发模式(设置
PYGWALKER_DEV=1或ANYWIDGET_HMR=1):_esm指向该 bundle 的文件路径,anywidget 从磁盘读取,并在 HMR 下通过watchfiles监听该文件,每当vite build --watch重写它就把新代码推送到前端。
由于该切换完全由环境变量显式开启,在未设置这些标志的普通安装中,加载行为逐字节不变——对最终用户没有任何影响。
dev.py 常用参数
| 参数 | 作用 |
|---|---|
--no-jupyter | 只跑前端 watch 构建 |
--no-frontend | 只启动 JupyterLab(bundle 已构建好时) |
--jupyter-port N | 指定 JupyterLab 端口 |
--no-browser | 不自动打开浏览器(输出不是 TTY 时自动启用,如 Agent 运行场景) |
--log-dir DIR | 更改日志目录(默认logs/) |
另外还有一个历史遗留的 Vite dev-server +GlobalVarManager.set_component_url("/pyg_dev_app/")+jupyter-server-proxy方案,它只驱动已废弃的低层 iframe 兼容渲染器;旧的env='Jupyter'别名现在会统一选择 anywidget,显式调用兼容方法的完整说明见 docs/DEVELOPMENT.md。新开发工作一律优先走 anywidget HMR 路径。
日志:一处查看所有输出
scripts/dev.py把所有输出集中到仓库根目录的logs/(git 忽略):
| 文件 | 内容 |
|---|---|
logs/frontend.log | Vite 构建/watch 输出——留意built in …(重建完成)与 TypeScript 错误 |
logs/jupyter.log | JupyterLab 服务器输出——打开 notebook 的 URL 与 token 在这里 |
logs/pygwalker.log | 内核侧 PyGWalker Python 日志(经PYGWALKER_LOG_FILE设置) |
Python 侧日志还支持两个与编排器无关的环境变量(由pygwalker/utils/log.py处理):PYGWALKER_LOG_FILE=/path/to/file.log追加写入文件,PYGWALKER_LOG_LEVEL=DEBUG调整详细程度(默认INFO)。前端运行时的日志(如 comm 错误)出现在浏览器 devtools 控制台,不会写入logs/;面向用户的错误会以应用内 toast 通知呈现。
验证与提交前检查:本地复刻完整 CI
提交前,可以用一条命令在本地跑完整的 CI 流程(前端构建 + Playwright smoke 测试 + notebook 测试 + Python lint/测试):
python scripts/local_ci.py # 可加 --skip-frontend / --skip-notebooks 缩小范围scripts/local_ci.py 是 GitHub Actions Auto CI 工作流的本地等价实现,支持--skip-frontend、--skip-notebooks、--legacy-modin-deps(镜像 Ubuntu Python 3.11 modin CI 分支)三个开关。也可以按下面的分步命令逐个执行。
Python 侧:格式化、lint 与测试
在仓库根目录(venv 已激活)执行:
python -m ruff check pygwalker tests scripts bin pygwalker_tools python -m ruff format --check pygwalker tests scripts bin pygwalker_tools python -X faulthandler -W error::DeprecationWarning:pygwalker -m pytest -o faulthandler_timeout=60 tests python -m pytest --nbmake --nbmake-kernel=python tests/*.ipynb逐条说明:
- 前两条用
ruff分别做 lint 检查与格式检查(pyproject.toml中配置了target-version = "py310"、line-length = 120); - 第三条运行单元测试,同时开启 faulthandler、把
pygwalker包内的DeprecationWarning提升为错误,并设置faulthandler_timeout(文档中为 60 秒;scripts/local_ci.py 中的 CI 等价实现使用 300 秒); - 第四条用
nbmake逐本执行tests/*.ipynb中的 notebook,验证 notebook 场景可运行。
需要留意:pygwalker_tools/是一个活跃打包的辅助命名空间,当前支持面为pygwalker_tools.metrics,由tests/test_metrics_tools.py覆盖,因此它必须保持在 lint、测试、wheel 与 sdist 的路径中——这也解释了上述命令为什么显式包含pygwalker_tools。
前端侧:类型检查、构建与 smoke 测试
在app/目录下执行:
yarn typecheck yarn build yarn playwright install chromium yarn test:front_endyarn typecheck对应tsc --noEmit --pretty false;yarn build是全量构建(typecheck + 四个 bundle);yarn playwright install chromium首次运行需要安装 Chromium;app/playwright.config.ts 配置了testDir: "./tests"、30 秒用例超时、基于http://127.0.0.1:8769的 webServer(yarn dev --host 127.0.0.1),CI 下会复用/重建该服务器;yarn test:front_end运行 Playwright smoke 测试(app/tests/gwalker-smoke.spec.ts)。
再次强调:yarn build:app虽然便于快速迭代主 bundle,但不运行 TypeScript 检查、也不构建 CI 与包构建所必需的 DSL 转换辅助 bundle,提交前必须走完整的yarn build或至少yarn typecheck。
包构建
在仓库根目录执行:
python -m build --wheel --no-isolation当前包构建会在构建 wheel 时重新构建前端 bundle,而不是复用已有的pygwalker/templates/dist文件。这一行为由 pyproject.toml 中的 Hatch 配置保证:
[tool.hatch.build.hooks.jupyter-builder] dependencies = ["hatch-jupyter-builder"] build-function = "hatch_jupyter_builder.npm_builder" ensured-targets = ["pygwalker/templates/dist/pygwalker-app.iife.js"] optional-editable-build = true [tool.hatch.build.hooks.jupyter-builder.build-kwargs] path = "app" build_dir = "./build" build_cmd = "build"ensured-targets确保构建产物存在;wheel 构建钩子会在app/下执行build(即 typecheck + 四个 bundle),因此发布出的 wheel 始终包含刚构建的 bundle。这也解释了为什么pygwalker/templates/dist/被 git 忽略、按需重建、永不手工提交。前端构建也可直接由 scripts/compile.sh 完成(自动处理 yarn 缺失时的全局安装,再执行yarn && yarn build)。
CI 说明:工作流与仓库配置对齐
GitHub workflows 的现状(详见 docs/CONTRIBUTING.md 的 CI Notes):
- 用 Node.js 22.x 构建前端资产;
- 运行前端 Playwright smoke 测试;
- 再运行 Python 测试矩阵;
- Python 包构建也会安装 Node.js 与 Yarn,因为 Hatch 构建钩子在 wheel 创建期间会重建前端。
因此,任何 CI 工作流的改动都要与app/package.json、pyproject.toml、scripts/compile.sh保持一致,否则本地验证与远端 CI 会出现偏差。
提交前后的小结与常见问题
一次典型的贡献流程可以概括为:
- 搭建环境:Python 3.10+ venv +
pip install -e ".[dev]",cd app && yarn install,首次yarn build生成pygwalker/templates/dist/; - 迭代开发:
python scripts/dev.py一键启动 watch 构建与 JupyterLab,编辑app/src即可看到热重载;涉及消息协议(pygwalker/communications/protocol.py)改动时,运行python scripts/generate_comm_protocol_ts.py重新生成app/src/interfaces/comm.generated.ts并重建前端,切不可手改生成文件; - 本地验证:
python scripts/local_ci.py(或分步执行 Python 的 ruff/pytest/nbmake 与前端 typecheck/build/playwright); - 打包检查:
python -m build --wheel --no-isolation,确认 Hatch 钩子重建了前端 bundle。
常见问题(完整清单见 docs/DEVELOPMENT.md 的 Troubleshooting 一节):
- "Missing PyGWalker frontend asset" 错误:bundle 尚未构建,先
cd app && yarn build,或等scripts/dev.py完成首次构建; - 前端改动不生效:确认
logs/frontend.log出现built in …,且 JupyterLab 以ANYWIDGET_HMR=1启动(编排器会自动设置);改动较大时重跑单元或重启内核; - React 版本错误等异常:在
app/下执行干净重建(rm -rf node_modules && yarn install && yarn build,如需手动清理依赖); - 千万别提交
pygwalker/templates/dist/:它是生成产物,wheel 构建(与 CI)会通过 Hatch 钩子按需重建。
遵循上述工作流,无论是人类贡献者还是编码 Agent,都能以与 CI 完全一致的标准完成 PyGWalker 的前后端开发与交付。
【免费下载链接】pygwalkerPyGWalker: Turn your dataframe into an interactive UI for visual analysis项目地址: https://gitcode.com/GitHub_Trending/py/pygwalker
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考