Starlette 开发脚本全指南:从安装、测试到发布的一体化工作流
【免费下载链接】starletteThe little ASGI framework that shines. 🌟项目地址: https://gitcode.com/gh_mirrors/st/starlette
导读
本文聚焦 Starlette 仓库中 scripts/README.md 所定义的开发脚本体系,逐行解读install、test、lint、check、coverage、build、docs、sync-version等脚本背后的真实命令与设计意图。该体系遵循 GitHub "Scripts to Rule Them All" 约定,用一套统一命名的脚本封装了 Starlette 从依赖安装、代码质量检查、测试覆盖到打包发布的完整工程化流程。读完本文,你将能够在自己参与 Starlette 开发时熟练使用这套脚本,也能将其模式复用到自己的 Python 项目中。
脚本总览:一套命名约定统一工程化流程
scripts/README.md 的核心思想非常简洁:用统一命名、语义清晰的脚本覆盖开发生命周期的每个环节。原文档列出的脚本及职责如下:
| 脚本 | 职责 |
|---|---|
scripts/install | 在虚拟环境中安装依赖 |
scripts/test | 运行测试套件 |
scripts/lint | 运行自动化代码检查/格式化工具 |
scripts/check | 运行代码检查,确认其通过 |
scripts/coverage | 检查代码覆盖率是否完整 |
scripts/build | 构建源码包和 wheel 包 |
这套设计明确标注为借鉴 GitHub 的 "Scripts to Rule Them All" 实践——即把每个项目的常规开发命令收敛到固定脚本名下,让新贡献者无需记忆每个工具的具体命令,就能以一致的方式完成环境搭建、测试和发布。
除了原文档点名的 6 个脚本,仓库scripts/目录下还有两个承担辅助职责的脚本:
scripts/sync-version:校验版本号一致性,被check依赖;scripts/docs:启动本地文档开发服务器。
下文将逐一深入每个脚本的实际实现。
环境准备:scripts/install 与 uv 依赖管理
scripts/install的实现极为精简,全部逻辑只有一行核心命令:
#!/bin/sh -e set -x uv sync --frozen三个细节值得注意:
#!/bin/sh -e:-e选项保证任何一条命令失败时脚本立即退出,避免在错误状态下继续执行,这是所有脚本通用的稳健性设计。set -x:打开命令回显,让终端明确展示正在执行的真实命令,便于排查问题。uv sync --frozen:使用 uv 锁定文件安装,不更新锁文件,确保团队成员拿到完全一致的依赖版本。
仓库在 pyproject.toml 中对 uv 做了配置:
[tool.uv] default-groups = ["dev", "docs"] required-version = ">=0.8.6" exclude-newer = "7 days"即默认同步dev和docs两个依赖组,且要求 uv 版本不低于 0.8.6。其中dev组(见 pyproject.toml)集中了全部开发工具:pytest、coverage、ruff、mypy、twine、trio、httpx、pytest-codspeed等,并注明"addstarlette[full]souv syncconsiders the extras",保证同步时会解析 full 可选依赖。
代码质量双通道:lint 与 check
Starlette 将代码质量工具拆成两个脚本,对应"主动修复"与"被动校验"两种场景,使用方式完全一致:./scripts/lint或./scripts/check。
scripts/lint:自动修复
#!/bin/sh -e export SOURCE_FILES="starlette tests" set -x uv run ruff format $SOURCE_FILES uv run ruff check --fix $SOURCE_FILESlint面向开发者日常使用,会直接修改代码:先用ruff format统一格式化starlette与tests两个目录,再以--fix自动修复可自动解决的 lint 问题。注意SOURCE_FILES仅包含starlette tests,不包含benchmarks。
scripts/check:CI 校验
#!/bin/sh -e export SOURCE_FILES="starlette tests benchmarks" set -x ./scripts/sync-version uv run ruff format --check --diff $SOURCE_FILES uv run mypy $SOURCE_FILES uv run ruff check $SOURCE_FILEScheck是"只读"的校验通道,包含四个步骤:
./scripts/sync-version:先校验版本一致性(见下文);ruff format --check --diff:只检查格式是否符合规范,不做修改,并输出差异预览;mypy $SOURCE_FILES:对源码执行静态类型检查,且SOURCE_FILES在此扩展为starlette tests benchmarks三部分;ruff check $SOURCE_FILES:运行 lint 规则检查,不自动修复。
ruff 的规则配置见 pyproject.toml:行宽 120,启用E(pycodestyle 错误)、F(Pyflakes)、I(isort 导入排序)、FA(future annotations)、UP(pyupgrade)、RUF100等规则集,仅忽略UP031。mypy 则启用strict = true(见 pyproject.toml),并对starlette.testclient.*单独放行implicit_optional。
scripts/sync-version:版本一致性守卫
#!/bin/sh -e SEMVER_REGEX="([0-9]+)\.([0-9]+)\.([0-9]+)(-([0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?(\+[0-9A-Za-z-]+)?" CHANGELOG_VERSION=$(grep -o -E $SEMVER_REGEX docs/release-notes.md | head -1) VERSION=$(grep -o -E $SEMVER_REGEX starlette/__init__.py | head -1) if [ "$CHANGELOG_VERSION" != "$VERSION" ]; then echo "Version in changelog does not match version in starlette/__init__.py!" exit 1 fi它用一条标准 semver 正则分别从 docs/release-notes.md 的更新日志和 starlette/init.py 的版本声明中提取版本号,两者不一致即报错退出。这保证了发布版本、变更记录、包版本三者永远同步——这正是 pyproject.toml 中[tool.hatch.version]以starlette/__init__.py为单一版本来源的配套校验。
测试与覆盖率:scripts/test 与 scripts/coverage
scripts/test:适配本地与 CI 两套环境
#!/bin/sh set -ex if [ -z $GITHUB_ACTIONS ]; then scripts/check fi uv run coverage run -m pytest $@ if [ -z $GITHUB_ACTIONS ]; then scripts/coverage fitest脚本实现了智能环境适配:
- 本地运行时(未设置
GITHUB_ACTIONS环境变量),会先执行scripts/check做完整质量校验,测试结束后再执行scripts/coverage检查覆盖率,即"本地一次跑完所有关卡"; - 在 GitHub Actions CI 中(
GITHUB_ACTIONS非空),则跳过这两步,只运行测试主体,因为 CI 工作流通常已单独配置了 lint 与覆盖率步骤,避免重复。
测试主体是uv run coverage run -m pytest $@,通过 coverage 包裹 pytest 运行,并且$@透传所有命令行参数——这意味着你可以追加文件路径或 pytest 标记来跑指定测试,例如:
./scripts/test tests/test_routing.pypytest 的严格配置见 pyproject.toml:-rXs --strict-config --strict-markers、xfail_strict = true,并把未过滤的警告提升为异常,同时放行starlette.middleware.wsgi等已知弃用警告。
scripts/coverage:100% 覆盖红线
#!/bin/sh -e set -x uv run coverage report --show-missing --skip-covered --fail-under=100覆盖率脚本用三个参数把门槛拉满:
--show-missing:列出所有未覆盖的行号,方便针对性补测;--skip-covered:隐藏已完全覆盖的文件,让报告只聚焦问题;--fail-under=100:覆盖率低于 100% 即退出码非 0。
这是 Starlette 长期坚持的工程纪律——任何新代码必须配套测试,保证每行都处于测试保护之下。仓库中的 tests/ 目录覆盖了 routing、requests、responses、websockets、middleware 等全部核心模块,正是这套红线要求的产物。
发布链路:scripts/build 与版本产物
#!/bin/sh -e set -x uv build uv run twine check dist/* uv run zensical build --cleanbuild脚本三步完成发布前准备:
uv build:构建出sdist源码包与wheel二进制包到dist/目录;uv run twine check dist/*:用 twine 校验构建产物的元数据、README 渲染与包结构是否符合 PyPI 上传规范;uv run zensical build --clean:通过 zensical(文档构建工具)重建项目文档。
至此,dist/中的产物即可通过twine upload发布,而版本号来源已由scripts/sync-version在check阶段保证一致。
本地文档预览:scripts/docs
#!/bin/sh -e set -x uv run zensical servedocs脚本用zensical serve启动本地文档开发服务器,供撰写文档时实时预览。zensical属于 pyproject.toml 中docs依赖组(含mkdocstrings、mkdocstrings-python、zensical等),文档源文件位于 docs/,配置见 mkdocs.yml。
实战速查:给贡献者的日常命令清单
| 场景 | 命令 | 说明 |
|---|---|---|
| 首次克隆后搭建环境 | ./scripts/install | 按 lock 文件精确安装 dev + docs 依赖 |
| 写代码后自动格式化 | ./scripts/lint | ruff 自动格式化并修复 |
| 提交前全面自检 | ./scripts/check | 版本校验 + 格式 + 类型 + lint |
| 跑全部测试(含覆盖率门槛) | ./scripts/test | 本地会串联 check 与 coverage |
| 只跑指定测试 | ./scripts/test tests/test_routing.py | $@透传 pytest 参数 |
| 查看覆盖率明细 | ./scripts/coverage | 低于 100% 即失败 |
| 预览文档 | ./scripts/docs | 启动本地文档服务器 |
| 构建发布产物 | ./scripts/build | sdist + wheel + twine 校验 + 文档构建 |
模式启示:如何借鉴这套脚本体系
Starlette 的 scripts 体系对任何 Python 项目都有直接参考价值,其可复用的设计要点包括:
- 固定入口、一致命名:
install/test/lint/check/build是社区通用约定,新贡献者零学习成本; set -ex的错误即停:任何一步失败立即中断,杜绝"部分成功"的假象;- 修复与校验分离:
lint(自动修)与check(只检查)服务不同场景,CI 用check保证可复现; - 环境自适应:通过
GITHUB_ACTIONS环境变量区分本地与 CI,避免重复执行冗余步骤; - 发布前守卫:
sync-version在源头锁死版本一致性,把发布错误拦截在构建之前。
对想要借鉴的读者,可直接对照本仓库 scripts/ 目录逐行阅读,理解每一处set -x、uv run与参数透传的设计取舍,再按自身工具链(如 poetry、pdm、pipenv)替换uv即可落地到自己的项目。
【免费下载链接】starletteThe little ASGI framework that shines. 🌟项目地址: https://gitcode.com/gh_mirrors/st/starlette
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考