概述
从一个空目录开始,使用 uv
创建、开发、构建并发布一个名为 ccyy-demo
的命令行调用的工具
初始化项目
uv
提供了uv init
命令,可以快速生成一个遵循最佳实践的项目骨架。使用--package
参数可以直接创建标准的src
布局。
1.基于已有项目进行初始化
bash
# 创建并进入项目根目录
mkdir ccyy-demo
cd ccyy-demo
# 在当前项目下初始化并生成标准目录结构
# 会自动创建虚拟环境 (.venv)、pyproject.toml, 以及src/ccyy_demo/__init__.py源代码结构
uv init . --package
2.使用uv创建并初始化项目
bash
uv init --package ccyy_demo
# 需单独创建venv环境
uv venv
现在,你的目录结构应该是这样的:
css
ccyy-demo/
├── .venv/
├── pyproject.toml
├── .python-version
├── .gitignore
├── README.md
└── src/
└── ccyy_demo/
├── __init__.py
编写应用代码
创建 src/ccyy_demo/main.py
文件,写入命令行调用工具
的代码核心逻辑。将使用 argparse
来处理命令行参数。
python
import argparse
def main():
"""CLI 工具的主入口函数"""
parser = argparse.ArgumentParser(
description="一个由 ccyy-demo 创建的、使用 uv 构建的简单 CLI 工具。"
)
parser.add_argument(
"--name",
default="World",
help="The name to greet."
)
args = parser.parse_args()
print(f"Hello, {args.name}! This is ccyy-demo speaking.")
if __name__ == "__main__":
main()
在 src/ccyy_demo/__init__.py
的执行入口添加实现函数
bash
from .main import main as ccyy_demo_main
def main() -> None:
ccyy_demo_main()
定义项目 (pyproject.toml
)
pyproject.toml
是现代Python项目的核心配置文件,它遵循 PEP 621 标准,用于定义项目的元数据、依赖项和构建系统。
uv init
已经为生成了一个 pyproject.toml
模板,默认内容如下:
bash
[project]
name = "ccyy-demo"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.10"
dependencies = []
[project.scripts]
ccyy-demo = "ccyy_demo:main"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
扩展后的pyproject.toml
bash
# 包含项目的核心元数据,如名称、版本、描述等。这些信息会用于PyPI(Python 包索引)以及包管理工具。
[project]
# 项目名称,在PyPI上发布时不能有冲突
# 通常使用连字符 "-" 而不是下划线 "_"
name = "ccyy-demo"
# 项目的当前版本号,遵循语义化版本
version = "0.1.0"
# 项目的简短描述
description = "一个使用 uv 构建的示例 CLI 项目"
# 项目的详细描述,通常从 README.md 文件中读取
readme = "README.md"
# 项目所需的最低 Python 版本
requires-python = ">=3.10"
# 项目的许可证信息
license = { text = "MIT" }
# 项目作者信息
authors = [
{ name = "Your Name", email = "your@email.com" }
]
# 项目的关键词,有助于在PyPI上被搜索到。
keywords = ["cli", "demo", "uv", "ccyy"]
# 可以添加一些有用的链接,比如项目主页、文档、代码仓库等
[project.urls]
Homepage = "https://github.com/your-username/ccyy-demo"
Repository = "https://github.com/your-username/ccyy-demo"
Bug Tracker = "https://github.com/your-username/ccyy-demo/issues"
# 列表定义了项目运行所必需的核心依赖,这些包会在用户安装项目时自动安装
dependencies = [
"xxx>=8.0",
]
# 定义了安装包后可执行的命令行脚本,当用户安装包后,就可以直接在终端中运行这里的命令
# 格式: `command-name = "path.to.module:function_name"`
[project.scripts]
ccyy-mcp = "ccyy_demo.main:main"
# 定义了可选的依赖组,这对于区分开发环境、测试环境和生产环境的依赖非常有用
[project.optional-dependencies]
# "dev" 组通常包含开发过程中需要的工具,如代码检查、格式化、测试等
# 用户可以通过 `pip install .[dev]` 来安装这些依赖
dev = [
"ruff", # 高性能的代码检查和格式化工具
"pytest", # 强大的 Python 测试框架
"mypy", # 静态类型检查工具
]
# 定义了项目的构建工具。这是pyproject.toml的强制性部分,告诉pip等工具如何构建项目包
[build-system]
# requires指定构建项目所需的包列表。
# "hatchling"是一个现代、快速且功能强大的Python项目构建后端
requires = ["hatchling"]
# build-backend指定用于执行构建过程的Python对象
build-backend = "hatchling.build"
使用uv
安装依赖
uv init
已经创建了虚拟环境。只需激活它并安装依赖。激活成功后,会在终端提示符前看到 (.venv)
的字样。
bash
# 1. 激活虚拟环境
# Windows (CMD)
.venv\Scripts\activate
# macOS / Linux
source .venv/bin/activate
# 2. 安装项目依赖
uv pip install -e .[dev]
# 3.如果只想安装运行时的核心依赖,可以省略 `[dev]`
uv pip install -e .
命令解析:
-
-e
: 可编辑模式。这是开发的核心。它会创建一个指向你源代码的链接,而不是复制文件。这意味着你对源代码的任何修改都会立刻生效,无需重新安装 -
.
: 代表当前目录下的项目 -
[dev]
: 告诉安装器,除了项目的基本依赖外,还要安装[project.optional-dependencies]
中dev
组的所有包
本地运行和测试
由于在 [project.scripts]
中定义了ccyy-demo
,所以在安装后(特别是可编辑模式下,-e
模式),可以直接在终端中运行它。
bash
# 直接运行,使用默认参数 "World"
ccyy-demo
# > Hello, World! This is ccyy-demo speaking.
# 传入参数
ccyy-demo --name Jack
# > Hello, Jack! This is ccyy-demo speaking.
依赖锁定
在发布前,生成一个精确的依赖锁文件,以保证生产环境的确定性。
1.编译生产依赖
直接编译
pyproject.toml
,uv会自动读取[project.dependencies]
部分。
bash
uv pip compile pyproject.toml -o requirements.txt
2.编译开发依赖
编译可选依赖。如果想为开发环境生成一个锁定文件,可以使用
--extra
标志。
bash
uv pip compile pyproject.toml --extra dev -o dev-requirements.txt
为了确保开发依赖和生产依赖的版本兼容,通常会让开发依赖文件引用生产依赖文件:
编译时,让dev-requirements.txt引用并遵循requirements.txt中的版本约束
bash
uv pip compile pyproject.toml --extra dev -o dev-requirements.txt -c requirements.txt
3.安装锁定的依赖
一旦有了
requirements.txt
文件,就可以使用uv pip sync
来安装它。sync
命令会确保虚拟环境与requirements.txt
文件完全一致,不多也不少。
bash
# 激活虚拟环境
# Linux/Mac
source .venv/bin/activate
# Windows:
.venv\Scripts\activate
# 使用 sync 安装锁定的依赖
uv pip sync -r requirements.txt
构建
使用 uv build
命令来构建项目。这个命令会创建一个源代码发行版 (tar.gz
) 和一个wheel
文件,被放置在项目根目录下的一个名为dist的文件夹里
bash
uv build
还可以通过传递参数来指定构建的wheel的目标Python版本:
bash
uv build --python 3.9
更多关于uv build
的使用参考帮助命令
bash
uv build -h
发布
首先,访问Pypi官网,在Account settings
菜单栏下找到API tokens并执行Add API token进行添加一个Token 然后,可以使用
uv publish
命令将包发布到PyPI或其他包索引。
bash
uv publish --token Token
更多关于uv publish
的使用参考帮助命令
bash
uv publish -h
生产环境实践之CI/CD
自动化测试和发布是生产级项目的标配,以GitHub Actions为例。
创建工作流配置文件
1.通过GitHub网页界面创建
bash
进入 GitHub 仓库
点击 "Add file" → "Create new file"
在文件名输入框中输入:.github/workflows/publish.yml
将 YAML 配置内容粘贴到编辑器中
点击 "Commit new file"
2.通过本地Git创建并推送到远程仓库
bash
# 在项目根目录创建文件夹结构
mkdir -p .github/workflows
# 创建配置文件
touch .github/workflows/publish.yml
publish.yml
具体配置内容如下:
yaml
# --------------------------------------------------
# 工作流的全局配置
# --------------------------------------------------
# name: 定义工作流的名称。这个名称会显示在你的 GitHub 仓库的 "Actions" 标签页中,方便识别和管理这个自动化流程。
name: Publish Python Package to PyPI
# --------------------------------------------------
# 触发器 (Triggers)
# --------------------------------------------------
# on: 定义触发这个工作流的事件。可以配置多种触发条件。
on:
# push: 表示当代码被推送到仓库时触发。
push:
# tags: 进一步限制,只有当推送的是一个 "标签 (tag)" 时才触发。
# 这是一种常见的发布策略,确保只有打了版本标签的提交才会被发布。
tags:
# - 'v*': 这是一个模式匹配规则。'*' 是通配符。
# 意味着只有当标签以 'v' 开头时(例如 v1.0, v2.1.3),这个工作流才会被触发。
# 推送普通的代码提交或不匹配的标签(如 'release-1')不会触发此流程。
- 'v*'
# --------------------------------------------------
# 任务 (Jobs)
# --------------------------------------------------
# jobs: 定义工作流中要执行的一个或多个任务。
# 任务可以并行或按顺序运行。这里我们只有一个名为 "publish" 的任务。
jobs:
# publish: 这是我们为这个任务写的唯一标识符(ID)。你可以自定义,如 'deploy'。
publish:
# name: 为任务定义一个更友好的显示名称,它会显示在 GitHub Actions 的 UI 界面中。
name: Build and publish to PyPI
# runs-on: 指定运行这个任务的虚拟机环境。
# GitHub 会提供临时的云服务器来执行任务。
# 'ubuntu-latest' 表示使用最新稳定版的 Ubuntu Linux 系统,这是 Python 项目最常用的环境。
runs-on: ubuntu-latest
# --------------------------------------------------
# 步骤 (Steps)
# --------------------------------------------------
# steps: 定义了构成这个任务的一系列按顺序执行的步骤。
# 每个步骤可以是一个独立的命令,也可以是使用一个预定义的 "Action"。
steps:
# 步骤 1: 检出代码
# - name: (可选) 为步骤提供一个描述性名称,会显示在日志中。
- name: Check out repository
# uses: 指定使用一个社区或官方提供的可复用 Action。
# 'actions/checkout@v4' 是一个官方 Action,
# 它的功能是将你的仓库代码下载到虚拟机的工作目录中,以便后续步骤可以访问它。
uses: actions/checkout@v4
# 步骤 2: 设置 Python 环境
- name: Set up Python
# 'actions/setup-python@v5' 是另一个官方 Action,
# 专门用于在虚拟机中安装并配置指定版本的 Python。
uses: actions/setup-python@v5
# with: 用于向 Action 传递参数。
with:
# python-version: 指定要安装的 Python 版本。
# 建议使用你的项目所支持和测试过的具体版本。
python-version: '3.11'
# 步骤 3: 安装 uv 工具
# uv 是一个由 Astral 开发的高性能 Python 包管理工具,可以替代 pip、pip-tools、virtualenv 和 venv。
# 它以极快的速度著称,在这里我们用它来构建和发布包。
- name: Install uv publishing tool
# 'astral-sh/setup-uv@v2' 是 uv 官方提供的 Action,用于在环境中快速安装 uv。
uses: astral-sh/setup-uv@v2
with:
# version: 指定要安装的 uv 版本,'latest' 表示始终使用最新版。
version: "latest"
# 步骤 4: 构建包
# 在发布之前,需要将项目源代码打包成标准的 Python 发行版格式(sdist 和 wheel)。
- name: Build package
# run: 指定直接在虚拟机的命令行 (shell) 中执行一条命令。
# 'uv build' 会读取项目根目录下的 'pyproject.toml' 文件,
# 然后在 'dist/' 目录下生成 .whl (wheel) 和 .tar.gz (sdist) 文件。
run: uv build
# 步骤 5: 发布到 PyPI
# 这是最后一步,将构建好的包上传到 Python 包索引 (PyPI)。
- name: Publish package to PyPI
# 'uv publish' 命令会自动查找 'dist/' 目录下的包文件并上传。
# '--token' 是一个命令行参数,用于提供认证凭据。
# '${{ secrets.PYPI_API_TOKEN }}' 是 GitHub Actions 的特殊语法,用于安全地引用密钥。
# 它会从你仓库的 "Settings -> Secrets and variables -> Actions" 中读取名为 'PYPI_API_TOKEN' 的值。
# 使用 Secrets 可以确保你的 API Token 不会暴露在代码或公开的日志中。
run: uv publish --token ${{ secrets.PYPI_API_TOKEN }}
配置GitHub Secrets
进入GitHub仓库
makefile
点击Settings > Secrets and variables > Actions
在Repository secrets部分,创建一个名为 PYPI_API_TOKEN 的 Secret
Name: 必须为PYPI_API_TOKEN,需与工作流配置文件中保持一致
Secret: 粘贴从PyPI官网复制的、以 pypi- 开头的完整 Token
点击 Add secret

创建和推送tag
bash
# 打标签
git tag v1.0.0
# 推送标签到远程仓库
git push origin v1.0.0
验证发布
推送tag后,进入 GitHub 仓库的 Actions 标签页 查看 Publish to PyPI 工作流的运行状态
如果成功,构建的包将出现在 PyPI 上
生产环境实践之Docker
创建Dockerfile
根据上述Python CLI应用创建对应适合的Dockerfile文件
yaml
# 1. 选择一个基础镜像 使用UV官方提供的镜像
FROM ghcr.io/astral-sh/uv:python3.11-alpine
# 2. 设置工作目录
# 在容器内创建一个 /app 目录,并将其设置为后续所有命令的执行目录。
WORKDIR /app
# 3. 复制所有项目文件
# 将本地项目目录下的所有文件复制到容器的 /app 目录中。
# '.' 代表本地的当前目录,第二个 '.' 代表容器内的工作目录 (/app)。
COPY . .
# 4.创建虚拟环境并安装依赖
RUN uv sync
# 5. 激活虚拟环境(设置PATH)
ENV PATH="/app/.venv/bin:$PATH"
# 6. 设置容器启动时要执行的默认命令
# 当运行 `docker run <镜像名>` 时,容器会自动执行这个命令。
CMD ["ccyy-demo", "--name", "Docker User"]
构建镜像
bash
root@master:~/ccyy_demo# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
demo 0.1 59c234aaad24 3 minutes ago 105MB
运行容器
bash
root@master:~/ccyy_demo# docker run demo:0.1
Hello, Docker User! This is ccyy-demo speaking.