必须写明确小版本号(如“3.9”“3.11”),不能写“3”或“3.x”,否则setup-python会因找不到匹配缓存而触发源码编译,因缺失build-essential等依赖导致失败。

必须显式写具体小版本号,比如 3.9、3.11,不能写 3 或 3.x;否则会 fallback 到源码编译,大概率失败。
matrix 中的 python-version 值怎么写才有效
GitHub Actions 的 actions/setup-python@v4(或更新版)不支持模糊匹配。写 "3" 会报错 Version 3 not found;写 "3.x" 会被当作文本字符串,找不到缓存,最终尝试从源码编译 Python——这需要 build-essential 等系统依赖,而 GitHub 托管运行器默认不装,直接卡住或失败。
正确做法是查官方支持列表,然后写明确的小版本号:
- 查当前可用版本:在 workflow 里加一步
run: actions/setup-python --list-versions,或访问https://raw.githubusercontent.com/actions/python-versions/main/versions-manifest.json - PyPy 同理,得写
pypy-3.9,不能只写pypy - 推荐用 LTS 和主流活跃版本,比如
['3.9', '3.11', '3.12'];避免硬塞已 EOL 版本(如3.7),除非你真要维护兼容性
为什么 pip install -e . 在某个 matrix job 里会失败
常见现象是 ERROR: Package 'xxx' requires a different Python: 3.7.18 not in >=3.8 这类报错,尤其出现在用了 pyproject.toml 且声明了 requires-python = ">=3.8" 的项目中。
根本原因是:matrix 每个 job 是干净环境,但 setup-python 只负责设 PATH 和版本,不干预项目元数据校验。如果矩阵里混入了不满足 requires-python 的版本,pip 就会拒绝安装。
解决建议:
- 检查
pyproject.toml中的requires-python范围,和 matrix 列表对齐 - 若必须测试旧版本(如兼容性兜底),改用
pip install --no-deps -e .绕过依赖检查,再手动装依赖 - 更稳妥的做法:把 matrix 拆成两个 jobs,一个跑主版本,一个单独跑兼容性版本,避免混在一起触发冲突
actions/cache@v4 缓存 pip 时 key 必须含 ${{ matrix.python-version }}
matrix 下每个 job 默认不共享 pip cache,不加区分地共用同一个 cache key 会导致不同 Python 版本之间 pip 安装出错(比如 3.9 编译的 wheel 被 3.11 加载失败)。
GitHub 仓库备份技能 - 将 OpenClaw 工作空间自动或手动备份至 GitHub 私有仓库。支持自动定时备份和手动交互式配置,引导完成 Token 配置、仓库创建、首次备份及定时任务设置。用途:(1) 首次设置 (2) 日常备份。
正确写法示例:
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}-${{ matrix.python-version }}
注意点:
-
key中必须包含${{ matrix.python-version }},否则缓存会污染 - 如果项目用
pyproject.toml+pip install -e .,建议把pyproject.toml也加入 hash(hashFiles('**/pyproject.toml')) - 不要缓存整个
venv目录——它和 Python 版本强绑定,且体积大、命中率低
测试命令加超时控制,防止某个版本 hang 死整个 workflow
某些老版本(如 3.7)或特定依赖组合下,pytest 可能卡住不动,导致 job 长时间 pending,拖慢整个 CI 流水线。
推荐用 timeout 包裹测试命令,并设置合理中断信号:
timeout -s SIGINT 300s python -m pytest tests/ -v || true
说明:
-
300s即 5 分钟,足够多数单元测试完成;复杂模型推理测试可酌情调高 -
-s SIGINT确保能正常终止子进程(比如正在加载大模型的线程) -
|| true防止 timeout 触发后整个 step 标记为 failure,让结果仍由 pytest 自己判断成败 - 不用
pytest tests/,而用python -m pytest,绕过 PATH 查找问题,也避免某些 runner 上没把pytest加进环境变量
矩阵测试看着简单,但版本间差异带来的隐性冲突(依赖兼容性、缓存污染、信号处理)最容易被忽略。别只盯着 YAML 语法对不对,重点看每个 job 实际跑起来时,环境、缓存、中断机制是不是真的隔离干净了。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










