惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Secure Thoughts
Security Latest
Security Latest
Simon Willison's Weblog
Simon Willison's Weblog
O
OpenAI News
GbyAI
GbyAI
L
LINUX DO - 最新话题
A
Arctic Wolf
T
Tor Project blog
G
GRAHAM CLULEY
I
InfoQ
博客园_首页
IT之家
IT之家
The Register - Security
The Register - Security
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
P
Proofpoint News Feed
The GitHub Blog
The GitHub Blog
Blog — PlanetScale
Blog — PlanetScale
N
Netflix TechBlog - Medium
K
Kaspersky official blog
博客园 - 三生石上(FineUI控件)
S
SegmentFault 最新的问题
U
Unit 42
PCI Perspectives
PCI Perspectives
量子位
P
Palo Alto Networks Blog
S
Securelist
T
Troy Hunt's Blog
博客园 - 【当耐特】
Recorded Future
Recorded Future
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
S
Security Affairs
Engineering at Meta
Engineering at Meta
T
The Blog of Author Tim Ferriss
博客园 - 聂微东
罗磊的独立博客
N
News and Events Feed by Topic
人人都是产品经理
人人都是产品经理
B
Blog RSS Feed
NISL@THU
NISL@THU
C
Cisco Blogs
T
Threatpost
有赞技术团队
有赞技术团队
Forbes - Security
Forbes - Security
Hugging Face - Blog
Hugging Face - Blog
Last Week in AI
Last Week in AI
T
The Exploit Database - CXSecurity.com
Cloudbric
Cloudbric
Cyberwarzone
Cyberwarzone
Google DeepMind News
Google DeepMind News
C
Cyber Attacks, Cyber Crime and Cyber Security

小陈同学 - 后端

用 NumPy 玩转电影评分系统:从随机数据到洞察分析 NumPy 进阶:搞懂广播机制,才能真正玩转数组 NumPy 入门:别再用 for 循环折磨自己了 uv:用 Rust 武装的极速 Python 包管理器入门指南 NodeJs连接MongoDB以及操作方法 NodeJs基于Token的身份认证
从 requirements.txt 到 pyproject.toml:现代 Python 项目升级实战指南(含依赖分析与 Docker)
Caleb · 2025-10-29 · via 小陈同学 - 后端

用 pipdeptree 清理顶级依赖,再用 uv 迁移至 pyproject.toml 并锁定版本,实现可复现、可部署的现代 Python 依赖管理。

pyproject.png

🧱 一、现实问题:requirements.txt 的“依赖泥潭”

在老项目中,常见的现象是这样的:

$ pip list
Package         Version
--------------- --------
numpy           1.24.3
pandas          2.0.1
requests        2.31.0
urllib3         2.0.4
charset-normalizer 3.2.0
idna            3.4
fastapi         0.95.2
uvicorn         0.22.0
pydantic        1.10.11
...

看起来一切正常,其实乱得很。
因为 requirements.txt 里可能只有 3~5 个包:

fastapi==0.95.2
pandas==2.0.1
uvicorn==0.22.0

pip list 却列出了几十个依赖。这时有两个关键问题:

  1. 哪些是项目自己需要的?
  2. 哪些是​依赖的依赖(transitive dependencies)

我们要在迁移前先把这些关系理清,否则迁移到 pyproject.toml 之后仍旧是混乱的。

🧩 二、精准识别“主依赖” vs “传递依赖”

1️⃣ 使用 pipdeptree 分析依赖树

安装:

pip install pipdeptree

查看依赖层级:

pipdeptree --warn silence

示例输出:

fastapi==0.95.2
  - pydantic [required: <2.0.0, installed: 1.10.11]
  - starlette [required: <1.0.0, installed: 0.27.0]
pandas==2.0.1
  - numpy [required: >=1.20.3, installed: 1.24.3]
  - python-dateutil [installed: 2.8.2]
  - pytz [installed: 2023.3]
uvicorn==0.22.0
  - click [installed: 8.1.3]
  - h11 [installed: 0.14.0]

👉 很明显,fastapipandasuvicorn 是你主动安装的;
其余如 pydanticnumpystarlette 等都是“传递依赖”。

Tip: 你可以用 pipdeptree --reverse 反查:哪个包依赖了这个库。

🧮 三、清理并锁定顶级依赖

1️⃣ 提取顶级包

pip freeze > all.txt
pipdeptree --warn silence --freeze > tree.txt

打开 tree.txt,手动(或脚本)过滤掉那些被其他包引用的依赖。

最终保留的核心依赖(即​顶级包​)写入新的 requirements.txt

fastapi==0.95.2
pandas==2.0.1
uvicorn==0.22.0

2️⃣ 验证清理是否正确

先创建个全新虚拟环境:

python -m venv cleanenv
source cleanenv/bin/activate
pip install -r requirements.txt
pipdeptree

如果依赖树和原项目行为一致,你的“核心依赖集”就整理对了。

🧭 四、迁移到 pyproject.toml + uv

安装 uv(强烈推荐):

curl -LsSf https://astral.sh/uv/install.sh | sh

初始化:

uv init

导入依赖:

uv add --from-requirements requirements.txt

查看结果(生成的 pyproject.toml):

[project]
name = "movie-analyzer"
version = "0.1.0"
dependencies = [
    "fastapi==0.95.2",
    "pandas==2.0.1",
    "uvicorn==0.22.0",
]
requires-python = ">=3.10"

🧰 五、验证和同步依赖

锁定依赖版本:

uv lock

安装依赖:

uv sync

验证运行:

uv run python main.py
uv 会自动生成 .venvuv.lock,确保依赖一致性。
即使协作者在另一台机器,也能完美复现同样的环境。

🧱 六、用 Docker 打包部署

这是最通用、最干净的构建方式。

FROM python:3.11-slim AS base

# 安装 uv
RUN pip install uv

WORKDIR /app

# 拷贝依赖文件
COPY pyproject.toml uv.lock ./

# 安装依赖
RUN uv sync --frozen --no-cache

# 拷贝源码
COPY src ./src

# 入口命令
CMD ["uv", "run", "fastapi", "run", "--host", "0.0.0.0", "--port", "8000"]

构建镜像:

docker build -t docker-test .

运行容器:

docker run -p 8000:8000 docker-test

🔍 七、附:自动识别“顶级依赖”的脚本

如果你懒得手动筛选,可以用这个 Python 脚本快速过滤:

import subprocess

def get_top_level_packages():
    output = subprocess.check_output(["pipdeptree", "--warn", "silence"]).decode()
    top_level = []
    for line in output.splitlines():
        if not line.startswith(" "):  # 顶级包
            pkg = line.split("==")[0]
            top_level.append(pkg)
    return top_level

if __name__ == "__main__":
    for pkg in get_top_level_packages():
        print(pkg)

执行:

python find_top_deps.py > clean_requirements.txt

它会自动生成仅包含“主依赖”的 requirements.txt。

⚡ 八、实战总结

步骤工具作用
依赖分析pipdeptree查出依赖关系树
顶级提取脚本 or 手动确定哪些是核心依赖
环境验证venv+pip install确认依赖可重现
现代化迁移uv init + add生成 pyproject.toml
锁定同步uv lock + sync可重复依赖管理
部署打包Docker + uv一致性环境交付

🧠 九、总结

“requirements.txt 是笔记本,而 pyproject.toml 是配置中心。”

通过 pipdeptree 清理依赖、再用 uv 统一管理,
你能把老项目彻底从“依赖泥潭”里拔出来,
同时获得更快的安装、更好的团队协作与更稳定的部署。

作者: 文章链接: https://reinness.com/posts/313 版权声明:  本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自小陈同学