使用 Python Poetry 进行依赖管理
简介
当您的 Python 项目依赖于外部包时,您需要确保使用每个包的正确版本。更新后,软件包可能无法像更新前那样工作。
Python Poetry 这样的依赖管理器可帮助在项目中指定、安装和解析外部包。这样,可以确保始终在每台机器上使用正确的依赖版本。
在本文中,将介绍:
- 开始一个新的Poetry 项目
- 将Poetry 添加到现有项目
- 使用pyproject.toml文件
- 引脚依赖项
- 安装依赖项poetry.lock
- 执行基本的 Poetry CLI命令
使用Poetry将帮助启动新项目、维护现有项目并掌握依赖管理。您将准备好使用pyproject.toml文件,这将是在 Python 项目中定义构建要求的标准。
虽然本教程侧重于依赖管理,但 Poetry 还可以帮助您构建和打包项目。如果您想分享您的作品,您甚至可以将您的 Poetry 项目发布到Python Packaging Index (PyPI)。
写在前面
在深入了解 Python Poetry 的本质之前,需要了解一些先决条件。
相关术语
如果在其中一个Python脚本中使用了import 语句,则可以使用模块。
其中一些模块可能是自己写的Python文件。 其他可能是内置模块,如DateTime。 但是,有时 Python 提供的还不够。那时可能会转向外部的打包模块。
当Python代码依赖于外部模块时,可以说这些包是项目的依赖项。
可以在PyPI中找到不属于 Python 标准库的包。在了解其工作原理之前,需要在系统上安装 Poetry。
Python Poetry 安装
要在命令行中使用 Poetry,应该在系统范围内安装它。如果只是想尝试一下,那么可以使用pip。
但是应该谨慎尝试这种方法,因为 Poetry 会安装它自己的依赖项,这可能会与在项目中使用的其他包发生冲突。
安装 Poetry的推荐方法是使用官方install-poetry脚本。
可以手动下载并运行此Python 文件,也可以在下面选择操作系统对应的命令:
1 | #osx / linux / bashonwindows 安装 |
poetry --version
在终端中运行以查看是否poetry有效。此命令将显示当前的poetry版本。
如果要更新 Poetry,则可以运行poetry self update
Python Poetry入门
安装 Poetry 后,了解一下 Poetry 是如何工作的。
下面开始一个新的 Poetry 项目以及如何将 Poetry 添加到现有项目中。还将看到项目结构并检查pyproject.toml文件。
创建一个新的Poetry项目
可以使用命令和项目名称作为参数来创建新的 Poetry 项目。
在示例中,将该项目称为rp-poetry. 创建项目,然后进入新创建的目录:
1 | $ poetry new rp-poetry |
通过运行poetry new rp-poetry
,创建了一个名为 rp-poetry/ 的新文件夹。
当查看文件夹内部时,会看到一个结构:
1 | rp-poetry/ |
Poetry 会自动规范化包名称。它将项目名称中的破折号 (-) 转换为rp_poetry/文件夹名称中的下划线 (_) 。否则,Python 中不允许使用该名称,因此无法将其作为模块导入。
要更好地控制创建包名称,您可以使用选项 --name
将其命名为与项目文件夹不同的名称:
1 | $ poetry new rp-poetry --name realpoetry |
如果希望将源代码额外的存储在 src/ 父文件夹中,那么 Poetry 可以使用 --src
:
1 | $ poetry new --src rp-poetry |
通过添加 --src 标志,您创建了一个名为 src/ 的文件夹,其中包含您的 rp_poetry/ 目录:
1 | rp-poetry/ |
创建新的 Poetry 项目时,将立即收到基本的文件夹结构。
检查项目结构
在 rp_poetry/ 这个目录中,你会找到一个__init__.py
包含你的包版本的文件:
1 | # rp_poetry/__init__.py |
当跳到 tests/ 文件夹并打开 test_rp_poetry.py 时,你会注意到 rp_poetry 已经可以导入:
1 | # tests/test_rp_poetry.py |
poetry还为项目添加了第一次测试。 test_version() 函数检查rp_poetry/__init__.py
的__version__
变量是否包含预期版本。
但是,__init__.py
文件不是定义包版本的唯一位置。 另一个是 pyproject.toml 文件。
使用 pyproject.toml 文件
使用 Poetry 最重要的文件之一是 pyproject.toml 文件。这个文件不是poetry的发明。这是 PEP 518 中定义的配置文件标准:
此PEP指定Python软件包如何指定要执行其所选构建系统的构建依赖项。 作为本说明书的一部分,为用于指定构建依赖项的软件包引入了新配置文件(预期相同的配置文件将用于将来配置详细信息)。
最后,他们决定采用TOML格式,它代表Tom’s Obvious Minimal Language。在他们看来,TOML 足够灵活,比其他选项(YAML、JSON、CFG 或 INI)具有更好的可读性和更低的复杂性。
要查看 TOML 可以打开pyproject.toml文件:
1 | # pyproject.toml |
pyproject.toml文件中看到四个部分。 这些部分称为表格。 它们包含了 Poetry 等工具识别和用于依赖管理或构建例程的指令。
如果表名称是tool-specific,则必须使用 tool.
前缀。 通过使用这样的子表,可以为项目中的不同工具添加说明。 在这种情况下,只有tool.poetry。 但是,您可能会看到其他项目中的 [tool.pytest.ini_options] 的示例。
在[tool.poetry]上面的第3行上,可以存储有关poetry项目的一般信息。 可用的键由poetry定义。
虽然某些键是可选的,但有四个必须指定:
- name: 包的名字
- version: 包的版本,最好遵循语义版本控制
- description: 对您的包裹的简短描述
- authors: 作者列表,格式为 name
第 9 行 [tool.poetry.dependencies] 和第 12 行 [tool.poetry.dev-dependencies] 的子表对于依赖管理至关重要。
当将依赖项添加到 Poetry 项目时,将在下一节中了解有关这些子表的更多信息。
现在,重要的是要认识到包依赖和开发依赖之间存在差异。
该pyproject.toml文件的最后一个表 [build-system] 在第 15 行。
该表定义了 Poetry 和其他构建工具可以使用的数据,但由于它不是特定于工具的,所以它没有前缀。Poetry pyproject.toml 使用两个键创建了文件:
- requires:构建包所需的依赖项列表,使此键成为必需项
- build-backend:用于执行构建过程的 Python 对象
当使用 Poetry 开始一个新项目时,这是 pyproject.toml 开始使用的文件。随着时间的推移,将添加有关您的包和您正在使用的工具的配置详细信息。
随着 Python 项目的增长,pyproject.toml 文件也会随之增长。
对于子表 [tool.poetry.dependencies] 和 [tool.poetry.dev-dependencies]
在下一节中,您将了解如何扩展这些子表。
Poetry的使用
一旦你建立了一个 Poetry 项目,真正的工作就可以开始了。
在此过程中,将了解 Poetry 如何提供虚拟环境并处理依赖关系。
使用poetry的虚拟环境
当开始一个新的 Python 项目时,最好创建一个虚拟环境。否则,可能会混淆来自不同项目的不同依赖项。使用虚拟环境是 Poetry 的核心功能之一,它永远不会干扰全局 Python 安装。
但是,Poetry 不会在启动项目时立即创建虚拟环境。可以通过让 Poetry 列出连接到当前项目的所有虚拟环境来确认 Poetry 没有创建虚拟环境。
如果你还没有,cd进入rp-poetry/然后运行一个命令:
1 | $ poetry env list |
目前,不应该有任何输出。
当运行某些命令时, Poetry 会一路创建一个虚拟环境。如果想更好地控制虚拟环境的创建,那么可能决定明确告诉 Poetry 要使用哪个 Python 版本,然后从那里开始:
1 | $ poetry env use python3 |
使用此命令,将使用与安装 Poetry 相同的 Python 版本。当 PATH 中有 Python 可执行文件时,使用 python3 可以工作。
注意:可以将绝对路径传递给 Python 可执行文件。它应该可以在
pyproject.toml
文件中找到的 Python 版本约束相匹配。
如果没有,那么可能会遇到麻烦,因为使用的 Python 版本与项目所需的版本不同。在环境中运行的代码在另一台机器上可能存在错误。
更糟糕的是,外部包通常依赖于特定的 Python 版本。因此,安装你包的用户可能会收到错误,因为依赖项版本与其 Python 版本不兼容。
运行时env use
,会看到一条消息:
1 | Creating virtualenv rp-poetry-AWdWY-py3.9 in ~/Library/Caches/pypoetry/virtualenvs |
Poetry 为您的项目环境构建了一个唯一名称。名称包含项目名称和 Python 版本。中间看似随机的字符串是父目录的哈希值。
有了中间这个唯一的字符串,Poetry 可以在系统上处理多个具有相同名称和相同 Python 版本的项目。
这很重要,因为默认情况下,Poetry 在同一个文件夹中创建所有虚拟环境。
无需任何其他配置,Poetry 在Poetry缓存目录 virtualenvs/ 的文件夹中创建虚拟环境:
操作系统 | 路径 |
---|---|
macOS | ~/Library/Caches/pypoetry |
Windows | C:\Users<username>\AppData\Local\pypoetry\Cache |
Linux | ~/.cache/pypoetry |
如果要更改默认缓存目录,则可以编辑Poetry 的配置。
当已经在使用virtualenvwrapper或其他第三方工具来管理您的虚拟环境时,这可能很有用。要查看当前配置,包括已配置的cache-dir,可以运行命令:
1 | $ poetry config --list |
通常,不必更改此路径。如果想了解有关与 Poetry 虚拟环境交互的更多信息,那么 Poetry 文档 包含有关管理环境的一章。
只要在项目文件夹中,Poetry 就会使用与之关联的虚拟环境。如果有任何疑问,可以通过env list
再次运行命令来检查虚拟环境是否已激活:
1 | $ poetry env list |
这将显示类似 rp-poetry-AWdWY-py3.9 (Activated) . 通过激活的虚拟环境,可以开始管理一些依赖项并看到 Poetry 大放异彩。
声明你的依赖
Poetry 的一个关键元素是它对依赖项的处理。在开始之前,先看看pyproject.toml文件中的两个依赖表:
1 | # rp_poetry/pyproject.toml (Excerpt) |
当前声明了两个依赖项。一个是 Python 本身。另一个是pytest,一个广泛使用的测试框架。
项目包含一个 tests/ 文件夹和一个 test_rp_poetry.py 文件。
使用 pytest 作为依赖项,Poetry可以在安装后立即运行您的测试。
确保位于rp-poetry/项目文件夹中并运行命令:
1 | $ poetry install |
使用该install命令,Poetry 会检查您的pyproject.toml文件中的依赖关系,然后解析并安装它们。
当有许多依赖项需要具有不同版本的不同第三方包时,解决部分尤其重要。在安装任何包之前,Poetry 会确定哪个版本的包满足其他包,设置为它们的要求的版本约束。
除了pytest及其要求之外,Poetry 还将项目本身安装。这样,可以rp_poetry立即导入测试:
1 | # tests/test_rp_poetry.py |
安装项目包后,可以导入rp_poetry测试并检查__version__
字符串。
pytest安装后,可以使用命令poetry run
执行测试:
1 | $ poetry run pytest |
当前的测试正在成功运行,因此可以继续编码。但是,如果仔细查看第 3 行,就会发现有些奇怪。
它说 pytest-5.4.3,与 pyproject.toml 文件中所说的 5.2 不同
回顾一下,文件pytest中的依赖pyproject.toml项如下所示:
1 | # rp_poetry/pyproject.toml (Excerpt) |
^5.2前面的插入符号(^)具有特定的含义,它是 Poetry 提供的版本控制约束之一。
这意味着 Poetry 可以安装与版本字符串最左边的非零数字匹配的任何版本。这意味着5.4.3允许使用。6.0不允许版本。
当 Poetry 尝试解析依赖版本时,像插入符号这样的符号将变得很重要。
声明的依赖项越多,它就越复杂。让我们看看 Poetry 如何通过将新包安装到项目中来处理这个问题。
安装带有poetry的软件包
如果你想为requests你的项目添加一个外部包,那么你可以运行一个命令:
1 | $ poetry add requests |
通过运行poetry add requests,在项目中添加最新版本的requests库。
如果想更具体的版本可以使用版本约束,requests<=2.1
或者 requests==2.24
当不添加任何约束时,Poetry 将始终尝试安装最新版本的软件包。
有时,只想在开发环境中使用某些包。pytest是其中之一。另一个常见的库包括像Black这样的代码格式化程序,像Sphinx这样的文档生成器,以及像Pylint、Flake8、mypy或coverage.py这样的静态分析工具。
要明确告诉 Poetry 包是开发依赖项,poetry add 使用 --dev 选项运行。还可以使用 -D 选项,它与 --dev 相同:
1 | $ poetry add black -D |
添加requests为项目依赖项和black开发依赖项。Poetry 在后台为你做了一些事情。一方面,它将声明的依赖项添加到pyproject.toml文件中:
1 | # rp_poetry/pyproject.toml (Excerpt) |
Poetry 将requests包作为项目依赖项添加到[tool.poetry.dependencies]表中,同时black作为开发依赖项添加到[tool.poetry.dev-dependencies].
区分项目依赖项和开发依赖项可以防止安装用户不需要运行程序的要求。开发依赖项仅与您的包的其他开发人员相关,他们希望pytest使用black. 当用户安装你的包时,他们只安装requests。
可以在Poetry 文档中了解有关可选依赖项的更多信息。
除了对 pyproject.toml 文件的更改之外,Poetry 还创建了一个名为 poetry.lock 的文件。
在此文件中,Poetry 会跟踪您在项目中使用的所有包和确切版本。
处理poetry.lock
当运行该 poetry add 命令时,Poetry 会自动更新 pyproject.toml 并将已解析的版本固定在 poetry.lock 文件中。
但是,不必让 Poetry 完成所有工作。可以手动将依赖项添加到 pyproject.toml 文件中并在之后锁定它们。
引脚依赖项 poetry.lock
如果想用 Python 构建一个网络爬虫,那么可能想使用Beautiful Soup来解析你的数据。将其添加到文件中的 tool.poetry.dependencies 表中pyproject.toml:
1 | # rp_poetry/pyproject.toml (Excerpt) |
通过添加beautifulsoup4 = "4.10.0"
,告诉 Poetry 它应该完全安装这个版本。
当向pyproject.toml文件添加需求时,它尚未安装。
只要poetry.lock你的项目中没有文件存在,你就可以poetry install在手动添加依赖后运行,因为 Poetry 会先查找poetry.lock文件。
如果没有找到,Poetry 将解析pyproject.toml文件中列出的依赖项。
一旦poetry.lock文件存在,Poetry 将依赖该文件来安装依赖项。仅运行poetry install会触发警告,提示两个文件不同步并会产生错误,因为 Poetry 尚不知道beautifulsoup4项目中的任何版本。
要将pyproject.toml文件中手动添加的依赖项固定到poetry.lock,您必须首先运行以下poetry lock命令:
1 | $ poetry lock |
通过运行poetry lock,Poetry 处理pyproject.toml文件中的所有依赖项并将它们锁定到poetry.lock文件中。
Poetry并不止于此。运行时poetry lock,Poetry 还会递归遍历并锁定您的直接依赖项的所有依赖项。
注意:poetry lock如果有适合您的版本限制的新版本可用,该命令还会更新您现有的依赖项。如果您不想更新poetry.lock文件中已有的任何依赖项,则必须将–no-update选项添加到poetry lock命令中:
1 | $ poetry lock --no-update |
在这种情况下,Poetry 仅解析新的依赖项,但poetry.lock不会更改文件中的任何现有依赖项版本。
现在已经固定了所有依赖项,是时候安装它们以便可以在项目中使用它们。
安装依赖项 poetry.lock
如果按照上一节中的步骤操作,那么已经安装pytest并black使用了 poetry add
命令。还锁定了beautifulsoup4,但还没有安装 Beautiful Soup。
要验证beautifulsoup4尚未安装,请使用以下命令打开Python 解释器 poetry run:
1 | $ poetry run python3 |
执行poetry run python3将在 Poetry 的环境中打开一个交互式REPL会话。
首先,尝试导入requests。然后尝试 importing bs4,这是 Beautiful Soup 的模块名称。
这应该会引发错误,因为尚未安装 Beautiful Soup:
1 | >>> |
正如预期的那样,可以requests导入,但是bs4找不到模块。通过键入exit()并点击退出交互式 Python 解释器Enter。
使用poetry lock命令锁定依赖项后,必须运行poetry install
命令,可以在项目中实际使用它们:
1 | $ poetry install |
通过运行poetry install,Poetry 读取poetry.lock文件并安装其中声明的所有依赖项。
现在,bs4已准备好在您的项目中使用。要对此进行测试,请输入poetry run python3
并导入 bs4Python 解释器:
1 | >>> |
这次没有错误,并且拥有声明的确切版本。这意味着 Beautiful Soup 已正确固定在poetry.lock文件中,已安装在项目中,并且可以使用了。
要列出项目中的可用包并检查它们的详细信息,可以使用该show命令。
当使用--help
标志运行它时,将看到如何使用它:
1 | $ poetry show --help |
要检查包,可以使用show包名称作为参数,也可以使用--tree
选项将所有依赖项以树的形式列出。这将帮助查看项目的嵌套需求。
更新依赖
为了更新依赖项,Poetry 根据两种情况提供了不同的选项:
- 更新版本约束内的依赖项。
- 更新版本约束之外的依赖项。
可以在pyproject.toml文件中找到版本限制。当新版本的依赖项仍然满足版本限制时,可以使用以下update命令:
1 | $ poetry update |
该update命令将在版本限制内更新所有包及其依赖项。
之后,Poetry 将更新您的poetry.lock文件。
如果你想更新一个或多个特定的包,那么你可以将它们作为参数列出:
1 | $ poetry update requests beautifulsoup4 |
使用此命令,Poetry 将搜索满足文件中列出的版本限制的新版本requests和新版本。
然后它将解析项目的所有依赖项并将版本固定到文件中。
文件将保持不变,因为列出的约束仍然有效。
beautifulsoup4pyproject.tomlpoetry.lockpyproject.toml
如果要使用比pyproject.toml文件中定义的版本更高的版本来更新依赖项,则需要pyproject.toml事先调整文件。另一种选择是 add 使用版本约束或 latest 标签运行命令:
1 | $ poetry add pytest@latest --dev |
当运行add带有latest标记的命令时,它会查找包的最新版本并更新您的pyproject.toml文件。包含latest标签或版本约束对于使用该add命令至关重要。
如果没有它,会收到一条消息,表明该包已存在于项目中。另外,不要忘记--dev
为开发依赖项添加标志。否则,会将包添加到常规依赖项中。
添加新版本后,必须运行 install 只有这样,更新才会被锁定到poetry.lock文件中。
如果不确定更新会为依赖项引入哪些基于版本的更改,可以使用--dry-run
标志。此标志适用于命令update和add命令。它在终端中显示操作而不执行任何操作。
这样,可以安全地发现版本更改并决定哪种更新方案最适合。
区分pyproject.toml和poetry.lock
虽然pyproject.toml文件中的版本要求可能很宽松,但 Poetry 会锁定你在poetry.lock文件中实际使用的版本。这就是为什么在使用 Git 时应该提交此文件的原因。
通过poetry.lock在Git 存储库中提供文件,可以确保所有开发人员都将使用所需软件包的相同版本。当遇到包含poetry.lock文件的存储库时,最好使用 Poetry。
使用poetry.lock,可以确保使用的版本与其他开发人员使用的版本完全相同。如果其他开发人员不使用 Poetry,可以将其添加到未使用 Poetry 设置的现有项目中。
将poetry添加到现有项目
很有可能,你的项目不是从poetry new
命令开始的。或者,可能继承了一个不是用 Poetry 创建的项目,但现在想使用 Poetry 进行依赖管理。
在这些类型的情况下,可以将 Poetry 添加到现有的 Python 项目中。
添加pyproject.toml到脚本文件夹
如果项目只包含一些 Python 文件,那么仍然可以添加 Poetry 作为未来构建的基础。在这个例子中,只有一个文件,hello.py:
1 | # rp-hello/hello.py |
这个脚本唯一能做的就是输出字符串"Hello World!"。但也许这只是一个大项目的开始,因此决定将 Poetry 添加到您的项目中。poetry new 将使用 poetry init 命令,而不是使用之前的命令:
1 | $ poetry init |
该poetry init命令将启动交互式会话以创建pyproject.toml文件。
Poetry 提供了大多数需要设置的配置的建议,按下Enter
以使用它们。当不声明任何依赖项时,pyproject.tomlPoetry 创建的文件如下所示:
1 | # rp-hello/pyproject.toml |
内容看起来与在之前的示例相似。
现在可以使用 Poetry 项目提供的所有命令。有了pyproject.toml文件,现在可以运行脚本:
1 | $ poetry run python3 hello.py |
因为 Poetry 没有找到任何可以使用的虚拟环境,所以它在执行脚本之前创建了一个新环境。执行此操作后,它会显示 Hello World!
消息而没有任何错误。这意味着你现在有一个正在运行的 Poetry 项目。
使用现有requirements.txt文件
有时项目已经有一个requirements.txt文件。看看requirements.txt这个Python 网络爬虫的文件:
1 | $ cat requirements.txt |
使用该cat实用程序,可以读取文件并将内容写入标准输出。
在本例中,它显示了网络爬虫项目的依赖项。使用 创建 Poetry 项目后poetry init
,可以将该cat实用程序与poetry add
命令结合使用:
1 | $ poetry add `cat requirements.txt` |
当需求文件像这样简单时,使用poetry add和cat可以为节省一些手动工作。
但是,有时requirements.txt文件有点复杂。在这些情况下,可以执行测试运行并查看结果,或者手动将需求添加到文件中的[tool.poetry.dependencies]表中pyproject.toml。
要查看您的结构pyproject.toml是否有效,可以运行poetry check
。
从poetry.lock创建requirements.txt
在某些情况下,必须有一个requirements.txt文件。例如,想在 Heroku 上托管 Django 项目。
对于这种情况,Poetry 提供了export命令。如果有一个 Poetry 项目,可以requirements.txt从poetry.lock文件中创建一个文件:
1 | $ poetry export --output requirements.txt |
poetry export以这种方式使用该命令会创建一个requirements.txt包含散列和环境标记的文件。
这意味着可以确保处理与poetry.lock文件内容类似的非常严格的要求。
如果还想包含你的开发依赖项,可以添加–dev到命令中。要查看所有可用选项,可以输入poetry export --help
命令参考
本内容介绍了 Poetry 的依赖管理。在此过程中,使用了一些 Poetry 的命令行界面 (CLI) 命令:
Poetry 命令 | 解释 |
---|---|
$ poetry --version | 显示Poetry安装版本 |
$ poetry new | 创建一个新的Poetry项目 |
$ poetry init | 将Poetry添加到现有项目中 |
$ poetry run | 使用Poetry执行给定的命令 |
$ poetry add | 添加一个包到pyproject.toml并安装它 |
$ poetry update | 更新项目的依赖项 |
$ poetry install | 安装依赖 |
$ poetry show | 列出已安装的软件包 |
$ poetry lock | 将最新版本的依赖项固定到poetry.lock |
$ poetry lock --no-update | 刷新poetry.lock文件而不更新任何依赖版本 |
$ poetry check | 验证pyproject.toml |
$ poetry config --list | 显示Poetry配置 |
$ poetry env list | 列出项目的虚拟环境 |
$ poetry export | 导出poetry.lock为其他格式 |
可以查看Poetry CLI 文档以了解有关上述命令和 Poetry 提供的其他命令的更多信息。还可以poetry --help
直接在终端中运行以查看信息!
结论
在本教程探索了如何创建新的 Python Poetry 项目以及如何将 Poetry 添加到现有项目中。Poetry 的一个关键部分是pyproject.toml文件。与 poetry.lock 结合使用,可以确保安装项目所需的每个包的确切版本。
当跟踪poetry.lockGit 存储库中的文件时,还要确保项目中的所有其他开发人员在他们的机器上安装相同的依赖项版本。