An older project still configured its tox environments the hard way — duplicated dependency specs, redundant install commands. My newer projects had solved this years ago. Time to catch up.
In earlier years I specified the dependencies and their installation for my tox environments using two approaches. The first was to use the install_command option:
[testenv]
install_command = pip install -e '.[development]' -U {opts} {packages}
commands = pytest
Ini
It works perfectly fine and you don't need to explicitly specify the dependencies as they are already specified in setup.py:
development_extras = [
'flake8>=6.0,<7.0',
'pytest>=7.0,<8.0',
'tox>=3.28,<4.0',
]
setup(
...
extras_require={
'development': development_extras,
},
...
)
Python
But for some environments in larger projects, often linting stages like flake8 or isort, installing all dependencies was overkill. So I specified them explicitly as deps:
[testenv:flake8]
deps = flake8>=6.0,<7.0
commands = flake8 src
Ini
This is redundant. As soon as the required version of a dependency changes, I had to update it in two places. Everything I have to remember to update is a potential source of error.
tox has an extras option that handles exactly this. It installs the package's extras into the environment without duplicating version specs. First I split the dependencies within setup.py into more specific parts:
linting_extras = [
'flake8>=6.0,<7.0',
]
testing_extras = [
'pytest>=7.0,<8.0',
'tox>=3.28,<4.0',
]
development_extras = linting_extras + testing_extras
extras_require = {
'development': development_extras,
'linting': linting_extras,
'testing': testing_extras,
}
Python
Then I can use extras in tox to reference these groups directly:
[testenv]
extras = testing
commands = pytest
[testenv:flake8]
extras = linting
commands = flake8 src
Ini
One place to maintain, no way to forget. The tox config gets shorter and each environment only installs what it actually needs.
I've used this pattern in texsite, my open-source Wagtail CMS package, and in cloudapps, a course-management platform, both before migrating to uv.