从零开始带你使用Python开发一个命令行工具

 更新时间:2026年02月27日 09:34:02   作者:SunnyRivers  
在现代 Python 开发生态中,命令行工具CLI是自动化,脚本化和工具链集成的核心,下面我们就来看看如何借助uv和 PyPI快速开发并打包发布一个 CLI 工具吧

在现代 Python 开发生态中,命令行工具(CLI)是自动化、脚本化和工具链集成的核心。借助 uv(超快的 Python 包管理器)和 PyPI,我们可以快速开发、打包、发布一个 CLI 工具,并让用户无需安装 Python 环境就能通过 uvx 直接运行!

本文将带你完成整个流程:

  • 开发一个最简 CLI 工具
  • 使用标准 src/ 项目结构
  • 打包并发布到 PyPI
  • 用户通过 uvx xccli 一键使用

为什么选择 uv + pyproject.toml

  • uv 是由 Astral 开发的超快 Python 包安装器(比 pip 快 10–100 倍)
  • uvx 可以直接运行 PyPI 上的 CLI 工具,无需 pip install
  • pyproject.toml 是现代 Python 项目的标准配置文件(取代 setup.py)
  • src/ 布局 避免开发时意外导入本地模块,更安全

开发一个简单的命令行工具:mycli

我们要创建的工具叫 mycli,运行后输出一句问候。

1. 创建项目结构

mkdir my-uv-demo
cd my-uv-demo

目录结构如下:

my-uv-demo/
├── pyproject.toml
└── src/
    └── my_uv_demo/
        ├── __init__.py
        └── mycli.py

2. 编写核心逻辑:src/my_uv_demo/mycli.py

def main():
    print("Hello from mycli! ✨")

if __name__ == "__main__":
    main()

3. 配置 pyproject.toml

[project]
name = "my-uv-demo"               # PyPI 上的包名(需唯一)
version = "0.1.0"
description = "A simple CLI tool built with uv"
authors = [{name = "Your Name", email = "you@example.com"}]
requires-python = ">=3.12"
license = {text = "MIT"}
readme = "README.md"

# 定义命令行入口:mycli -> 调用 my_uv_demo.xccli:main
[project.scripts]
xccli = "my_uv_demo.mycli:main"

# 指定源码在 src/ 下
[tool.hatch.build.targets.wheel]
packages = ["src/my_uv_demo"]

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

4. 本地测试(使用 uvx)

在项目根目录运行:

uvx --from . mycli

输出:

Hello from mycli! ✨

这说明你的 CLI 工具已能正常工作!

用户如何使用你的工具

一旦发布成功,任何安装了 uv 的用户都可以直接运行:

uvx xccli

无需:

  • 安装 Python(如果系统已有)
  • 创建虚拟环境
  • 手动 pip install

uvx 会自动:

  • 从 PyPI 下载你的包
  • 解析依赖(本例无依赖)
  • 在隔离环境中运行 xccli 命令

输出依然是:

Hello from mycli! ✨

这就是现代 Python 工具分发的极致体验!

详解原理

一旦发布成功,为什么uvx xccli 直接执行就可以运行?它是怎么找到这个xccli工具的?

一句话回答:uvx xccli 能直接运行,是因为 uvx 会自动在 PyPI 上查找哪个已发布的 Python 包提供了名为 xccli 的可执行脚本(entry point),然后下载、安装并运行它。

这依赖于两个核心机制:

  • PyPI 包的元数据中声明了 console_scripts(即 [project.scripts])
  • uvx 能解析这些元数据,并按需构建临时环境来执行命令

详细原理分解

第一步:你的包在 PyPI 上“注册”了 mycli 命令

当你在 pyproject.toml 中写:

[project.scripts]
mycli = "my_uv_demo.mycli:main"

打包工具(如 hatchling)会在生成的 wheel(.whl 文件)中,将这条信息写入 entry_points.txt 元数据文件,内容类似:

[console_scripts]
mycli = my_uv_demo.mycli:main

当你发布到 PyPI 后,这个元数据就公开可查。

这个机制最早来自 setuptools 的 console_scripts,现在是标准(PEP 621)。

第二步:用户运行 uvx xccli

当用户输入:

uvx mycli

uvx 会执行以下步骤:

1.查询 PyPI:哪个包提供了 xccli?

uvx 会向 PyPI 的 API 发起请求(或使用本地缓存),查找所有已发布包中,console_scripts 包含 xccli 的包。

例如,它发现:

  • 包 my-uv-demo(你发布的)声明了 xccli = …
  • 没有其他包冲突(如果有多个,会报错或让用户指定)

注意:uvx 不是靠包名找命令,而是靠 命令名 → 反查提供者。

2.下载并安装该包到隔离环境

uvx 会:

  • 创建一个临时虚拟环境(或复用缓存)
  • 用 uv pip install my-uv-demo 安装你的包(及其依赖)
  • 安装过程中,pip/uv 会根据 console_scripts 自动生成一个可执行文件(如 xccli 或 xccli.exe)并放入环境的 bin/ 目录

3.直接执行该命令

最后,uvx 直接调用这个 xccli 可执行文件,等价于:

/path/to/temp-env/bin/mycli

但对用户完全透明!

验证:手动查看 PyPI 包的 entry points

你可以用 pip show 查看任意已安装包的脚本:

pip install my-uv-demo  # 假设你已发布
pip show -f my-uv-demo | grep mycli

或者用 uv:

uv pip show -f my-uv-demo

你会看到类似:

console-scripts:
  xccli = my_uv_demo.xccli:main

常见问题 & 注意事项

Q1:如果两个包都定义了 xccli 怎么办?

A:uvx 会报错,提示冲突。因此命令名最好具有唯一性或品牌标识(如 black、ruff、poetry)。

Q2:为什么不能直接用包名运行?比如 uvx my-uv-demo?

A:因为包名 ≠ 命令名。一个包可以提供多个命令(如 git 提供 git, git-receive-pack 等),所以必须通过命令名定位。

Q3:uvx 会不会每次都下载?

A:不会!uvx 会缓存已安装的工具(默认在 ~/.cache/uv/tools/),下次运行极快。

总结

步骤命令/操作
初始化项目创建 src/ 结构 + pyproject.toml
本地测试uvx --from . mycli
打包uv build
发布uv publish(需 PyPI Token)
用户使用uvx mycli

通过这套流程,你不仅开发了一个 CLI 工具,还让它像 npm 全局命令一样简单易用,但速度更快、依赖更干净。

到此这篇关于从零开始带你使用Python开发一个命令行工具的文章就介绍到这了,更多相关Python命令行工具内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

最新评论