谷中仁谷中仁的博客

Uncategorized

使用uv来更好的管理你的python依赖

痛点

在Python 项目开发过程中,我们肯定会用到requirements.txt 来管理项目中所用到的第三方库,这么多年都是这么过来的,那有什么痛点呢?

  • 你的requirements.txt 中是不是多了一些莫名其妙的依赖,你还不敢删除
  • 你不知道其中的某个依赖是因为哪个依赖引入进来的,或者被哪个依赖所引用
  • 每次运行命令生成这个文件,还得去瞅一下是不是正确,有时候,不同的人生成的顺序还不一样

你是不是也是经常遇到?

工具介绍

pyproject.toml

pyproject.toml 文件是定义项目配置的 Python 标准。

NodeJS 项目中的 package.json 一样,可以管理第三方依赖,可以存储可以运行的命令,所使用的 Runtime 的版本号限制和项目的基本信息等等的,功能强大可见一斑。

uv

uv

An extremely fast Python package and project manager, written in Rust.(一个极快的 Python 包和项目管理器,用 Rust 编写。) — https://docs.astral.sh/uv/

速度快是其特点,但是使用也是相当方便。而且文档相当详细。

如何使用

mkdir py-uv
cd py-uv/
uv init
# Initialized project `py-uv`
uv venv
# Using CPython 3.13.2
# Creating virtual environment at: .venv
# Activate with: source .venv/bin/activate
source .venv/bin/activate
gst
# On branch main
#
# No commits yet
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
# 	.gitignore
# 	.python-version
# 	README.md
# 	hello.py
# 	pyproject.toml
#
#nothing added to commit but untracked files present (use "git add" to track)
uv run hello.py
# Using CPython 3.13.2
# Creating virtual environment at: .venv
# Hello from py-uv!
uv add pyfiglet
# Resolved 2 packages in 515ms
# Prepared 1 package in 532ms
# Installed 1 package in 7ms
#  + pyfiglet==1.0.3

这时,我们可以看看 pyproject.toml 中有哪些内容

[project]
name = "py-uv"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
    "pyfiglet>=1.0.3",
]

可以看到 pyfiglet 被添加到了 dependencies 中;其他的内容字如其意,就不展开讲了。

在源文件中添加一点 python 代码

diff --git a/hello.py b/hello.py
index b18db96..204b9e3 100644
--- a/hello.py
+++ b/hello.py
@@ -1,6 +1,12 @@
+import pyfiglet
+
 def main():
     print("Hello from py-uv!")
+    ascii_art = pyfiglet.figlet_format("MyApp Started!")
+    print(ascii_art)
+
 if __name__ == "__main__":
     main()
~

再次运行

uv run hello.py
# Hello from py-uv!
#  __  __          _                  ____  _             _           _ _
# |  \/  |_   _   / \   _ __  _ __   / ___|| |_ __ _ _ __| |_ ___  __| | |
# | |\/| | | | | / _ \ | '_ \| '_ \  \___ \| __/ _` | '__| __/ _ \/ _` | |
# | |  | | |_| |/ ___ \| |_) | |_) |  ___) | || (_| | |  | ||  __/ (_| |_|
# |_|  |_|\__, /_/   \_\ .__/| .__/  |____/ \__\__,_|_|   \__\___|\__,_(_)
#         |___/        |_|   |_|

至此,我们的项目已经使用 uv 运行起来了,但是在真正部署的时候我们需要生成 requirement.txt 然后启动程序。

生成 requirement.txt

在正式的开发项目中,我们不可能每个人手动生成一次,然后再提交,这样很可能忘记这个操作,最好的就是将其放在在 git hooks 中,在每次 push 代码之前生成并检查其已经存在且是最新的,这样每个人都避免了手动生成和校验。如下是一段 shell 脚本来实现该功能

# generate-requirements.sh
#!/bin/basa
set -euo pipefail
uv pip compile pyproject.toml --quiet --output-file requirements.txt
# Check for uncommitted changes
if [[ -n $(git status --porcelain) ]]; then
  echo "Error: There are uncommitted changes. Please commit or stash them before running this script."
  exit 1
fi

然后将其集成到 pre-commit 中, 使其在 push 前执行这个操作

- id: generate requirement.txt
  name: Generate requirements.txt
  entry: ./scripts/git-hooks/generate-requirements.sh
  language: script
  always_run: true
  stages: [pre-push]

如此可以将该流程完全自动化。

运行 git push 或者 ./scripts/git-hooks/generate-requirements.sh, 会自动生成 requirement.txt 文件, 内容如下:

# This file was autogenerated by uv via the following command:
#    uv pip compile pyproject.toml --output-file requirements.txt
pyfiglet==1.0.3
    # via py-uv (pyproject.toml)

{{< admonition tip “Note” true >}} 我从哪里来,我要去哪里 {{< /admonition >}}

其中的最后一行表明,pyfiglet 是被 py-uv 这个项目依赖的,也就是我们刚创建的这个项目;而在多个依赖的项目中,生成的 requirement.txt 也可能出现,一个不知名的依赖被多个依赖再次依赖,这就是使用 uv 工具生成 requirement.txt的好处。

总结

好的工具的选择可以为工程构建增速提效。 工具的组合更是可以产生解放生产力。

full-text search

Type at least 2 characters to search.