常见问题解答

常见问题解答 #

为什么依赖解析过程很慢? #

虽然 Poetry 核心的依赖解析器经过高度优化,对于大多数情况来说应该足够快,但在某些依赖项集合中,找到有效的解决方案可能需要时间。

这是因为并非所有 PyPI 上的库都正确声明了它们的元数据,因此无法通过 PyPI JSON API 获取它们。此时,Poetry 别无选择,只能下载这些包并检查它们以获取必要的信息。这是一个昂贵的操作,无论是在带宽还是时间上,这就是为什么它看起来是一个漫长的过程。

目前还没有解决方法。但是,如果你注意到 Poetry 正在下载同一个包的多个版本,你可以通过在你的 pyproject.toml 中更严格地约束该包来减轻工作量。这样,Poetry 就不用筛选那么多版本,这在某些情况下可能会大大加快锁定过程。

注意
一旦 Poetry 在你的机器上缓存了发行版信息,依赖解析过程就会快得多。

Poetry 使用什么类型的版本控制方案? #

Poetry 使用“major.minor.micro”版本标识符,如 PEP 440 中所述。

版本升级与 Python 的版本控制类似

  • 主版本升级(增加第一个数字)仅在发生重大变更时进行,前提是无法进行弃用周期,并且许多用户必须执行一些手动步骤才能从一个版本迁移到下一个版本。
  • 次版本升级(增加第二个数字)可能包括新功能以及新的弃用和删除在早期次版本中弃用的功能。
  • 微版本升级(增加第三个数字)通常只包括错误修复。弃用的功能不会在微版本中删除。

为什么 Poetry 不遵循语义化版本控制? #

由于其庞大的用户群,即使大多数用户认为不相关的微小更改,事后看来也可能成为某些用户的重大变更。坚持严格的 语义化版本控制 并且(几乎)总是升级主版本而不是次版本似乎不可取,因为次版本将不再具有任何意义。

无界版本约束是一个坏主意吗? #

没有上限的版本约束,例如 *>=3.4,将允许更新到依赖项的任何未来版本。这包括破坏向后兼容性的主版本。

一旦你的包发布,你就无法再调整它的依赖项,以防依赖项破坏 BC - 你必须进行新的发布,但之前的发布仍然是损坏的。(用户仍然可以通过自己限制依赖项来解决损坏的依赖项。)

为了避免此类问题,你可以在约束中定义一个上限,你可以在测试你的包与依赖项的新主版本兼容后,在新的发布中增加这个上限。

例如,你可以使用 ^3.4 而不是 >=3.4,它允许所有版本 <4.0^ 运算符与遵循 语义化版本控制 的库配合得很好。

但是,在定义上限时,即使你的包的用户能够更新依赖项,即使它没有破坏任何东西并且与你的包完全兼容,他们也无法将依赖项更新到上限之外。你必须先发布一个具有增加上限的新版本包。

如果你的包将用作其他包中的库,最好避免使用上限,从而避免不必要的依赖冲突(除非你已经确定依赖项的下一个版本会破坏你的包)。如果你的包将用作应用程序,定义上限可能会有所帮助。

tox 是否受支持? #

是的。只要你使用 tox >= 4,你就可以将其与 Poetry 提供的符合 PEP 517 的构建系统结合使用。(使用 tox 3,你必须设置 隔离构建 选项。)

因此,在你的 pyproject.toml 文件中,如果它不存在,请添加以下部分

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

tox 可以通过多种方式进行配置。这取决于要测试的代码以及要安装的依赖项。

用例 #1 #

[tox]

[testenv]
deps =
    pytest
commands =
    pytest tests/ --import-mode importlib

tox 将创建项目的 sdist 包,并使用 pip 将其安装到一个新的环境中。因此,依赖项由 pip 解决。

用例 #2 #

[tox]

[testenv]
allowlist_externals = poetry
commands_pre =
    poetry install --no-root --sync
commands =
    poetry run pytest tests/ --import-mode importlib

tox 将创建项目的 sdist 包,并使用 pip 将其安装到一个新的环境中。因此,依赖项首先由 pip 解决。但之后我们将运行 Poetry,它将把锁定的依赖项安装到环境中。

用例 #3 #

[tox]

[testenv]
skip_install = true
allowlist_externals = poetry
commands_pre =
    poetry install
commands =
    poetry run pytest tests/ --import-mode importlib

tox 不会执行任何安装。Poetry 安装所有依赖项,并将当前包以可编辑模式安装。因此,测试针对的是本地文件,而不是构建和安装的包。

关于凭据的说明 #

请注意,默认情况下,tox 不会转发当前 shell 会话的环境变量。如果在 Linux 系统上使用系统密钥环或使用环境变量配置凭据,这可能会导致 Poetry 无法在 tox 环境中安装依赖项。你可以使用 passenv 配置选项 显式转发所需的变量,或者使用 passenv = "*" 转发所有变量。Linux 系统可能需要转发 DBUS_SESSION_BUS_ADDRESS 变量以允许访问系统密钥环,但这可能因桌面环境而异。

或者,你可以完全禁用密钥环

poetry config keyring.enabled false

请注意,这会导致 Poetry 将密码写入纯文本配置文件。更改此设置后,你需要重新设置凭据。

Nox 是否受支持? #

使用 nox-poetry 包将 poetry.lock 中指定的依赖项的锁定版本安装到 Nox 会话中。

我不希望 Poetry 管理我的虚拟环境。我可以禁用它吗? #

虽然 Poetry 自动创建虚拟环境以始终与全局 Python 安装隔离,但在某些情况下,使用 Poetry 管理的虚拟环境是不可能的或不必要的。

在这种情况下,你可以通过将 virtualenvs.create 设置设置为 false 来禁用此功能

poetry config virtualenvs.create false
警告

推荐的最佳实践,包括在容器中安装应用程序时,是使用虚拟环境。这也可以由其他工具管理。

Poetry 团队强烈建议使用虚拟环境。

为什么 Poetry 告诉我当前项目的支持 Python 范围与一个或多个包的 Python 要求不兼容? #

pip 不同,Poetry 不会仅针对当前环境中的 Python 进行解析。相反,它确保依赖项在 pyproject.toml 中给定的 Python 版本范围内可解析。

假设你具有以下 pyproject.toml

[tool.poetry.dependencies]
python = "^3.7"

这意味着你的项目旨在与任何 Python 版本 >=3.7,<4.0 兼容。每当你尝试添加一个 Python 要求与整个范围不匹配的依赖项时,Poetry 都会告诉你这一点,例如

The current project's supported Python range (>=3.7.0,<4.0.0) is not compatible with some of the required packages Python requirement:
    - scipy requires Python >=3.7,<3.11, so it will not be satisfied for Python >=3.11,<4.0.0

通常,你希望将项目的支持 Python 范围与失败依赖项的上限匹配。或者,如果你知道它并非在所有版本中都需要,你可以告诉 Poetry 仅针对特定范围的 Python 版本安装此依赖项

为什么 Poetry 强制执行 PEP 440 版本? #

这样做是为了符合更广泛的 Python 生态系统。

例如,如果 Poetry 为使用不符合 PEP 440 的版本的项目构建分发,第三方工具将无法正确解析该版本。

Poetry 破坏了我的 Docker 缓存,因为它要求我在安装第三方依赖项之前复制源文件 #

默认情况下,运行 poetry install ... 需要你拥有源文件(包括“根”包和可能拥有的任何目录路径依赖项)。这与 Docker 的缓存机制交互不佳,因为对源文件的任何更改都会使任何层(Dockerfile 中的后续命令)重新运行。例如,你的 Dockerfile 可能如下所示

FROM python
COPY pyproject.toml poetry.lock .
COPY src/ ./src
RUN pip install poetry && poetry install --only main

只要任何源文件发生更改,RUN 层的缓存就会失效,这将强制重新安装所有第三方依赖项(可能是这些步骤中最慢的一步),如果你更改了 src/ 中的任何文件。

为了避免这种缓存失效,你可以将此步骤分成两步

  1. 安装第三方依赖项。
  2. 复制源代码并仅安装源代码。

这可能看起来像这样

FROM python
COPY pyproject.toml poetry.lock .
RUN pip install poetry && poetry install --only main --no-root --no-directory
COPY src/ ./src
RUN poetry install --only main

我们在这里使用的两个关键选项是 --no-root(跳过安装项目源代码)和 --no-directory(跳过安装任何本地目录路径依赖项,如果你没有,可以省略此选项)。有关 poetry install 可用选项的更多信息

我的请求超时了! #

Poetry 的默认 HTTP 请求超时时间为 15 秒,与 pip 相同。与 PIP_REQUESTS_TIMEOUT 类似,实验性环境变量 POETRY_REQUESTS_TIMEOUT 可以设置为更改此值。