Fix install_command ignored from TOML config#3724
Conversation
|
Addressed the review feedback: removed single-letter variables, compacted comments and the |
|
Converted to draft. Rebased on main — will mark ready once CI passes. |
|
CI update: all test jobs pass on all platforms (3.9-3.14, Ubuntu/Windows/macOS) and all type/type-min jobs pass. The only failures are |
Let's bump the timeout for those then, can be part of this PR. |
Two bugs prevented install_command from working in TOML configuration:
1. get_base_sections used test_env() for base sections (env_run_base,
env_pkg_base), placing them under the env namespace. But base sections
are top-level — env_run_base lives at [env_run_base] in tox.toml and
[tool.tox.env_run_base] in pyproject.toml, not under [env].
2. The TOML replacement engine (Unroll) raised KeyError when encountering
{packages} or {opts} placeholders in string values, because it tried
to resolve them as config references. The INI loader returns None for
unknown references (keeping the original text); the TOML loader raised
instead. This caused the config loader to fall through to the default
install_command.
Fixes tox-dev#3574.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
for more information, see https://pre-commit.ci
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use shell_cmd() for expected output so quoting matches the platform (shlex.quote on Unix, list2cmdline on Windows). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
a8a2618 to
adc65ff
Compare
Summary
Fixes #3574 — custom
install_commandwas silently ignored when specified intox.tomlorpyproject.toml, always falling back to the default pip install command.Root cause
Two bugs conspired to produce this behavior:
get_base_sectionsplaced base sections under theenvnamespace. It usedtest_env(b)which wraps the section name underenv.*, butenv_run_baseandenv_pkg_baseare top-level sections —[env_run_base]intox.tomland[tool.tox.env_run_base]inpyproject.toml. This caused the loader to navigate toenv.env_run_base(which doesn't exist) and returnNone, so no settings fromenv_run_basewere applied.The TOML replacement engine raised on unknown
{...}placeholders. WhenUnrollprocessed strings like{packages}inside aninstall_commandarray,TomlReplaceLoadertried to resolvepackagesas a config key, failed withKeyError, and raised — causing the config loader to fall through to the default. The INI loader's equivalent (ReplaceReferenceIni) returnsNonefor unresolvable references (keeping the original text), matching the documented contract ofReplaceReference.__call__.Changes
toml_pyproject.py:get_base_sectionsnow constructs sections with the core prefix (orNone), correctly placingenv_run_base/env_pkg_baseat the top level rather than underenv._replace.py:TomlReplaceLoader.__call__returnsNone(instead of raising) when aKeyErroroccurs with no default, consistent with the INI loader and theReplaceReferenceprotocol.install_commandis respected from bothtox.tomlandpyproject.toml.docs/changelog/3574.bugfix.rst.Test plan
tox.tomlandpyproject.tomlvariants)