🐛 fix(config): factor filter fallback to default value#3751
Merged
gaborbernat merged 2 commits intotox-dev:mainfrom Feb 18, 2026
Merged
🐛 fix(config): factor filter fallback to default value#3751gaborbernat merged 2 commits intotox-dev:mainfrom
gaborbernat merged 2 commits intotox-dev:mainfrom
Conversation
When using factor-conditional values like base_python = py312: python3.12, environments without a matching factor got an empty value instead of the config default. This caused py313 envs to silently use the wrong Python interpreter. The empty result from factor filtering was treated as a valid value, preventing the default from being applied. Now when factor filtering removes all content, a KeyError is raised so the loader falls through to the default value.
When all lines in a setting are conditional and none match the current environment, the setting falls back to its default value rather than becoming empty. This was fixed in the accompanying code change but not documented.
d7e87c2 to
65f3f71
Compare
worksbyfriday
added a commit
to worksbyfriday/tox
that referenced
this pull request
Feb 22, 2026
When {[section]key} references a value with factor-conditional lines and
no factors match, the substitution should resolve to empty string rather
than remaining unresolved as a literal reference.
The root cause: process_raw() raises KeyError when factor filtering empties
a value that originally had content (added in tox-dev#3751 to fix tox-dev#3189). For
same-section config values this is correct — it allows fallback to computed
defaults (e.g. base_python derived from env name). But for cross-section
references via SectionProxy, the KeyError propagated all the way up to
the replacer, which returned None (unresolved), leaving the literal
{[section]key} in the output.
The fix: when a SectionProxy lookup raises KeyError but the key exists in
the section, the factor filtering emptied the value — return empty string
instead of propagating the error. This preserves the tox-dev#3189 fix for
same-section config values while correctly handling cross-section references.
Fixes tox-dev#3809
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
When using factor-conditional config values like
base_python = py312: python3.12, environments whose factors don't match any conditional line silently received an empty value instead of the config default. 🐛 Forbase_pythonthis meant the wrong Python interpreter was used — e.g. apy313environment would quietly run with whatever Python tox itself was installed under, rather than thepy313spec derived from the env name.The root cause is that INI factor filtering can reduce a non-empty value to an empty string when no factors match. This empty string was treated as a valid loaded value, preventing the default from being applied. The fix detects when factor filtering empties a value that originally had content and raises
KeyError, allowing the loader to fall through to the default as intended.This affects any factor-conditional config key, not just
base_python. Previously, unmatched factor conditionals would produce empty values; now they correctly fall back to the configured or computed default.Fixes #3189.