Skip to content

🐛 fix(env): reject partial testenv section matches#3753

Merged
gaborbernat merged 1 commit intotox-dev:mainfrom
gaborbernat:fix-partial-testenv-match-3219
Feb 18, 2026
Merged

🐛 fix(env): reject partial testenv section matches#3753
gaborbernat merged 1 commit intotox-dev:mainfrom
gaborbernat:fix-partial-testenv-match-3219

Conversation

@gaborbernat
Copy link
Copy Markdown
Member

When a testenv section uses generative syntax like [testenv:functional{-py310}], only functional-py310 should be a valid environment. However, running tox -e functional-py312 or tox -e functional silently passed validation and fell back to the base [testenv], producing unexpected results. 🔍 This was a regression from tox 3, where these would correctly error as unknown environments.

The root cause was that _ensure_envs_valid decomposed all known env names — including those from section headers — into individual factors, then treated them as freely combinable. So functional (from functional-py310) became a valid factor that could be mixed with any Python version factor. The fix distinguishes between factors that are genuinely combinable (from env_list generative expressions and conditional markers) and complete env names from section headers. Section names are recognized as whole identifiers but their component parts can no longer be arbitrarily recombined via -e.

⚠️ This is a behavioral change: users who relied on partial section name matching to silently fall back to [testenv] will now get a clear error message pointing them to the correct environment name. Matrix-style env_list combinations like py312-django50 continue to work as expected.

Fixes #3219

Previously, `_ensure_envs_valid` decomposed all known env names
(including section headers like `functional-py310`) into individual
factors, making them freely combinable. This meant `tox -e
functional-py312` would silently pass validation and fall back to
the base testenv, even though only `functional{-py310}` was defined.

The fix distinguishes between combinable factors (from env_list and
conditional markers) and fixed env names from section headers. Section
names are accepted as whole identifiers but their component parts
can no longer be freely recombined with arbitrary factors.

Fixes tox-dev#3219
@gaborbernat gaborbernat added the bug:normal affects many people or has quite an impact label Feb 18, 2026
@gaborbernat gaborbernat enabled auto-merge (squash) February 18, 2026 07:51
@gaborbernat gaborbernat merged commit 4bcb661 into tox-dev:main Feb 18, 2026
28 checks passed
@edabor
Copy link
Copy Markdown

edabor commented Feb 19, 2026

Hello !

First, let me thank you for providing such powerful tool. It has greatly helped simplifying CI in pyvista

It seems that this PR now prevents using complex factor conditions as described in https://tox.wiki/en/3.27.1/config.html#complex-factor-conditions
I recognize it was documented in an old version of tox that disappeared in latest docs (#3276) but it was working as I expected it before this PR.

Here is MWE with the behavior changes induced by this PR:

[tox]

env_list = py3.{10-14}

[testenv]

deps =
    matplotlib
    np: numpy
    np-cov: coverage
command before this PR This PR
tox r -e py3.10-np-cov installs coverage, matplotlib and numpy HandledError | provided environments not found in configuration file

We managed to find a workaround in pyvista/pyvista#8343 by explicitly declaring factors but I was curious if this behavior change introduced by this PR was intentional.

Thanks in advance.

gaborbernat added a commit to gaborbernat/tox that referenced this pull request Feb 20, 2026
PR tox-dev#3753 restricted env name validation to prevent section header names
from being split into freely combinable factors. However, it also
prevented factor-conditional-discovered env names (like `np-cov` from
`np-cov: coverage`) from contributing their individual factors. This
caused `tox -e py310-np-cov` to fail with "provided environments not
found" when compound factor conditionals were used in the config.

The fix distinguishes between section header env names (kept as whole
identifiers) and factor-conditional env names (split into individual
combinable factors), restoring the expected behavior.

Fixes tox-dev#3780
gaborbernat added a commit to gaborbernat/tox that referenced this pull request Feb 20, 2026
PR tox-dev#3753 restricted env name validation to prevent section header names
from being split into freely combinable factors. However, it also
prevented factor-conditional-discovered env names (like `np-cov` from
`np-cov: coverage`) from contributing their individual factors. This
caused `tox -e py310-np-cov` to fail with "provided environments not
found" when compound factor conditionals were used in the config.

The fix distinguishes between section header env names (kept as whole
identifiers) and factor-conditional env names (split into individual
combinable factors), restoring the expected behavior.

Fixes tox-dev#3780
gaborbernat added a commit that referenced this pull request Feb 20, 2026
PR #3753 fixed section header names from being decomposed into freely
combinable factors, preventing `tox -e functional-py312` from silently
falling back to `[testenv]` when only `[testenv:functional{-py310}]` was
defined. However, it also broke compound factor conditionals like
`np-cov: coverage` — running `tox -e py310-np-cov` would fail with
"provided environments not found" because the individual factor `cov`
(from the compound conditional `np-cov`) was no longer recognized as
combinable.

🔍 The fix distinguishes between env names from section headers and env
names discovered from factor conditionals. Section header names remain
valid only as whole identifiers (preserving the #3753 fix), while
factor-conditional env names have their individual factors added to the
combinable set. This is done by collecting section-derived env names via
`Config.sections()` and treating everything else in `known_envs` (minus
`env_list`) as factor-conditional — splitting those into individual
factors.

Fixes #3780
@gaborbernat gaborbernat deleted the fix-partial-testenv-match-3219 branch February 20, 2026 07:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bot:chronographer:provided bug:normal affects many people or has quite an impact

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Partial match on testenv results in use of base testenv

2 participants