Python项目管理工具:Poetry 使用指南

Mar 01,2026 Python Poetry

sky-and-plane 在项目开发中,良好的代码管理工具至关重要。对于 Python 开发而言,核心诉求是管理项目依赖、虚拟环境、项目元信息等。近年来,一系列 PEP(Python 增强提案)规范了使用 pyproject.toml 文件进行项目依赖、构建和元信息管理。伴随着标准落地,许多新工具渐次发布,首当其冲的就是 Poetry。Poetry 是用于 Python 的依赖管理和打包工具,设计目标是简化和提升 Python 包的创建、管理与发布过程。在 Poetry 官网 中对其的介绍是:Poetry 是让 Python 打包和依赖管理更加轻松的工具。

本文将通过实际操作的方式,一步步了解 Poetry 的功能与常见工作流。本文基于以下版本进行演示:

OS:Debian 13(Trixie)
Python:3.13
poetry:2.3.2

Poetry 还在快速更新迭代中,有些配置和用法可能会因版本差异而不同,请注意区分。

安装和使用

安装 Poetry 的方法见官方文档: https://python-poetry.org/docs。不同平台有各自的安装方法,建议使用 pipx 安装。

$ pipx install poetry
$ poetry --version
Poetry (version 2.3.2)

Poetry 版本升级方法:

$ pipx upgrade poetry

Poetry 常用命令速览:

$ poetry new
$ poetry init
$ poetry add
$ poetry remove
$ poetry install
$ poetry sync
$ poetry run

项目管理

以下命令可以用于了解 Poetry 的用法和版本信息等。

$ poetry list
$ poetry about

子命令介绍: + list 查看所有 Poetry 支持的子命令。 + about 查看 Poetry 的版本等信息。

Poetry 有一个全局性的 --verbose 选项,或者 -v/-vv/-vvv,可以用来观察 Poetry 的 debug 信息和具体的运行过程。

Poetry 的全局配置

查看 Poetry 的默认配置:

$ poetry config --list
cache-dir = "~/.cache/pypoetry"       # 缓存目录
data-dir = "~/.local/share/pypoetry"
installer.max-workers = null
virtualenvs.path = "{cache-dir}/virtualenvs"   # 项目虚拟环境目录
...

设置 Poetry 的配置项。修改 Poetry 的全局配置会影响 Poetry 的行为,谨慎修改。

$ poetry config virtualenvs.in-project true
$ poetry config repositories.aliyun https://mirrors.aliyun.com/pypi/simple/
  • 修改 virtualenvs.in-project 配置项为 true。默认情况下,Poetry 会在 virtualenvs.path 配置规定的目录下创建项目的虚拟环境,修改该项为 true 后,Poetry 会在项目目录下创建虚拟环境,目录为 .venv
  • 配置一个名为 aliyun 的 PyPI 源,修改为国内源以提升依赖安装速度。

Poetry 的配置保存在 ~/.config/pypoetry/config.toml 文件中。

$ cat ~/.config/pypoetry/config.toml
[virtualenvs]
in-project = true

[repositories.aliyun]
url = "https://mirrors.aliyun.com/pypi/simple/"

以上是比较常见的 Poetry 全局指令。接下来是和项目管理相关的内容。

创建新项目

使用 Poetry 的 new 子指令创建一个全新的项目。

$ poetry new myproj
Created package myproj in myproj
$ tree myproj
myproj
├── pyproject.toml
├── README.md
├── src
│   └── myproj
│       └── __init__.py
└── tests
    └── __init__.py

new 子命令创建新的 Python 项目。新项目目录包含基础的项目结构,除 pyproject.toml 外还会生成 README.mdtests 等基础文件,内容多为占位信息。

Python 项目有两种常见结构:一种是把包放在项目的顶级目录下,一般称为 flat 布局,许多 Web 项目都是这么做的;另一种是把包放到项目的 src 目录下,称为 src 布局,许多库项目采取了这种方式。Poetry 默认采用 src 布局,如果想使用 flat 布局,可以传入 --flat 参数。

$ poetry new myproj2 --name app --flat
Created package app in myproj2

$ tree myproj2
myproj2
├── app
│   └── __init__.py
├── pyproject.toml
├── README.md
└── tests
    └── __init__.py
  • --name 参数用于指定创建项目的包名,如果不指定,包名和项目名一样。
  • --flat 指定创建 flat 布局项目,包名 app 就在项目顶级目录下,没有 src 目录了。生成的 pyproject.toml 文件也有细微区别。

初始化已有项目

如果现有项目要切换到 Poetry 进行管理,可以使用 init 指令,会在现有项目中创建 pyproject.toml 文件。

$ mkdir myproj3
$ cd myproj3
$ poetry init --no-interaction   # 不使用交互式输入项目信息

$ ls
pyproject.toml   # 仅仅创建了 pyproject.toml 文件

Poetry 初始化项目的工作十分简单,只新增了一个 pyproject.toml 文件。如果 init 指令不使用 --no-interaction 参数,Poetry 会出现交互式配置提示,需要一步步填入项目元信息。

check 子命令用于检查 pyproject.toml 文件的格式是否正确。

$ poetry check 
All set!

项目配置

Poetry 通过 pyproject.toml 文件实现大部分管理功能,部分 Poetry 子命令(比如 addremove 等)会修改这个文件,这个文件也可以手动修改。

pyproject.toml 并不是 Poetry 的发明,PEP 518 定义了该文件作为构建配置入口,PEP 621 定义了 [project] 元信息规范。其他符合 PEP 规范的工具也可以使用这个文件。

以下是 myproj2 项目的 pyproject.toml 文件

$ cd myproj2

$ cat pyproject.toml 
[project]
name = "app"
version = "0.1.0"
description = ""
authors = [
    {name = "Your Name",email = "you@example.com"}
]
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
]

[build-system]
requires = ["poetry-core>=2.0.0,<3.0.0"]
build-backend = "poetry.core.masonry.api"

在 TOML 格式中,方括号代表 table,类似一个子 JSON,其中的等号定义内容相当于 JSON 中的键值对。

  • [project] 定义了项目的元信息,例如 name、version、description、authors 等。
  • requires-python 指定本项目依赖的 Python 版本。
  • dependencies 用于指定本项目的依赖。
  • [build-system] 中指定了库项目构建相关的依赖和构建后端。使用 Poetry 打包/发布时必须保留该部分;即便是应用项目,保留默认配置也更稳妥。

PyPI 源管理

在 Poetry 管理的项目中,可以使用 source 子命令管理 PyPI 源,source 子命令下有 addshowremove 等子命令用于对 PyPI 源进行管理。

$ poetry source add aliyun https://mirrors.aliyun.com/pypi/simple
$ poetry source add douban https://pypi.doubanio.com/simple

$ poetry source show
 name      : aliyun                                 
 url       : https://mirrors.aliyun.com/pypi/simple 
 priority  : primary                              

 name      : douban                           
 url       : https://pypi.doubanio.com/simple 
 priority  : primary

aliyun 和 douban 两个源的优先级都是 primary,当存在多个 primary 源时,Poetry 会按它们在 pyproject.toml 中的顺序进行查找;未显式指定 --source 的依赖通常会优先走第一个 primary 源。

如果需要从特定的 source 安装依赖,可以用 --source 指定源站。

$ poetry add flask --source douban

在运行上面的命令之后,目录下会产生 poetry.lock 文件,它非常重要,记录了当前项目的依赖关系和依赖版本等信息,相当于一个快照,poetry sync 等命令会读取 poetry.lock 还原出完全一致的依赖环境。

再次查看 pyproject.toml 文件,重点看看其中的依赖部分:

[project]
...
requires-python = ">=3.13"
dependencies = [
    "flask (>=3.1.3,<4.0.0)"
]

[[tool.poetry.source]]
name = "aliyun"
url = "https://mirrors.aliyun.com/pypi/simple"
priority = "primary"


[[tool.poetry.source]]
name = "douban"
url = "https://pypi.doubanio.com/simple"
priority = "primary"


[tool.poetry.dependencies]
flask = {source = "douban"}
  • project.dependencies 中指明了项目依赖的 flask 版本。
  • [tool.poetry.dependencies] 中指明了 Flask 依赖来自的源。这在某些场景很有用,比如英伟达的 CUDA 源分为 CPU 版本和 GPU 版本,CPU 就要使用特定的源才能安装。

非 package 项目

Poetry 项目分两种模式:

  • 默认是 package 模式:意味项目需要被打包和发布,这种模式下 pyproject.toml 中的 version 是强制必填字段,运行 poetry install 会安装当前项目。一般采用 src 项目布局。

  • non-package 模式:意味这是应用类型的项目。一般使用 flat 项目布局。

[tool.poetry] 中添加如下配置,指定为 non-package 模式。

package-mode = false

一般来说,用什么模式的区别不大,项目的布局更重要一些。不管是不是 package 模式,都建议设置 version 字段。

poetry run

使用 poetry run 会在当前的 Poetry 环境中运行命令。如果虚拟环境还不存在,运行这个命令会创建虚拟环境。

$ poetry run which python
/tmp/myproj2/.venv/bin/python

$ poetry run flask --version
Python 3.13.5
Flask 3.1.3
Werkzeug 3.1.6

依赖管理

管理 Python 版本

较新版本的 Poetry 支持安装特定版本的 Python 了。先看看当前虚拟环境中的 Python 版本。

$ poetry env info
Virtualenv
Python:         3.13.5
Implementation: CPython
Path:           /tmp/myproj2/.venv
Executable:     /tmp/myproj2/.venv/bin/python
Valid:          True

Base
Platform:   linux
OS:         posix
Python:     3.13.5
Path:       /usr
Executable: /usr/bin/python3.13

和系统 Python 版本一致,是 3.13。Poetry 的 python 子命令有 installlistremove 3 个子命令管理项目的 Python 版本。

$ poetry python list --all
 Version  Implementation Manager Path
 3.14.3t  CPython        Poetry  Available for download
 3.14.3   CPython        Poetry  Available for download
...    

上面的命令会列出所有可用的 Python 版本,Available for download 表示可以下载安装。如果不使用 --all 参数,只会列出本地已有的 Python 版本。

安装 Python 3.11 试试看:

$ poetry python install 3.11
Downloading and installing 3.11 (cpython) ... Done
Testing 3.11 (cpython) ... Done

$ poetry python list
Version Implementation Manager Path
3.13.5  CPython        System  /usr/bin/python3.13
3.13.5  CPython        System  /usr/bin/python3
3.13.5  CPython        System  /bin/python3.13
3.13.5  CPython        System  /bin/python3
3.11.14 CPython        Poetry  ~/.local/share/pypoetry/python/cpython@3.11.14/bin/python3.11
3.11.14 CPython        Poetry  ~/.local/share/pypoetry/python/cpython@3.11.14/bin/python3
3.11.14 CPython        Poetry  ~/.local/share/pypoetry/python/cpython@3.11.14/bin/python

安装过程就是到 GitHub 的 python-build-standalone 仓库下载对应版本的 Python 包安装。

可以看到 Poetry 把 Python 3.11 安装到 ~/.local/share/pypoetry/python/ 目录下了。

然后修改 pyproject.toml 文件,编辑 requires-python 一行,指定使用 Python 3.11 版本:

requires-python = ">=3.11,<3.12"

删除旧的 3.13 版本虚拟环境,然后切换为 3.11 并重建虚拟环境。

$ poetry env remove
Deleted virtualenv: /tmp/myproj2/.venv

$ poetry update
Creating virtualenv app in /tmp/myproj2/.venv
Writing lock file

$ poetry env info

Virtualenv
Python:         3.11.14
Implementation: CPython
Path:           /tmp/myproj2/.venv
Executable:     /tmp/myproj2/.venv/bin/python
Valid:          True

Base
Platform:   linux
OS:         posix
Python:     3.11.14
Path:       ~/.local/share/pypoetry/python/cpython@3.11.14
Executable: ~/.local/share/pypoetry/python/cpython@3.11.14/bin/python3.11

$ poetry run python --version
Python 3.11.14

先删除旧的虚拟环境,然后运行poetry update 会新建 3.11 版本的虚拟环境。新的 .venv 环境里的 Python 版本是 3.11,也显示了 3.11 环境基于 Poetry 安装在用户目录下的 Python。

管理依赖

从 PyPI 里查找包,可以看到把 aliyun 这个 PyPI 源中匹配 aiohttp 的包都列出来了。

$ poetry search aiohttp
 Package                                                    Version     Source Description 
 aiohttp                                             0.1          aliyun             
 aiohttp                                             0.2          aliyun             
 aiohttp                                             0.3          aliyun             
 aiohttp                                             0.4          aliyun    
 ...

addremove 子命令分别用来安装和卸载依赖,都会同步修改 pyproject.toml 文件。

$ poetry add "aiohttp>2,<3" httpx

$ poetry show aiohttp
 name         : aiohttp                                      
 version      : 2.3.10                                       
 description  : Async http client/server framework (asyncio) 
...

使用 > 或者 < 限制版本时要使用引号,因为它们在 shell 中有重定向的含义。如果指定的版本和之前不一样,Poetry 会重新安装成新指定的版本,并更新 pyproject.toml 文件。

上面指定了 aiohttp 的版本范围,实际安装的是符合条件的最高版本。pyproject.toml 文件中也做了相应的变更。

$ grep -E  ^dependencies -A 4  pyproject.toml
dependencies = [
    "flask (>=3.1.3,<4.0.0)",
    "aiohttp (>2,<3)",
    "httpx (>=0.28.1,<0.29.0)"
]

上传项目到 Git 时,建议上传 pyproject.tomlpoetry.lock 两个文件,不要上传 .venv

注意:如果开发的是库(library),而不是应用(application),则往往不需要上传 poetry.lock 到代码版本管理仓库,因为库需要保持多个依赖版本的兼容性,如果写死版本,很可能会产生依赖冲突。

当把这个项目迁移到新环境或者目录时,可以使用 poetry sync 解析并安装所有依赖,这个命令提供了 --dry-run 选项,可以只输出操作,不实际运行。

$ poetry sync

poetry addpip install 安装依赖时都会分析包的依赖,并解决依赖。在执行 poetry remove 时,Poetry 会删除依赖的库,而 pip uninstall 则不会,pip 只会删除指定库。

依赖组

有些依赖仅仅在开发阶段使用,比如 lint 工具;有些是在软件测试中用到的,比如 pytest。生产环境运行时应该保持最精简的状态和最小体积,不需要安装这些开发和测试阶段的依赖。为了区分依赖,可以新增 devtest 两个可选(optional)依赖组,依赖组的名字可以随意指定,但建议使用有意义的词汇。

$ poetry add --group dev ruff autopep8
$ poetry add --group test pytest

$ grep -A7 "dependency-groups" pyproject.toml 
[dependency-groups]
dev = [
    "ruff (>=0.15.4,<0.16.0)",
    "autopep8 (>=2.3.2,<3.0.0)"
]
test = [
    "pytest (>=9.0.2,<10.0.0)"
]

从结果可以看到,pyproject.toml 中多了 [dependency-groups] 子表,内容是指定安装的依赖。在 [project]dependencies 里定义的依赖是 main 组。

默认情况下,install 命令会安装所有依赖组。使用 --with 安装可选组,使用 --without 排除可选组,使用 --only 只安装某些组。

$ poetry install --only=dev,main
$ poetry install --without=test

在目前的 pyproject.toml 配置下(只有 main、dev、test 这三个组),上面两个命令的效果等价。

注意:使用 --only 时,Poetry 会自动忽略 --with--without 选项。

使用 show 子命令可以查看依赖的安装情况,默认会把间接依赖也列出来,使用 --tree 以树形方式展示依赖关系,使用 --top-level 选项只列出 pyproject.toml 文件中指定的顶级依赖。

poetry.lock 文件

上面说过,poetry.lock 文件详细记录了当前项目所有依赖包的精确版本信息,包括直接依赖和间接依赖,相当于当前项目依赖情况的一个快照。不要手动修改 poetry.lock 文件。

如果手动修改了 pyproject.toml 文件的依赖项,可能会导致 poetry.lock 中的依赖不一致。运行 poetry install 时会报错:

$ poetry install
Installing dependencies from lock file

pyproject.toml changed significantly since poetry.lock was last generated. Run `poetry lock` to fix the lock file.

$ poetry lock
Resolving dependencies... (3.0s)

Writing lock file

poetry install 时的输出提示 pyproject.tomlpoetry.lock 文件内容不同步,需要运行 poetry lock 来更新 poetry.lock 文件。

注意:poetry lock 这个命令只会更新 poetry.lock 文件的依赖条目,并不会安装依赖。而且这个过程会遍历所有直接依赖的依赖项,以便解决潜在的依赖版本冲突问题。

依赖锁定主要解决如下两个问题: + 解析:找到满足所有依赖限制下的解决方案,避免出现间接依赖的版本冲突。 + 锁定:通过 poetry.lock 文件为当前所有依赖项创建快照。

使用 poetry lock --regenerate 会忽略已有的 poetry.lock 文件,重新创建一个 poetry.lock 文件覆盖旧的。

执行 poetry install 会安装 poetry.lock 文件中的所有依赖,且只安装环境中缺失的那部分。

如果环境中存在 poetry.lockpyproject.toml 中未记录的依赖怎么办?比如,使用 pip 往虚拟环境中安装的依赖。使用 poetry sync 不止会依赖检查、安装和同步,也会清理环境中未被记录的依赖。

$ poetry run pip install requests

$ poetry sync
Installing dependencies from lock file

Package operations: 0 installs, 0 updates, 3 removals

  - Removing charset-normalizer (3.4.4)
  - Removing requests (2.32.5)
  - Removing urllib3 (2.6.3)

Installing the current project: app (0.1.0)

使用 sync 子命令,Poetry 移除了虚拟环境中没有被 poetry.lock 文件记录的依赖,使得虚拟环境和 poetry.lock 的依赖保持一致。

poetry installpoetry sync 命令的功能十分相似,都可以安装指定的依赖项,但有两点不一样:

  • poetry install 不会清理环境中 Poetry 未记录的依赖,而 poetry sync 会清理。syncinstall 更严格。
  • 如果是 package 项目,poetry install 会把当前的项目作为依赖安装。

依赖升级

Poetry 的 show 子指令可以查看项目依赖的情况:

$ poetry show aiohttp
$ poetry show --latest 
  • 查看 aiohttp 包的版本和依赖关系
  • --latest 查看依赖可用的最新版本

如果依赖有满足条件的新版本,可以使用 update 子命令进行更新。

$ poetry update aiohttp
$ poetry update

以上示例分别用于更新指定的依赖和更新所有依赖。update 也支持 --dry-run 选项,由于版本升级总是伴随冲突风险,建议升级前查看具体升级了哪些依赖。

如果要突破 pyproject.toml 文件中的版本限制进行升级,比如 aiohttp 2.3.10 升级到 aiohttp 3.3.0,或者直接升级到最新版本,需要通过如下的 add 指令操作,这个命令也会同步修改 pyproject.toml 中的依赖版本限制。

$ poetry add "aiohttp<3.10"
$ grep aiohttp pyproject.toml 
    "aiohttp (<3.10)",

$ poetry show aiohttp 
 name         : aiohttp                                      
 version      : 3.9.5
 ...

升级依赖版本和新增依赖一样,都是 add 子命令;通过新的版本约束触发重新解析并升级到符合条件的版本。

虚拟环境

如果 Poetry 的全局配置项 virtualenvs.in-project=false,Poetry 项目的虚拟环境会放在用户目录下的 .cache/pypoetry/virtualenvs,可以为一个项目支持多个不同的 Python 环境,以便切换多个版本进行测试。当 virtualenvs.in-project=true,项目的虚拟环境就是项目目录下的 .venv 目录,就无法再支持多版本了。

Poetry 在运行时,会通过检查 pyproject.toml 文件检测当前是否在 Poetry 环境中,是否已经有虚拟环境。如果 Poetry 项目中还没有虚拟环境,Poetry 会自动创建虚拟环境后执行命令。下面是临时把 virtualenvs.in-project 改为 false 之后,测试多个版本的 Python 环境。

$ poetry config virtualenvs.in-project false   # 设置虚拟环境为用户目录下,而非项目目录下

$ sed -i 's/^requires-python.*$/requires-python = ">=3.11"/' pyproject.toml   # 修改项目的python依赖为 >= 3.11

$ poetry env use 3.11  # 切换 Python 3.11
Creating virtualenv app-X2aZMY7n-py3.11 in ~/.cache/pypoetry/virtualenvs
Using virtualenv: ~/.cache/pypoetry/virtualenvs/app-X2aZMY7n-py3.11
$ poetry run python --version   # 验证当前 Python 版本
Python 3.11.14

$ poetry env use 3.13  # 切换 Python 3.13
Creating virtualenv app-X2aZMY7n-py3.13 in ~/.cache/pypoetry/virtualenvs
Using virtualenv: ~/.cache/pypoetry/virtualenvs/app-X2aZMY7n-py3.13
$ poetry run python --version   # 验证当前 Python 版本
Python 3.13.5

$ poetry env info --path   # 虚拟环境的路径
~/.cache/pypoetry/virtualenvs/app-X2aZMY7n-py3.13

$ poetry env list
app-X2aZMY7n-py3.11
app-X2aZMY7n-py3.13 (Activated)   # 当前启用的 Python 版本

以上命令使用 env use 创建了 Python 3.11 和 Python 3.13 的虚拟环境,后一个虚拟环境 Python 3.13 目前处于 Activated 状态。不同版本的虚拟环境有不同的虚拟环境目录,切换不同 Python 版本很方便验证项目在各个版本上的可用性。指定的虚拟环境版本必须符合 pyproject.toml 中对 Python 依赖的规定。

虚拟环境的路径中有一串看似无意义的随机字符串(X2aZMY7n),实际是对项目路径做了 hash 之后的 base64 编码,如果项目路径发生变化,虚拟环境也会重新生成。

poetry env remove --all 删除所有虚拟环境,也可以将 --all 替换为具体的版本,删除特定版本。

$ poetry env remove --all 

进入虚拟环境

在写代码或者某些场景中,可能需要进入虚拟环境操作,方法如下:

$ poetry env activate  # 查看激活虚拟环境的方法
source ~/.cache/pypoetry/virtualenvs/app-X2aZMY7n-py3.13/bin/activate

$ source ~/.cache/pypoetry/virtualenvs/app-X2aZMY7n-py3.13/bin/activate  # 激活虚拟环境
(app-py3.13) $ which python   # 检查虚拟环境
~/.cache/pypoetry/virtualenvs/app-X2aZMY7n-py3.13/bin/python

(app-py3.13) $ deactivate   # 退出虚拟环境 

和正常激活虚拟环境的区别不大,主要是找到当前的虚拟环境路径。

运行测试项目

开发流程中的 Poetry

在使用 Poetry 管理的项目中,开发流程中常涉及的管理动作如下: + poetry new 创建项目。 + poetry add/remove 管理项目依赖 + 开发项目 + poetry run 运行和测试项目 + poetry sync 更新本地的依赖情况

一般来说,pyproject.toml 文件中的某些信息也是需要偶尔手动维护的。

实例

新建项目

$ poetry new simple-web --flat
$ cd simple-web
$ poetry add flask

修改 app/__init__.py 文件为如下内容,是一个最简单的 Flask Web 应用:

from flask import Flask

app = Flask(__name__)

@app.route("/")
def index():
    return "Hello, World"

运行方法:

$ FLASK_APP=app:app poetry run flask run

小结

Poetry 把依赖管理、虚拟环境与构建发布整合到统一流程中,使用门槛低、可重复性强。对应用型项目,建议优先明确依赖组与 Python 版本约束;对库项目,则更应关注依赖范围与锁定策略的边界。值得关注的是,Poetry 之外还有势头正猛的后起之秀 uv,将在下一篇博客中介绍。

Last updates at Mar 01,2026

Views (7)

Leave a Comment

total 0 comments