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

推荐订阅源

F
Full Disclosure
WordPress大学
WordPress大学
小众软件
小众软件
Cloudbric
Cloudbric
AWS News Blog
AWS News Blog
腾讯CDC
量子位
人人都是产品经理
人人都是产品经理
大猫的无限游戏
大猫的无限游戏
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
V
Vulnerabilities – Threatpost
Scott Helme
Scott Helme
Hugging Face - Blog
Hugging Face - Blog
博客园_首页
C
CXSECURITY Database RSS Feed - CXSecurity.com
The Hacker News
The Hacker News
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
IT之家
IT之家
Jina AI
Jina AI
Attack and Defense Labs
Attack and Defense Labs
S
SegmentFault 最新的问题
Simon Willison's Weblog
Simon Willison's Weblog
The Cloudflare Blog
阮一峰的网络日志
阮一峰的网络日志
T
Tailwind CSS Blog
Last Week in AI
Last Week in AI
博客园 - 【当耐特】
Google Online Security Blog
Google Online Security Blog
美团技术团队
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V
Visual Studio Blog
罗磊的独立博客
L
LINUX DO - 最新话题
博客园 - Franky
博客园 - 叶小钗
Apple Machine Learning Research
Apple Machine Learning Research
The Last Watchdog
The Last Watchdog
J
Java Code Geeks
AI
AI
C
Cisco Blogs
酷 壳 – CoolShell
酷 壳 – CoolShell
C
Cyber Attacks, Cyber Crime and Cyber Security
Cisco Talos Blog
Cisco Talos Blog
博客园 - 三生石上(FineUI控件)
雷峰网
雷峰网
Help Net Security
Help Net Security
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
云风的 BLOG
云风的 BLOG
I
Intezer
S
Securelist

Keenformatics

PyLaDe Ports blocked by browsers Manually verifying an SSL certificate How to generate documentation with Sphinx How To Override Sublime Text Packages Shortcuts and Preferences How To Find out Sublime Text Key Binding Commands How To Make Terminator Behave Like Guake (Ubuntu) Sentiment Analysis lexicons and datasets Model-Driven approach vs hardcore coding
Using Tox with Poetry dependency groups
fievelk · 2024-12-26 · via Keenformatics

Poetry is one of the most famous dependency management tools for Python, and I frequently use it in place of the basic requirements.txt to simplify version management in my libraries. Despite its widespread adoption, Poetry is not fully compliant with Python’s PEPs and this sometimes leads to challenges during the development process. One such challenge I recently encountered was integrating Poetry’s “dev dependencies” with Tox.

In my projects, I usually specify two groups of dependencies with Poetry:

  • the main dependency group: these dependencies will be installed with my library as part of the regular installation process (for example: pip install my-project).
  • An additional dependency group called dev: these additional dependencies are only used during development and testing and can only be installed through Poetry (for example: poetry install --with dev).

Assuming this simple setup, the initial pyproject.toml file would look like this:

[tool.poetry]
name = "my-project"
version = "0.1.0"
authors = ["me"]

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

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

[tool.poetry.group.dev.dependencies]
pytest = "^8.3.2"
tox = "^4.23.2"

As you can see, pytest and tox are both part of the tool.poetry.group.dev.dependencies group: we don’t want them to be installed by default with our library (since most users won’t need them) but we still need to declare them, as they are necessary for development and testing.

Tox is a “generic virtual environment management and test command line tool” that can be used to run tests in multiple, isolated environments (for example different Python versions with different dependencies). For this example, let’s pretend we want Tox to run pytest on two environments: Python 3.11 and 3.12.

The following tox.ini configuration looks reasonable, but it won’t work:

[tox]
envlist =
    py312

[testenv]
description = Run tests using pytest
allowlist_externals = pytest
passenv = *
commands =
    pytest

The problem with this configuration is that Tox will not automatically install the dev dependencies we declared in pyproject.toml. Unfortunately, in fact, Poetry’s dependency groups (like our tool.poetry.group.dev.dependencies above) are not a standard and do not comply with existing PEPs, so Tox won’t detect tool.poetry.group.dev.dependencies and won’t install them.

One simple solution would be to just re-install all the dependencies needed by Tox (pytest, in our example) in tox.ini:

[tox]
envlist =
    py312

[testenv]
allowlist_externals = pytest
passenv = *
commands_pre =
    pip install pytest==8.3.4  # Install pytest explicitly before running the command below
commands =
    pytest

However, this means that we will duplicate our dependency declarations (pytest and its version are now declared both in pyproject.toml and tox.ini). This could introduce bugs and unexpected inconsistencies between our Tox environment and the one defined by pyproject.toml.

Another possible (but discouraged) way to do it would be to directly use Poetry in tox.ini to install the dev dependencies:

[tox]
envlist =
    py311
    py312

[testenv]
allowlist_externals = poetry, pytest
passenv = *
commands =
    poetry install --with dev
    pytest

While this might work, it will also make Tox aware of Poetry, which is suboptimal and unnecessary: Tox shouldn’t care about how dependencies are installed, nor should it explicitly install them. In fact, by default Tox looks into the [build-system] section of pyproject.toml and uses its value to delegate the dependencies’ build process to the correct backend (poetry.core.masonry.api in our case). This means that we don’t need to explicitly mention poetry in our tox.ini, because Tox already knows about its build system.

The solution

So Tox will use Poetry’s build-backend to install dependencies. But how do we make Tox aware of Poetry’s development dependency group? Simply put: we don’t. As I mentioned, Poetry dependency groups are non-standard and Tox is not aware of them. However, we can use another field that is, in fact, defined in the standard specification for Python packaging (PEP 508): extras.

The pyproject.toml then becomes:

[tool.poetry]
name = "my-project"
version = "0.1.0"
authors = ["me"]

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

[tool.poetry.dependencies]
python = "^3.11"
# Specify the optional dependencies that will be used below as "extras"
pytest = { version = "^8.3.2", optional = true }

# List the extra dependencies from the dependencies we defined above.
# This is used in place of tool.poetry.group.dev.dependencies.
[tool.poetry.extras]
dev = ["pytest"]

# Define dependencies that will be installed by developers using Poetry
[tool.poetry.group.dev.dependencies]
tox = "^4.23.2"

Final notes

Poetry’s popularity reflects the the broad appreciation of Python’s community. However, its widespread adoption also creates constrains regarding backward compatibility, making it challenging for the team to support new PEP standards especially when this involves dropping existing features that users rely on. At the same time, I would feel more confident using tools that fully comply with current standards. Package managers like Hatch or PDM seem to offer this, although their user bases seem significantly smaller than Poetry’s.

On the bright side, PEP 735, a new standard for dependency groups, was recently accepted. Hopefully, this can be a step towards moving Python dependency management tools in the direction of further standardization.

Resources