Skip to content

Python Poetry:现代依赖管理与打包指南

Updated on

管理 Python 依赖不应该是一件痛苦的事。但每个 Python 开发者都经历过这样的场景:你 clone 了一个项目,运行 pip install -r requirements.txt,然后看着依赖冲突在终端里连环爆炸。包 A 需要某个库的 1.x 版本,包 B 需要 2.x 版本,而 pip 会安装它最后“算出来”的那个版本——悄无声息地把另一个包弄坏。接下来就是数小时的排查与调试,而这一切都源于 pip 缺乏完善的依赖解析器与 lock 文件机制。

在团队协作中,这个问题会被进一步放大:一个开发者固定了精确版本,另一个使用了宽松范围,第三个人装了新包却忘了更新 requirements.txt。部署失败;本地测试通过但 CI 崩了。根因几乎永远相同:Python 的默认工具链把依赖管理当成了事后补救。

Poetry 通过提供一个统一的工具来解决这些问题:它同时负责依赖解析、虚拟环境管理以及包发布。它以标准化的 pyproject.toml 为核心,生成确定性的 lock 文件,并在安装前就解决依赖冲突——而不是装完才发现问题。本指南将覆盖从安装到发布的完整流程,并为每种常见工作流提供实用示例。

📚

什么是 Python Poetry?

Poetry 是一个用于 Python 的开源依赖管理与打包工具,由 Sebastien Eustace 于 2018 年创建。它通过将多个功能整合到一个一致的工具中,改善了 Python 打包生态长期碎片化的现状:

  • 依赖解析:Poetry 会在安装任何东西之前,分析所有依赖及其子依赖,找出兼容的版本组合。
  • Lock 文件poetry.lock 记录每个已安装包的精确版本,保证在不同机器上构建结果可复现。
  • 虚拟环境管理:Poetry 会为每个项目自动创建并管理隔离的虚拟环境。
  • 构建与发布:Poetry 可以构建 sdist 与 wheel,并直接发布到 PyPI 或私有仓库。
  • 项目脚手架:Poetry 能生成项目结构,并提供正确的 pyproject.toml 配置。

Poetry 使用 pyproject.toml 作为配置文件,遵循 PEP 518 与 PEP 621 标准。它取代了传统 Python 项目常见的 setup.pysetup.cfgrequirements.txtMANIFEST.in 等组合式配置。

安装 Poetry

Poetry 提供了自己的安装器,用于将 Poetry 本身与项目依赖隔离开,避免 Poetry 和项目包之间产生版本冲突。

推荐安装方式(官方安装器)

Linux、macOS 和 Windows(WSL)

curl -sSL https://install.python-poetry.org | python3 -

Windows(PowerShell)

(Invoke-WebRequest -Uri https://install.python-poetry.org -UseBasicParsing).Content | py -

安装完成后,将 Poetry 加入 PATH。安装器会输出准确路径——通常 Linux/macOS 是 $HOME/.local/bin,Windows 是 %APPDATA%\Python\Scripts

验证安装:

poetry --version

使用 pipx 安装

如果你更喜欢 pipx(同样能隔离 CLI 工具):

pipx install poetry

更新 Poetry

poetry self update

更新到指定版本:

poetry self update 1.8.0

启用 Tab 补全

Poetry 支持 Bash、Zsh、Fish 的补全:

# Bash
poetry completions bash >> ~/.bash_completion
 
# Zsh
poetry completions zsh > ~/.zfunc/_poetry
 
# Fish
poetry completions fish > ~/.config/fish/completions/poetry.fish

创建新项目

Poetry 提供两种开始方式:从零创建新项目,或在已有项目中初始化 Poetry。

从零创建新项目

poetry new my-project

将生成以下结构:

my-project/
├── pyproject.toml
├── README.md
├── my_project/
│   └── __init__.py
└── tests/
    └── __init__.py

如果你偏好更“扁平”的源代码布局(包放在根目录):

poetry new --src my-project

这会把包放到 src/ 目录中:

my-project/
├── pyproject.toml
├── README.md
├── src/
│   └── my_project/
│       └── __init__.py
└── tests/
    └── __init__.py

在已有项目中初始化

进入已有项目目录后运行:

cd existing-project
poetry init

Poetry 会以交互式向导询问包名、版本、描述、作者、Python 版本兼容范围与依赖等。你可以直接回车接受默认值,或跳过可选字段。

非交互式初始化:

poetry init --name my-package --description "A useful package" --author "Your Name <you@example.com>" --python "^3.9" --no-interaction

理解 pyproject.toml

pyproject.toml 是项目配置的单一事实来源(single source of truth)。下面是一个完整示例:

[tool.poetry]
name = "my-project"
version = "1.0.0"
description = "A data processing library"
authors = ["Your Name <you@example.com>"]
license = "MIT"
readme = "README.md"
homepage = "https://github.com/yourname/my-project"
repository = "https://github.com/yourname/my-project"
keywords = ["data", "processing", "analytics"]
classifiers = [
    "Development Status :: 4 - Beta",
    "Intended Audience :: Developers",
    "Topic :: Software Development :: Libraries",
]
 
[tool.poetry.dependencies]
python = "^3.9"
pandas = "^2.0"
requests = "^2.31"
pydantic = ">=2.0,<3.0"
 
[tool.poetry.group.dev.dependencies]
pytest = "^8.0"
black = "^24.0"
mypy = "^1.0"
ruff = "^0.3"
 
[tool.poetry.group.docs.dependencies]
sphinx = "^7.0"
sphinx-rtd-theme = "^2.0"
 
[tool.poetry.scripts]
my-cli = "my_project.cli:main"
 
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

版本约束语法

Poetry 使用清晰的版本约束语法:

ConstraintMeaningAllows
^2.0兼容版本(compatible release)>=2.0.0, <3.0.0
^2.1.3兼容版本(patch)>=2.1.3, <3.0.0
~2.1近似范围(approximately)>=2.1.0, <2.2.0
>=2.0,<3.0范围(range)显式上下界
2.1.3精确版本(exact)2.1.3
>=2.0最小版本(minimum)2.0 及以上
*任意(any)所有版本

插入符号(^)约束最常见也最推荐。它遵循语义化版本(semantic versioning)原则,允许不改变最左侧非零位的更新。

依赖分组(Dependency Groups)

Poetry 通过分组组织依赖,替代了多个 requirements 文件的做法:

  • 主依赖[tool.poetry.dependencies]):包正常运行所需的依赖。别人安装你的包时会包含这些依赖。
  • 开发依赖[tool.poetry.group.dev.dependencies]):开发、测试、lint 等工具。发布的包不会包含它们。
  • 自定义分组[tool.poetry.group.docs.dependencies]):按需添加的任何分组,例如文档工具。

添加与移除依赖

添加包

添加到主依赖:

poetry add pandas

带版本约束添加:

poetry add "pandas>=2.0,<3.0"

添加到 dev 组:

poetry add --group dev pytest black ruff

添加到自定义组:

poetry add --group docs sphinx

从 Git 仓库添加依赖:

poetry add git+https://github.com/user/repo.git

从指定分支或 tag 添加:

poetry add git+https://github.com/user/repo.git#branch-name
poetry add git+https://github.com/user/repo.git#v1.0.0

添加本地路径依赖:

poetry add ../my-local-package

为某个包添加 extras:

poetry add "uvicorn[standard]"

移除包

移除一个包:

poetry remove pandas

从指定分组移除:

poetry remove --group dev black

查看已安装包

查看所有已安装包:

poetry show

查看某个包的详情:

poetry show pandas

显示依赖树:

poetry show --tree

显示可更新的包:

poetry show --outdated

Lock 文件:poetry.lock

poetry.lock 是 Poetry 最重要的特性之一。当你运行 poetry installpoetry add 时,Poetry 会解析所有依赖,并把精确版本(包含所有传递依赖)写入 poetry.lock

为什么 lock 文件很重要

没有 lock 文件时,使用 pip install -r requirements.txt 配合宽松版本约束,可能在不同机器或不同时间得到不同的安装结果。lock 文件消除了这种随机性。

例如:

[tool.poetry.dependencies]
requests = "^2.28"

这允许从 2.28.0 到 2.99.x 的任何版本。没有 lock 文件,你的 CI 可能安装 2.31.0,而你本地是 2.28.2。lock 文件会把所有环境固定到同一个精确版本。

lock 文件工作流

将 poetry.lock 提交到版本控制。 这能保证每个开发者与每次部署使用完全一致的包版本。

git add poetry.lock pyproject.toml
git commit -m "Add project dependencies"

按 lock 文件安装(用于可复现安装):

poetry install

这会严格安装 poetry.lock 中指定的版本,忽略任何更新的兼容版本。

当你想升级依赖时再更新 lock 文件

# 更新所有包
poetry update
 
# 更新某个包
poetry update pandas
 
# 只更新 lock 文件但不安装
poetry lock

校验 lock 文件一致性

poetry lock --check

它会确认 lock 文件与 pyproject.toml 一致,但不会修改任何内容。

虚拟环境管理

Poetry 会自动为项目创建并管理虚拟环境。

默认行为

当你运行 poetry installpoetry add 时,如果虚拟环境不存在,Poetry 会创建它。默认情况下环境存放在集中缓存目录:

  • Linux: ~/.cache/pypoetry/virtualenvs/
  • macOS: ~/Library/Caches/pypoetry/virtualenvs/
  • Windows: C:\Users\<user>\AppData\Local\pypoetry\Cache\virtualenvs\

项目内虚拟环境(In-Project)

很多开发者更喜欢把虚拟环境放在项目目录里(类似 Node.js 的 node_modules)。可全局配置:

poetry config virtualenvs.in-project true

这样会在项目根目录创建 .venv,更易发现,也更方便 IDE 自动识别。

在虚拟环境中运行命令

运行单条命令

poetry run python my_script.py
poetry run pytest
poetry run black .

进入虚拟环境 shell

poetry shell

会启动一个已激活虚拟环境的新 shell。用 exitCtrl+D 退出。

环境信息

查看环境详情:

poetry env info

列出该项目相关的所有环境:

poetry env list

使用指定 Python 版本:

poetry env use python3.11

移除某个环境:

poetry env remove python3.11

安装依赖

标准安装

安装所有依赖(主依赖 + 开发依赖):

poetry install

生产环境安装

不安装开发依赖:

poetry install --without dev

不安装指定分组:

poetry install --without dev,docs

只安装特定分组

poetry install --only main
poetry install --only dev

同步环境(Sync)

移除 lock 文件中不存在的包(清理式安装):

poetry install --sync

这会删除手动安装的包或已不在 lock 文件中的包,让环境严格匹配项目配置。

构建与发布包

Poetry 简化了包发布的完整工作流。

构建你的包

poetry build

会在 dist/ 目录生成 sdist(.tar.gz)与 wheel(.whl):

dist/
├── my_project-1.0.0.tar.gz
└── my_project-1.0.0-py3-none-any.whl

发布到 PyPI

先配置 PyPI token:

poetry config pypi-token.pypi your-api-token

然后发布:

poetry publish --build

--build 会在一步中完成构建与发布。

发布到私有仓库

添加私有仓库:

poetry config repositories.private https://private.pypi.example.com/simple/
poetry config http-basic.private username password

发布到该仓库:

poetry publish --repository private

版本管理

按语义化版本升级:

poetry version patch    # 1.0.0 -> 1.0.1
poetry version minor    # 1.0.0 -> 1.1.0
poetry version major    # 1.0.0 -> 2.0.0
poetry version prepatch # 1.0.0 -> 1.0.1a0

显示当前版本:

poetry version

从 requirements.txt 迁移

如果你的项目目前使用 requirements.txt,迁移到 Poetry 也很直接。

第 1 步:初始化 Poetry

cd your-project
poetry init --no-interaction

第 2 步:从 requirements.txt 添加依赖

对于简单的 requirements 文件:

cat requirements.txt | xargs poetry add

对于包含版本约束的文件,建议手动添加或用迁移脚本:

import subprocess
 
with open("requirements.txt") as f:
    packages = []
    for line in f:
        line = line.strip()
        if line and not line.startswith("#") and not line.startswith("-"):
            packages.append(line)
 
if packages:
    subprocess.run(["poetry", "add"] + packages)

第 3 步:添加开发依赖

如果你有 requirements-dev.txt

cat requirements-dev.txt | xargs poetry add --group dev

第 4 步:验证与锁定

poetry install
poetry lock --check

第 5 步:清理旧文件

确认一切正常后,可以移除旧文件:

rm requirements.txt requirements-dev.txt setup.py setup.cfg

导出回 requirements.txt

如果出于兼容性需要(Docker 构建、遗留 CI 系统):

poetry export -f requirements.txt --output requirements.txt

包含开发依赖:

poetry export -f requirements.txt --with dev --output requirements-dev.txt

Poetry vs pip vs pipenv vs uv:对比

选择哪种依赖管理工具取决于项目需求。下面是详细对比:

FeaturePoetrypippipenvuv
Dependency resolution高级 SAT solver基础(自 2020 起 backtracking)中等高级,Rust 实现
Lock file有(poetry.lock无(手动 pip freeze有(Pipfile.lock有(uv.lock
Virtual env management自动手动(python -m venv自动自动
Build and publish内置需要 setuptools/twine内置
Config filepyproject.tomlrequirements.txtPipfilepyproject.toml
Speed中等快(几乎不解析)很快(Rust)
Python version management无(用 pyenv)有(内置)
Monorepo support有限N/A
Script runnerspoetry runpipenv runuv run
Maturity成熟(2018)接近标准工具链成熟(2017)较新(2024)
PEP compliancePEP 518, 621N/A私有格式PEP 518, 621
Community极大中等增长很快
Best for全生命周期打包简单脚本、遗留项目Web 应用极致速度工作流

何时选择哪种工具

选择 Poetry:当你需要完整的打包解决方案——依赖管理、构建、发布到 PyPI 都在一个工具里完成,并且希望有成熟生态与丰富文档时。

选择 pip:适合简单脚本、快速原型,或受限于只能使用标准工具链的场景。pip 仍是其他工具构建的基础。

选择 pipenv:适合 Web 应用,需要可复现环境,但不打算发布到 PyPI 的场景。Pipfile 格式能清晰区分开发与生产依赖。

选择 uv:当安装速度是优先级,或你想要一个同时管理 Python 版本的“一体化工具”时。uv 使用 Rust 编写,依赖解析明显更快;它兼容 pip,可作为替代品直接上手。

Poetry 配置与技巧

常用配置项

# 将虚拟环境存放在项目目录
poetry config virtualenvs.in-project true
 
# 新环境优先使用当前激活的 Python
poetry config virtualenvs.prefer-active-python true
 
# 禁用自动创建虚拟环境
poetry config virtualenvs.create false
 
# 查看所有配置
poetry config --list

Poetry 与 Docker

一个用于生产的 Dockerfile(使用 Poetry):

FROM python:3.12-slim
 
ENV POETRY_VERSION=1.8.0 \
    POETRY_HOME="/opt/poetry" \
    POETRY_VIRTUALENVS_CREATE=false \
    POETRY_NO_INTERACTION=1
 
RUN pip install poetry==$POETRY_VERSION
 
WORKDIR /app
 
COPY pyproject.toml poetry.lock ./
RUN poetry install --without dev --no-root
 
COPY . .
RUN poetry install --without dev
 
CMD ["python", "-m", "my_project"]

要点:

  • POETRY_VIRTUALENVS_CREATE=false 会跳过容器内的虚拟环境创建(容器本身已隔离)。
  • 先装依赖再拷源码,以利用 Docker layer 缓存。
  • poetry install 运行两次:第一次不安装项目本体(仅依赖),第二次安装项目本体。

Poetry 与 CI/CD

GitHub Actions 示例:

name: CI
 
on: [push, pull_request]
 
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - name: Install Poetry
        run: pip install poetry
      - name: Install dependencies
        run: poetry install
      - name: Run tests
        run: poetry run pytest
      - name: Run linting
        run: poetry run ruff check .

Poetry 在 Jupyter 工作流中

数据科学工作通常在 Jupyter notebook 中进行,而依赖管理在此场景下尤为关键。Poetry 能通过确保 notebook 使用正确环境来很好地融入 Jupyter 工作流。

在 Poetry 项目中安装 Jupyter:

poetry add --group dev jupyter ipykernel

将 Poetry 环境注册为 Jupyter kernel:

poetry run python -m ipykernel install --user --name=my-project

在 Poetry 环境中启动 Jupyter:

poetry run jupyter notebook

如果你希望获得更顺滑的 Jupyter 体验,同时具备自动依赖管理与 AI 辅助能力,RunCell (opens in a new tab) 提供了集成式环境,让你更专注于分析而不是环境配置。RunCell 会自动处理包安装与 kernel 管理,与 Poetry 的项目级依赖控制形成互补。

常用 Poetry 命令速查

CommandDescription
poetry new <name>创建新项目
poetry init在已有目录初始化
poetry add <pkg>添加依赖
poetry remove <pkg>移除依赖
poetry install安装所有依赖
poetry update更新依赖
poetry lock只更新 lock 文件
poetry show列出已安装包
poetry show --tree显示依赖树
poetry show --outdated显示可更新包
poetry build构建包
poetry publish发布到 PyPI
poetry run <cmd>在虚拟环境中运行命令
poetry shell激活虚拟环境 shell
poetry env info显示环境详情
poetry version <rule>升级项目版本
poetry export导出 requirements.txt
poetry config --list查看所有配置
poetry search <pkg>搜索包
poetry check校验 pyproject.toml

常见问题排查

依赖解析失败

问题:Poetry 找不到一组兼容版本。

SolverProblemError: ...unable to find compatible versions...

解决:放宽版本约束,或检查冲突依赖:

# 查看冲突来源
poetry show --tree
 
# 尝试更宽的约束
poetry add "problematic-package>=1.0"

解析过慢

问题poetry lock 运行很久。

解决:Poetry 会缓存包元数据,但首次对依赖很多的项目进行解析可能较慢。如果超过几分钟:

# 清缓存后重试
poetry cache clear --all pypi
 
# 使用 verbose 输出观察过程
poetry lock -vvv

IDE 未检测到虚拟环境

问题:VS Code 或 PyCharm 找不到 Poetry 环境。

解决:启用项目内虚拟环境:

poetry config virtualenvs.in-project true
poetry install  # 在项目根目录重新创建 .venv

然后在 IDE 中选择 .venv/bin/python 作为解释器。

Hash 不匹配错误

问题poetry install 报 hash mismatch。

解决:重新生成 lock 文件(不更新依赖版本):

poetry lock --no-update

这会重新生成 hash,但不改变依赖版本。

FAQ

Python Poetry 用来做什么?

Python Poetry 是一个依赖管理与打包工具,负责安装包、解决版本冲突、管理虚拟环境,并将包发布到 PyPI。它用一个围绕 pyproject.toml 的统一工具,替代了 pip、venv、setuptools、twine 等工具的组合使用方式。

Poetry 比 pip 更好吗?

Poetry 与 pip 的定位不同。Poetry 提供依赖解析、lock 文件、虚拟环境管理与包发布的一体化体验;pip 更简单,适合直接安装。对于需要可复现构建、团队协作或需要发布包的项目,Poetry 优势明显;对于快速脚本或简单项目,pip 已足够。

如何从 pip 切换到 Poetry?

在项目中用 poetry init 初始化,然后用 cat requirements.txt | xargs poetry add 从 requirements.txt 导入依赖。Poetry 会生成 pyproject.toml 与 poetry.lock。用 poetry install 验证无误后,可删除旧的 requirements.txt 文件。如果仍需要 requirements.txt 兼容性,可使用 poetry export

Poetry 能替代 virtualenv 吗?

可以。Poetry 会为每个项目自动创建并管理虚拟环境,你无需手动创建或激活。默认情况下 Poetry 将环境存储在集中缓存目录;如果配置 poetry config virtualenvs.in-project true,则会放在项目目录中。你仍然可以使用 poetry shell 以交互方式激活环境。

Poetry 能管理多个 Python 版本吗?

Poetry 本身不负责安装 Python 版本,但会使用系统中已有的 Python。你可以用 pyenv 或 uv 安装多个 Python,然后用 poetry env use python3.11 指定项目使用哪个版本。Poetry 会在同一项目下为不同 Python 版本创建独立虚拟环境。

poetry.lock 和 requirements.txt 有什么区别?

poetry.lock 记录了每个已安装包的精确版本(包括所有传递依赖),并包含用于校验的内容 hash。通过 pip freeze 生成的 requirements.txt 也会列出精确版本,但缺少 hash 校验与依赖关系追踪。lock 文件能确保所有环境的安装结果具有确定性,而 requirements.txt 在传递依赖更新时可能产生差异。

结论

Python Poetry 将依赖管理从摩擦源变成了顺滑的工作流。通过把依赖解析、虚拟环境管理与包发布整合到一个工具中,它消除了长期困扰 Python 开发者的碎片化工具链。pyproject.toml 作为单一事实来源,lock 文件保证可复现安装,而依赖解析器能在冲突造成运行时失败之前就将其拦截。

无论你是在为 PyPI 构建一个库、在管理一个拥有数十个依赖的复杂应用,还是在团队协作中追求一致的环境,Poetry 都能提供仅靠 pip 难以实现的结构化与可靠性。它的学习曲线并不陡——大多数开发者一小时内就能上手——而省下的依赖排查时间往往在第一周就能回本。

你可以从下一个项目的 poetry new 开始,或在现有项目中运行 poetry init。添加依赖、提交 lock 文件,然后体验“理应如此”的依赖管理方式。对于 Jupyter 数据科学工作流,可以将 Poetry 的项目级依赖控制与 RunCell (opens in a new tab) 搭配,获得一个同时覆盖包管理与交互式分析的顺畅环境。

📚