Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: tox-dev/tox
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 4.36.1
Choose a base ref
...
head repository: tox-dev/tox
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 4.37.0
Choose a head ref
  • 14 commits
  • 34 files changed
  • 6 contributors

Commits on Feb 17, 2026

  1. feat(release): use GitHub auto-generated release notes

    Replace manual changelog extraction with --generate-notes flag to use
    GitHub's automatic release notes based on PRs and commits.
    
    Signed-off-by: Bernát Gábor <bgabor8@bloomberg.net>
    gaborbernat committed Feb 17, 2026
    Configuration menu
    Copy the full SHA
    03ebf9c View commit details
    Browse the repository at this point in the history
  2. ✨ feat(config): add extra_setup_commands for --notest phase (#3716)

    When running `tox --notest` in CI pipelines, teams need to separate
    dependency installation from test execution. The existing
    `commands_pre`, `commands`, and `commands_post` all run during the test
    phase and are completely skipped with `--notest`, leaving no way to run
    setup tasks during the installation phase. 🔧
    
    A common use case is installing pre-commit hooks with `pre-commit
    install-hooks` during the `--notest` phase, then running `pre-commit
    run` as the actual test command in a separate CI step. This separation
    allows faster feedback and better resource utilization in CI
    environments.
    
    This PR introduces `extra_setup_commands` that executes after all
    installations (dependencies and package) complete but before the test
    phase begins. ✨ These commands run during `--notest`, enabling users to
    prepare their environment with tools and hooks while deferring test
    execution to a separate step.
    
    The implementation adds the configuration option to `PythonRun`
    environments only, deliberately excluding packaging environments to
    maintain their clean separation of concerns. Commands execute with the
    same change directory and error handling semantics as other command
    sets.
    
    Resolves #1504
    
    ---------
    
    Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
    gaborbernat and pre-commit-ci[bot] authored Feb 17, 2026
    Configuration menu
    Copy the full SHA
    1e2e12b View commit details
    Browse the repository at this point in the history
  3. 🐛 fix(release): format changelog with pre-commit before committing (#…

    …3717)
    
    The release process generates `changelog.rst` using towncrier, but
    towncrier's output doesn't always match our pre-commit formatting rules.
    📝 This leads to the release commit containing unformatted changelog text
    that later gets flagged by CI, requiring follow-up formatting commits.
    
    This PR modifies the release script to run pre-commit on the generated
    `changelog.rst` immediately after towncrier builds it but before
    creating the release commit. The pre-commit hooks apply all necessary
    formatting (line wrapping, trailing whitespace removal, etc.) so the
    changelog is properly formatted from the start.
    
    The implementation catches and handles the case where pre-commit makes
    changes (exit code 1), stages those changes, and includes them in the
    release commit. This keeps the release history clean without requiring
    manual intervention or subsequent formatting commits.
    
    Signed-off-by: Bernát Gábor <bgabor8@bloomberg.net>
    gaborbernat authored Feb 17, 2026
    Configuration menu
    Copy the full SHA
    5191a92 View commit details
    Browse the repository at this point in the history
  4. 📝 docs: restructure documentation using Diátaxis framework (#3718)

    The documentation was organized in a flat structure that mixed
    tutorials, how-to guides, reference material, and conceptual
    explanations together. Users had difficulty finding information
    appropriate to their skill level and immediate needs. 📚 New users
    couldn't distinguish between learning materials and quick reference,
    while experienced users had to wade through explanatory content to find
    technical specifications.
    
    Adopted the Diátaxis documentation framework that organizes content by
    user needs rather than topics. The structure now separates Tutorial
    (learning-oriented), How-to guides (task-oriented), Reference
    (information-oriented), and Explanation (understanding-oriented). This
    matches the structure used by virtualenv and follows modern
    documentation best practices. Files were moved to appropriate
    directories, cross-references updated throughout, and installation
    documentation reorganized to use tabs for tool-specific details. Python
    compatibility specifications moved from installation guide to
    configuration reference where technical requirements belong.
    
    The new structure makes it immediately clear where to look: beginners
    start with the tutorial, practitioners consult how-to guides for
    specific tasks, developers check reference for technical details, and
    everyone can deepen understanding through explanations when needed.
    gaborbernat authored Feb 17, 2026
    Configuration menu
    Copy the full SHA
    f17313e View commit details
    Browse the repository at this point in the history
  5. 🐛 fix(pip): set PIP_USER=0 to prevent --user installs in virtualenvs (#…

    …3719)
    
    Users with `pip config --user` configured globally experienced
    installation failures in tox virtualenvs. 🐛 When pip attempted to honor
    the `--user` flag inside virtualenvs, it crashed because user
    site-packages aren't visible in isolated environments.
    
    This regression was introduced during the tox 4 rewrite. Tox 3 correctly
    set `PIP_USER=0` to override user configuration, but this protection was
    lost in the rewrite. The fix restores this behavior by setting the
    environment variable in all virtualenv-based Python environments.
    
    The solution follows pip's documented environment variable precedence
    where `PIP_USER=0` explicitly disables `--user` installs regardless of
    config file settings. This preserves user workflows while ensuring tox
    virtualenvs remain isolated. ✨
    
    Fixes #3010
    gaborbernat authored Feb 17, 2026
    Configuration menu
    Copy the full SHA
    6450988 View commit details
    Browse the repository at this point in the history
  6. 🐛 fix(config): prevent env_run_base deps from being clobbered (#3721)

    When users configure TOML environments with `deps =
    ["{[tool.tox.env_run_base]deps}", "extra-dep"]`, the additional
    dependencies were silently dropped and only the base section deps were
    installed. This breaks a natural pattern for extending base
    configurations, making it impossible to share common dependencies across
    environments while adding environment-specific ones. 🔧
    
    The configuration reference expansion logic incorrectly treated
    `env_run_base` and `env_pkg_base` as regular test environments because
    their section names start with the environment prefix `tool.tox.env`.
    This caused the system to attempt creating a virtual environment named
    `run_base` instead of reading the raw configuration values, breaking the
    reference expansion and silently discarding any additional dependencies
    in the list.
    
    The fix adds an explicit check to exclude these special base sections
    from environment resolution, ensuring they're always treated as raw
    configuration sections. This preserves the intended behavior where base
    sections can be referenced alongside additional values without data
    loss. ✨
    
    Closes #3393
    
    ---------
    
    Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
    gaborbernat and pre-commit-ci[bot] authored Feb 17, 2026
    Configuration menu
    Copy the full SHA
    0ee48ce View commit details
    Browse the repository at this point in the history
  7. Fix env name with dot losing description in TOML config (#3722)

    ## Description
    
    Fixes #3590
    
    Environment names containing dots (e.g. `"py3.11"`) in `pyproject.toml`
    had their descriptions silently ignored. `tox list` showed `[no
    description]` instead of the configured description.
    
    ### Reproducer
    
    ```toml
    [tool.tox.env."py3.11"]
    description = "tox test"
    ```
    
    ```console
    $ tox list
    py3.11 -> [no description]
    ```
    
    ### Root cause
    
    Three interrelated issues in `toml_pyproject.py`:
    
    1. **`sections()` split the env name on dots**: `from_key("py3.11")`
    treats `.` as the section separator, creating `Section(prefix="py3",
    name="11")` instead of preserving `"py3.11"` as the name.
    
    2. **`keys` property split ALL dots**: The full key
    `"tool.tox.env.py3.11"` was split into `["env", "py3", "11"]`.
    `get_loader()` then tried to traverse `dict["py3"]["11"]` instead of
    `dict["py3.11"]`, returning `None` (config not found).
    
    3. **`envs()` yielded full key**: When `sections()` is fixed to use
    `test_env()`, the full key becomes `"tool.tox.env.py3.11"` instead of
    just `"py3.11"`, causing a phantom duplicate environment.
    
    ### Fix
    
    - **`keys` property**: Build from `prefix` and `name` components
    directly instead of splitting the joined key on `SEP`. This preserves
    dots within the env name while still splitting structural path
    separators.
    - **`sections()`**: Use `test_env(env_name)` which correctly sets
    `prefix="tool.tox.env"` and `name="py3.11"` as an atomic unit.
    - **`envs()`**: Yield `section.name` instead of `section.key` to return
    just the env name.
    - **`get_base_sections()`**: Use `test_env()` for consistency.
    
    ### After fix
    
    ```console
    $ tox list
    py3.11 -> tox test
    ```
    
    ---------
    
    Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
    Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
    3 people authored Feb 17, 2026
    Configuration menu
    Copy the full SHA
    83b3ed8 View commit details
    Browse the repository at this point in the history
  8. 🐛 fix(ci): add completion extras to type checker environments (#3728)

    The `type` and `type-min` CI environments fail because `ty` cannot
    resolve the `argcomplete` module imported in
    `src/tox/config/cli/parse.py` and
    `tests/config/cli/test_argcomplete.py`. While `env_run_base` declares
    `extras = ["completion"]`, the type environments weren't picking it up
    reliably, causing `error[unresolved-import]` on fresh CI runs.
    
    🔧 The fix explicitly sets `extras = ["completion"]` on both `env.type`
    and `env.type-min` in `tox.toml`, reusing the existing
    `optional-dependencies.completion` that already defines
    `argcomplete>=3.6.3` rather than duplicating the dependency.
    gaborbernat authored Feb 17, 2026
    Configuration menu
    Copy the full SHA
    0d3f901 View commit details
    Browse the repository at this point in the history
  9. Fix factor selection via TOX_FACTORS environment variable (#3725)

    ## Summary
    - Fix `TOX_FACTORS` env var producing wrong results (each character
    treated as a separate factor instead of each factor string)
    - Root cause: `get_type()` inferred `list[str]` for `_AppendAction` with
    `nargs="+"`, but the actual runtime type is `list[list[str]]`
    - The existing `Convert` infrastructure already handles nested generics,
    so fixing the type inference is sufficient
    
    Closes #3557
    
    ## Test plan
    - [x] Added parametrized test `test_factor_select_via_env_var` covering
    single factor, AND (comma-separated), and OR (semicolon-separated)
    - [x] All 65 env_select tests pass
    - [x] All 6355 config tests pass
    - [x] All 6 CLI env var tests pass
    
    🤖 Generated with [Claude Code](https://claude.com/claude-code)
    
    ---------
    
    Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
    Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
    3 people authored Feb 17, 2026
    Configuration menu
    Copy the full SHA
    e7a0800 View commit details
    Browse the repository at this point in the history
  10. Fix setenv PATH modifications being overwritten (#3723)

    ## Summary
    - Fixes #3445
    - When `setenv` modifies `PATH`, those modifications were being silently
    overwritten when tox set up environment paths (via the `_paths` setter)
    - The `_paths` setter directly wrote to `_env_vars["PATH"]` using
    `_make_path()`, which only includes tox-managed paths — losing any
    user-defined PATH modifications from `setenv`
    
    ## Fix
    Changed the `_paths` setter to invalidate the `_env_vars` cache (set to
    `None`) instead of directly modifying `PATH`. This ensures the
    `environment_variables` property rebuilds from scratch on next access,
    properly incorporating both `setenv` PATH modifications and tox-managed
    paths in the correct order.
    
    ## Test plan
    - [x] Verified the fix resolves the issue described in #3445
    - [x] The `environment_variables` property already handles merging
    setenv with system PATH correctly — the bug was only in the setter
    bypassing this logic
    - [x] Added changelog fragment
    
    🤖 Generated with [Claude Code](https://claude.com/claude-code)
    
    ---------
    
    Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
    Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
    3 people authored Feb 17, 2026
    Configuration menu
    Copy the full SHA
    d81aae7 View commit details
    Browse the repository at this point in the history
  11. Fix extras with underscores not matching hyphenated metadata (#3727)

    ## Summary
    
    Fixes #3433 — extras with underscores in `tox.ini` (e.g. `snake_case`)
    were not matching hyphenated extra names in package metadata (e.g.
    `Provides-Extra: snake-case`), causing their dependencies to be silently
    skipped.
    
    ## Root cause
    
    `dependencies_with_extras_from_markers()` compared `todo` (from tox.ini
    extras) against `extra_markers` (from metadata markers) using set
    intersection, but neither side was normalized. When setuptools
    normalizes underscores to hyphens in wheel metadata, `"snake_case" &
    {"snake-case"}` produces an empty set, skipping all dependencies for
    that extra.
    
    ## Fix
    
    Normalize extra names using `canonicalize_name()` (from
    `packaging.utils`, already imported) at three points:
    1. **Requested extras** from tox.ini — normalized when building the
    `todo` set
    2. **Extra markers** from metadata — normalized when extracting from
    dependency markers
    3. **Recursive extras** from `req.extras` — normalized when discovered
    during resolution
    
    This ensures underscore/hyphen equivalence throughout the resolution
    process, consistent with PEP 685.
    
    ## Tests
    
    Added three test cases:
    - `test_extras_underscore_hyphen_matching` — underscores in extras match
    hyphens in markers
    - `test_extras_underscore_in_markers` — hyphens in extras match
    underscores in markers
    - `test_extras_normalization_with_recursive` — recursive extras with
    underscore/hyphen mismatch
    
    All existing tests pass (the `test_load_dependency_no_extra` ordering
    failure is pre-existing on main).
    
    ---------
    
    Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
    Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
    3 people authored Feb 17, 2026
    Configuration menu
    Copy the full SHA
    00f79b9 View commit details
    Browse the repository at this point in the history
  12. Fix install_command ignored from TOML config (#3724)

    ## Summary
    
    Fixes #3574 — custom `install_command` was silently ignored when
    specified in `tox.toml` or `pyproject.toml`, always falling back to the
    default pip install command.
    
    ### Root cause
    
    Two bugs conspired to produce this behavior:
    
    1. **`get_base_sections` placed base sections under the `env`
    namespace.** It used `test_env(b)` which wraps the section name under
    `env.*`, but `env_run_base` and `env_pkg_base` are top-level sections —
    `[env_run_base]` in `tox.toml` and `[tool.tox.env_run_base]` in
    `pyproject.toml`. This caused the loader to navigate to
    `env.env_run_base` (which doesn't exist) and return `None`, so no
    settings from `env_run_base` were applied.
    
    2. **The TOML replacement engine raised on unknown `{...}`
    placeholders.** When `Unroll` processed strings like `{packages}` inside
    an `install_command` array, `TomlReplaceLoader` tried to resolve
    `packages` as a config key, failed with `KeyError`, and raised — causing
    the config loader to fall through to the default. The INI loader's
    equivalent (`ReplaceReferenceIni`) returns `None` for unresolvable
    references (keeping the original text), matching the documented contract
    of `ReplaceReference.__call__`.
    
    ### Changes
    
    - **`toml_pyproject.py`**: `get_base_sections` now constructs sections
    with the core prefix (or `None`), correctly placing
    `env_run_base`/`env_pkg_base` at the top level rather than under `env`.
    - **`_replace.py`**: `TomlReplaceLoader.__call__` returns `None`
    (instead of raising) when a `KeyError` occurs with no default,
    consistent with the INI loader and the `ReplaceReference` protocol.
    - **Test**: Parameterized test verifying `install_command` is respected
    from both `tox.toml` and `pyproject.toml`.
    - **Changelog**: Added `docs/changelog/3574.bugfix.rst`.
    
    ### Test plan
    
    - [x] New parameterized test (`tox.toml` and `pyproject.toml` variants)
    - [x] All 27 show_config tests pass
    - [x] All 143 config/loader/source tests pass
    - [x] All 49 pip install tests pass
    
    ---------
    
    Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
    Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
    3 people authored Feb 17, 2026
    Configuration menu
    Copy the full SHA
    e84002a View commit details
    Browse the repository at this point in the history
  13. Fix deps with ~= version specifier treated as local paths (#3726)

    ## Summary
    - Fix `deps = pre-commit ~= 4` being treated as a local path instead of
    an invalid requirement
    - Root cause: `packaging.Requirement()` rejects `~=` with single-segment
    versions (PEP 440 requires 2+ segments), then tox's fallback treats the
    `~` as a tilde home directory path
    - Fix: detect PEP 440 version specifier operators before path detection,
    keep the string as-is for pip to give a clear error
    
    Closes #3447
    
    ## Test plan
    - [x] Added parametrized test for `pre-commit ~= 4` and `pre-commit~=4`
    - [x] All 104 req file tests pass
    - [x] All 49 pip install tests pass
    
    🤖 Generated with [Claude Code](https://claude.com/claude-code)
    
    ---------
    
    Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
    Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
    3 people authored Feb 17, 2026
    Configuration menu
    Copy the full SHA
    f80405e View commit details
    Browse the repository at this point in the history
  14. release 4.37.0

    gaborbernat committed Feb 17, 2026
    Configuration menu
    Copy the full SHA
    ab4fc8c View commit details
    Browse the repository at this point in the history
Loading