Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-build for openSUSE:Factory 
checked in at 2026-05-04 21:17:09
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-build (Old)
 and      /work/SRC/openSUSE:Factory/.python-build.new.30200 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-build"

Mon May  4 21:17:09 2026 rev:18 rq:1350557 version:1.5.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-build/python-build.changes        
2026-04-18 21:31:44.962270897 +0200
+++ /work/SRC/openSUSE:Factory/.python-build.new.30200/python-build.changes     
2026-05-04 21:17:16.759989261 +0200
@@ -1,0 +2,18 @@
+Sun May  3 18:04:12 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 1.5.0:
+  * Drop Python 3.9 support - by :user:`henryiii` (:issue:`1036`)
+  * Make --ignore-installed opt-in from the API via fresh=True -
+    by :user:`henryiii` (:issue:`1056`)
+  * Fix release pipeline generating CHANGELOG.rst entries with
+    inconsistent heading levels, which broke sphinx -W and pinned
+    Read the Docs stable at 1.4.0 - by :user:`gaborbernat`.
+  * Revert :pr:`1039` from build 1.4.3, no longer check
+    direct_url (for now) - by :user:`henryiii` (:issue:`1039`)
+  * Add --ignore-installed to pip install command to prevent
+    issues with packages already present in the isolated build
+    environment - by :user:`henryiii` (:issue:`1037`)
+  * Partial revert of :pr:`973`, keeping log messages in one
+    entry, multiple lines. (:issue:`1044`)
+
+-------------------------------------------------------------------

Old:
----
  build-1.4.3.tar.gz

New:
----
  build-1.5.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-build.spec ++++++
--- /var/tmp/diff_new_pack.ixrRxu/_old  2026-05-04 21:17:17.288010884 +0200
+++ /var/tmp/diff_new_pack.ixrRxu/_new  2026-05-04 21:17:17.292011048 +0200
@@ -33,7 +33,7 @@
 %endif
 %{?sle15_python_module_pythons}
 Name:           python-build%{psuffix}
-Version:        1.4.3
+Version:        1.5.0
 Release:        0
 Summary:        Simple PEP517 package builder
 License:        MIT

++++++ build-1.4.3.tar.gz -> build-1.5.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/build-1.4.3/.github/workflows/pre-release.yml 
new/build-1.5.0/.github/workflows/pre-release.yml
--- old/build-1.4.3/.github/workflows/pre-release.yml   2026-04-10 
23:24:52.000000000 +0200
+++ new/build-1.5.0/.github/workflows/pre-release.yml   2026-04-30 
05:17:22.000000000 +0200
@@ -29,7 +29,7 @@
           persist-credentials: false
           token: ${{ secrets.GH_RELEASE_TOKEN }}
       - name: Install the latest version of uv
-        uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # 
v8.0.0
+        uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # 
v8.1.0
         with:
           enable-cache: true
           cache-dependency-glob: "pyproject.toml"
@@ -45,6 +45,8 @@
           git config user.email "$(echo "$user_info" | jq -r '.id')+$(echo 
"$user_info" | jq -r '.login')@users.noreply.github.com"
       - name: Generate release commit and tag
         run: uv tool run --with tox-uv tox r -e release -- --version "${{ 
inputs.bump }}" --no-push
+      - name: Verify docs build against the release commit
+        run: uv tool run --with tox-uv tox r -e docs
       - name: Push release commit and tag
         run: |
           git remote set-url origin 
"https://x-access-token:${GH_RELEASE_TOKEN}@github.com/${{ github.repository 
}}.git"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/build-1.4.3/.github/workflows/reusable-change-detection.yml 
new/build-1.5.0/.github/workflows/reusable-change-detection.yml
--- old/build-1.4.3/.github/workflows/reusable-change-detection.yml     
2026-04-10 23:24:52.000000000 +0200
+++ new/build-1.5.0/.github/workflows/reusable-change-detection.yml     
2026-04-30 05:17:22.000000000 +0200
@@ -29,7 +29,7 @@
           filter: |
             src/**
             tests/**
-            tox.ini
+            tox.toml
             pyproject.toml
             .github/workflows/test.yml
             .github/workflows/reusable-type.yml
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/build-1.4.3/.github/workflows/reusable-pytest.yml 
new/build-1.5.0/.github/workflows/reusable-pytest.yml
--- old/build-1.4.3/.github/workflows/reusable-pytest.yml       2026-04-10 
23:24:52.000000000 +0200
+++ new/build-1.5.0/.github/workflows/reusable-pytest.yml       2026-04-30 
05:17:22.000000000 +0200
@@ -15,15 +15,14 @@
           - macos
           - windows
         py:
-          - "pypy3.9-v7.3.14"
           - "pypy3.10-v7.3.19"
           - "pypy3.11-v7.3.19"
+          - "3.15"
           - "3.14"
           - "3.13"
           - "3.12"
           - "3.11"
           - "3.10"
-          - "3.9"
         tox-target:
           - "tox"
           - "min"
@@ -45,7 +44,7 @@
           persist-credentials: false
 
       - name: Setup uv
-        uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # 
v8.0.0
+        uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # 
v8.1.0
 
       - name: Install tox (uv)
         run: uv tool install tox --with tox-uv
@@ -56,33 +55,22 @@
           python-version: ${{ matrix.py }}
           allow-prereleases: true
 
-      - name: Pick environment to run
-        run: |
-          import platform
-          import os
-          import sys
-
-          if platform.python_implementation() == "PyPy":
-              base = f"pypy{sys.version_info.major}{sys.version_info.minor}"
-          else:
-              base = f"py{sys.version_info.major}{sys.version_info.minor}"
-          env = f"BASE={base}\n"
-          print(f"Picked:\n{env}for {sys.version}")
-          with open(os.environ["GITHUB_ENV"], "a", encoding="utf-8") as file:
-              file.write(env)
-        shell: python
-
       - name: Run test suite via tox
         if: matrix.tox-target == 'tox'
         shell: bash
         run: |
+          PYTHON_VERSION=${{ matrix.py }}
+          BASE=${PYTHON_VERSION%-*}
           tox -vv --notest -e $BASE
           tox -e $BASE --skip-pkg-install
 
       - name: Run minimum version test
         if: matrix.tox-target == 'min'
         shell: bash
-        run: tox -e $BASE-${{ matrix.tox-target }}
+        run: |
+          PYTHON_VERSION=${{ matrix.py }}
+          BASE=${PYTHON_VERSION%-*}
+          tox -e ${{ matrix.tox-target }}-$BASE
 
       - name: Run path test
         if: matrix.tox-target == 'tox' && matrix.py == '3.10'
@@ -100,4 +88,4 @@
           files: .tox/coverage.xml
           flags: tests
           env_vars: PYTHON
-          name: ${{ matrix.py }} - ${{ matrix.os }}
+          name: ${{ matrix.py }} - ${{ matrix.os }} - ${{ matrix.tox-target }}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/build-1.4.3/.github/workflows/reusable-type.yml 
new/build-1.5.0/.github/workflows/reusable-type.yml
--- old/build-1.4.3/.github/workflows/reusable-type.yml 2026-04-10 
23:24:52.000000000 +0200
+++ new/build-1.5.0/.github/workflows/reusable-type.yml 2026-04-30 
05:17:22.000000000 +0200
@@ -13,10 +13,10 @@
         with:
           persist-credentials: false
 
-      - name: Setup Python 3.9
+      - name: Setup Python 3.10
         uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # 
v6
         with:
-          python-version: 3.9
+          python-version: "3.10"
 
       - name: Install tox
         run: python -m pip install tox
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/build-1.4.3/.pre-commit-config.yaml 
new/build-1.5.0/.pre-commit-config.yaml
--- old/build-1.4.3/.pre-commit-config.yaml     2026-04-10 23:24:52.000000000 
+0200
+++ new/build-1.5.0/.pre-commit-config.yaml     2026-04-30 05:17:22.000000000 
+0200
@@ -26,7 +26,7 @@
       - id: blacken-docs
         additional_dependencies: [black==25.*]
   - repo: https://github.com/rbubley/mirrors-prettier
-    rev: "v3.8.1"
+    rev: "v3.8.3"
     hooks:
       - id: prettier
   - repo: https://github.com/LilSpazJoekp/docstrfmt
@@ -37,7 +37,7 @@
         additional_dependencies: ["sphinx>=9.1"]
         exclude: ^docs/index\.rst$ # 
https://github.com/LilSpazJoekp/docstrfmt/issues/176
   - repo: https://github.com/astral-sh/ruff-pre-commit
-    rev: v0.15.9
+    rev: v0.15.12
     hooks:
       - id: ruff-check
         args: [--fix, --show-fixes]
@@ -53,12 +53,8 @@
       - id: rst-backticks
       - id: rst-directive-colons
       - id: rst-inline-touching-normal
-  - repo: https://github.com/tox-dev/tox-ini-fmt
-    rev: "1.7.1"
-    hooks:
-      - id: tox-ini-fmt
   - repo: https://github.com/zizmorcore/zizmor-pre-commit
-    rev: v1.23.1
+    rev: v1.24.1
     hooks:
       - id: zizmor
   - repo: local
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/build-1.4.3/CHANGELOG.rst 
new/build-1.5.0/CHANGELOG.rst
--- old/build-1.4.3/CHANGELOG.rst       2026-04-10 23:24:52.000000000 +0200
+++ new/build-1.5.0/CHANGELOG.rst       2026-04-30 05:17:22.000000000 +0200
@@ -1,19 +1,62 @@
-********************
+####################
+ 1.5.0 (2026-04-30)
+####################
+
+**********
+ Features
+**********
+
+- Drop Python 3.9 support - by :user:`henryiii` (:issue:`1036`)
+
+**********
+ Bugfixes
+**********
+
+- Make ``--ignore-installed`` opt-in from the API via ``fresh=True`` - by 
:user:`henryiii` (:issue:`1056`)
+
+***************
+ Miscellaneous
+***************
+
+- :issue:`1033`
+
+####################
+ 1.4.4 (2026-04-22)
+####################
+
+**********
+ Bugfixes
+**********
+
+- Fix release pipeline generating ``CHANGELOG.rst`` entries with inconsistent 
heading levels, which broke ``sphinx -W``
+  and pinned Read the Docs ``stable`` at 1.4.0 - by :user:`gaborbernat`. 
(:issue:`1031`)
+- Revert :pr:`1039` from build 1.4.3, no longer check direct_url (for now) - 
by :user:`henryiii` (:issue:`1039`)
+- Add ``--ignore-installed`` to pip install command to prevent issues with 
packages already present in the isolated
+  build environment - by :user:`henryiii` (:issue:`1037`) (:issue:`1040`)
+- Partial revert of :pr:`973`, keeping log messages in one entry, multiple 
lines. (:issue:`1044`)
+
+***************
+ Miscellaneous
+***************
+
+- :issue:`1048`, :issue:`1049`
+
+####################
  1.4.3 (2026-04-10)
-********************
+####################
 
-==========
+**********
  Features
-==========
+**********
 
 - Add ``kind`` parameter to log messages to separate semantic and 
representation - by :user:`abitrolly` (:issue:`973`)
 
-==========
+**********
  Bugfixes
-==========
+**********
 
-- Strip ``PYTHONPATH`` from the environment during isolated builds to prevent 
host packages from leaking into the build -
-  by :user:`gaborbernat` (:issue:`405`)
+- Strip ``PYTHONPATH`` from the environment during isolated builds to prevent 
host packages from leaking into the build
+  - by :user:`gaborbernat` (:issue:`405`)
 - Pass ``--no-input`` to pip to prevent hidden credential prompts that cause 
hangs, and automatically set
   ``PIP_KEYRING_PROVIDER=subprocess`` (or ``UV_KEYRING_PROVIDER=subprocess`` 
for the uv installer) when the ``keyring``
   CLI is on ``PATH`` -- by :user:`gaborbernat` (:issue:`409`)
@@ -25,9 +68,9 @@
 - Resolve thread-safety races in the build API - by :user:`gaborbernat` 
(:issue:`1015`)
 - Validate ``backend-path`` entries exist on disk with a clear error - by 
:user:`gaborbernat` (:issue:`1016`)
 
-===============
+***************
  Miscellaneous
-===============
+***************
 
 - :issue:`1020`, :issue:`1021`
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/build-1.4.3/docs/conf.py new/build-1.5.0/docs/conf.py
--- old/build-1.4.3/docs/conf.py        2026-04-10 23:24:52.000000000 +0200
+++ new/build-1.5.0/docs/conf.py        2026-04-30 05:17:22.000000000 +0200
@@ -16,7 +16,7 @@
 
 
 if hasattr(__builtins__, 'EncodingWarning'):
-    warnings.filterwarnings('ignore', category=EncodingWarning, 
module='sphinx_copybutton')  # noqa: F821
+    warnings.filterwarnings('ignore', category=EncodingWarning, 
module='sphinx_copybutton')
 
 
 # -- Project information -----------------------------------------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/build-1.4.3/docs/development/contributing.rst 
new/build-1.5.0/docs/development/contributing.rst
--- old/build-1.4.3/docs/development/contributing.rst   2026-04-10 
23:24:52.000000000 +0200
+++ new/build-1.5.0/docs/development/contributing.rst   2026-04-30 
05:17:22.000000000 +0200
@@ -41,24 +41,42 @@
  Running Tests
 ***************
 
-Due to its nature, build has a somewhat complex test suite with two sets of 
tests: unit tests and integration tests.
+Due to its nature, ``build`` has a somewhat complex test suite with two sets 
of tests: unit tests and integration tests.
 Unit tests verify the actual code implementation, while integration tests run 
build on real world projects as a sanity
-check. Integration tests take a long time to run and are not very helpful for 
tracking down issues, so they are disabled
-by default. They can be enabled by passing either ``--run-integration`` or 
``--only-integration`` arguments to pytest,
-where the latter will disable unit tests and only run integration tests. Even 
though these tests are disabled by
-default, they will be run in CI where test suite run durations are not a big 
issue.
-
-To run the test suite, use tox which automates running tests on different 
environments. Simply run ``tox`` in the
-project directory to execute the full test suite. The project has a fairly 
large environment matrix, running tests for
-all supported Python versions and implementations, and with the module being 
invoked directly from path, sdist install,
-or wheel install. Additionally, there are environments for type checking and 
documentation building, plus extras like
-checking code with minimum versions of dependencies.
+check. To run tests we use ``tox``.
 
 Some example commands for this project include running type checking with 
``tox -e type``, running only unit tests
-against Python 3.9 with ``tox -e py39``, running both unit and integration 
tests with ``tox -- --run-integration``,
-running only integration tests with ``tox -- --only-integration``, or running 
only integration tests with parallel tasks
-using ``tox -- -n auto --only-integration``. You can also run unit tests 
against a specific Python version with wheel
-installation using ``tox -e py39-wheel``.
+against Python 3.14 with ``tox run -e 3.14``, running both unit and 
integration tests with ``tox run --
+--run-integration``, running only integration tests with ``tox run -- 
--only-integration``, or running only integration
+tests with parallel tasks using ``tox run -- -n auto --only-integration``.
+
+Tests run in parallel by default, but if you pass any arguments, you need to 
include ``-n auto`` if you want to keep
+parallel runs.
+
+Integration tests take a long time to run, so they are disabled by default. 
Passing either ``--run-integration`` or
+``--only-integration`` arguments through ``tox`` to ``pytest`` will run them, 
where the latter will disable unit tests
+and only run integration tests. CI still runs both test suites.
+
+.. code-block:: console
+
+    tox -- -n auto --only-integration
+
+The project has a fairly large environment matrix, running tests for all 
supported Python versions and implementations,
+and with the module being invoked directly from path, sdist install, or wheel 
install. To run tests only for Python
+3.14:
+
+.. code-block:: console
+
+    tox -e 3.14
+
+and with the module being invoked directly from path, sdist install, or wheel 
install.
+
+Additionally, there are environments for type checking and documentation 
building, plus extras like checking code with
+minimum versions of dependencies. For type checking,
+
+.. code-block:: console
+
+    tox -e type
 
 Code coverage is tracked to ensure all code paths are tested. Aim for complete 
coverage of any new code you add. The CI
 system will report coverage metrics on your pull request and runs the test 
suite across all supported operating systems.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/build-1.4.3/docs/development/release.rst 
new/build-1.5.0/docs/development/release.rst
--- old/build-1.4.3/docs/development/release.rst        2026-04-10 
23:24:52.000000000 +0200
+++ new/build-1.5.0/docs/development/release.rst        2026-04-30 
05:17:22.000000000 +0200
@@ -105,4 +105,4 @@
 
 The automation consists of the pre-release workflow at 
``.github/workflows/pre-release.yml`` for manual triggering, the
 CD workflow at ``.github/workflows/cd.yml`` that triggers on tag pushes, the 
release script at ``tasks/release.py`` for
-version bumping and tag creation, and the ``[testenv:release]`` environment in 
``tox.ini`` providing dependencies.
+version bumping and tag creation, and the ``[env.release]`` environment in 
``tox.toml`` providing dependencies.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/build-1.4.3/docs/how-to/choosing-tools.rst 
new/build-1.5.0/docs/how-to/choosing-tools.rst
--- old/build-1.4.3/docs/how-to/choosing-tools.rst      2026-04-10 
23:24:52.000000000 +0200
+++ new/build-1.5.0/docs/how-to/choosing-tools.rst      2026-04-30 
05:17:22.000000000 +0200
@@ -83,7 +83,7 @@
 
 Use `tox <https://tox.wiki/>`_ when you need to:
 
-- Test your package across multiple Python versions (e.g., 3.9, 3.10, 3.11)
+- Test your package across multiple Python versions (e.g., 3.10, 3.11, 3.12, 
3.13, 3.14)
 - Run tests in `isolated environments 
<https://packaging.python.org/en/latest/glossary/#term-Virtual-Environment>`_
 - Automate testing workflows
 - Run linters (code checkers), formatters, type checkers
@@ -137,7 +137,7 @@
     import nox
 
 
-    @nox.session(python=["3.8", "3.9", "3.10", "3.11", "3.12"])
+    @nox.session(python=["3.10", "3.11", "3.12", "3.13", "3.14"])
     def tests(session):
         session.install("pytest", "pytest-cov")
         session.run("pytest", "tests")
@@ -232,7 +232,7 @@
         runs-on: ubuntu-latest
         strategy:
           matrix:
-            python: ["3.8", "3.9", "3.10", "3.11", "3.12"]
+            python: ["3.10", "3.11", "3.12", "3.13", "3.14"]
         steps:
           - uses: actions/checkout@v4
           - uses: actions/setup-python@v5
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/build-1.4.3/docs/how-to/ci-cd.rst 
new/build-1.5.0/docs/how-to/ci-cd.rst
--- old/build-1.4.3/docs/how-to/ci-cd.rst       2026-04-10 23:24:52.000000000 
+0200
+++ new/build-1.5.0/docs/how-to/ci-cd.rst       2026-04-30 05:17:22.000000000 
+0200
@@ -140,7 +140,7 @@
         runs-on: ubuntu-latest
         strategy:
           matrix:
-            python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
+            python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
 
         steps:
           - uses: actions/checkout@v4
@@ -292,17 +292,13 @@
         paths:
           - dist/
 
-    build:py38:
+    build:py310:
       extends: .build_template
-      image: python:3.8
+      image: python:3.10
 
-    build:py39:
+    build:py314:
       extends: .build_template
-      image: python:3.9
-
-    build:py312:
-      extends: .build_template
-      image: python:3.12
+      image: python:3.14
 
 **********
  CircleCI
@@ -346,11 +342,11 @@
 
     language: python
     python:
-      - "3.8"
-      - "3.9"
       - "3.10"
       - "3.11"
       - "3.12"
+      - "3.13"
+      - "3.14"
 
     install:
       - pip install build
@@ -375,10 +371,10 @@
 
     strategy:
       matrix:
-        Python38:
-          python.version: '3.8'
-        Python312:
-          python.version: '3.12'
+        Python310:
+          python.version: '3.10'
+        Python314:
+          python.version: '3.14'
 
     steps:
     - task: UsePythonVersion@0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/build-1.4.3/docs/how-to/install.rst 
new/build-1.5.0/docs/how-to/install.rst
--- old/build-1.4.3/docs/how-to/install.rst     2026-04-10 23:24:52.000000000 
+0200
+++ new/build-1.5.0/docs/how-to/install.rst     2026-04-30 05:17:22.000000000 
+0200
@@ -87,13 +87,11 @@
 
 ``build`` is verified to be compatible with the following Python versions:
 
-- 3.9
 - 3.10
 - 3.11
 - 3.12
 - 3.13
 - 3.14
-- PyPy 3.9
 - PyPy 3.10
 - PyPy 3.11
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/build-1.4.3/docs/index.rst 
new/build-1.5.0/docs/index.rst
--- old/build-1.4.3/docs/index.rst      2026-04-10 23:24:52.000000000 +0200
+++ new/build-1.5.0/docs/index.rst      2026-04-30 05:17:22.000000000 +0200
@@ -95,14 +95,14 @@
 
    development/contributing
    development/release
+   Source Code <https://github.com/pypa/build/>
+   Issue Tracker <https://github.com/pypa/build/issues>
 
 .. toctree::
-   :caption: Project
+   :caption: Changelog
    :hidden:
 
    changelog
-   Source Code <https://github.com/pypa/build/>
-   Issue Tracker <https://github.com/pypa/build/issues>
 
 .. _pip: https://github.com/pypa/pip
 .. _PyPI: https://pypi.org/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/build-1.4.3/docs/tutorial/getting-started.rst 
new/build-1.5.0/docs/tutorial/getting-started.rst
--- old/build-1.4.3/docs/tutorial/getting-started.rst   2026-04-10 
23:24:52.000000000 +0200
+++ new/build-1.5.0/docs/tutorial/getting-started.rst   2026-04-30 
05:17:22.000000000 +0200
@@ -14,7 +14,7 @@
  Prerequisites
 ***************
 
-You need Python 3.9 or later installed on your system. Check your Python 
version:
+You need Python 3.10 or later installed on your system. Check your Python 
version:
 
 .. code-block:: console
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/build-1.4.3/pyproject.toml 
new/build-1.5.0/pyproject.toml
--- old/build-1.4.3/pyproject.toml      2026-04-10 23:24:52.000000000 +0200
+++ new/build-1.5.0/pyproject.toml      2026-04-30 05:17:22.000000000 +0200
@@ -6,7 +6,7 @@
 name = "build"
 description = "A simple, correct Python build frontend"
 readme = "README.md"
-requires-python = ">= 3.9"
+requires-python = ">= 3.10"
 license = "MIT"
 authors = [
   { name = "Filipe Laíns", email = "[email protected]" },
@@ -17,7 +17,7 @@
 classifiers = [
   "Programming Language :: Python :: 3",
   "Programming Language :: Python :: 3 :: Only",
-  "Programming Language :: Python :: 3.9",
+
   "Programming Language :: Python :: 3.10",
   "Programming Language :: Python :: 3.11",
   "Programming Language :: Python :: 3.12",
@@ -49,7 +49,6 @@
   "keyring",
 ]
 virtualenv = [
-  "virtualenv >= 20.11; python_version < '3.10'",
   "virtualenv >= 20.17; python_version >= '3.10' and python_version < '3.14'",
   "virtualenv >= 20.31; python_version >= '3.14'",
 ]
@@ -65,6 +64,17 @@
   "uv >= 0.1.18",
   "virtualenv >= 20.0.35",
 ]
+lint = [
+  "prek",
+]
+coverage = [
+  "covdefaults >= 2.3",
+  "coverage[toml] >= 5.1",
+  "diff_cover >= 3",
+]
+bump = [
+  "bump-my-version >= 0.10",
+]
 docs = [
   "furo >= 2025.12.19",
   "pre-commit >= 3.0",
@@ -87,11 +97,11 @@
   "pytest-rerunfailures >= 9.1",
   "pytest-xdist >= 1.34",
   "wheel >= 0.36.0",
-  'setuptools >= 42.0.0; python_version < "3.10"',
   'setuptools >= 56.0.0; python_version == "3.10"',
   'setuptools >= 56.0.0; python_version == "3.11"',
   'setuptools >= 67.8.0; python_version >= "3.12"',
   "setuptools_scm >= 6",
+  "pip >= 22.3",
   { include-group = "extra" },
 ]
 typing = [
@@ -120,14 +130,19 @@
 ]
 
 [tool.flit.sdist]
-include = ["tests/", ".gitignore", "CHANGELOG.rst", "docs/", ".dockerignore", 
"tox.ini"]
+include = ["tests/", ".gitignore", "CHANGELOG.rst", "docs/", ".dockerignore", 
"tox.toml"]
 exclude = ["**/__pycache__", "docs/_build", "**/*.egg-info", 
"tests/packages/*/build", "docs/changelog/template.jinja2"]
 
+[tool.uv]
+# Our docs dependencies do not support 3.9, so remove it from the uv solve
+environments = ["python_version >= '3.10'"]
+
 
 [tool.coverage]
 run.plugins = ["covdefaults"]
 run.source = ["build", "tests"]
-run.omit = ["tests/conftest.py", "tests/test_integration.py"]
+run.omit = ["tests/conftest.py", "tests/test_integration.py",]
+report.omit = ["src/build/_types.py"]
 run.disable_warnings = [
   "module-not-measured",  # Triggers in multithreaded context on build
   "no-sysmon",
@@ -164,12 +179,13 @@
   "ignore:check_home argument is deprecated and ignored:DeprecationWarning:",  
# PyPy 3.11
   "default:Python 3.14 will, by default, filter extracted tar 
archives:DeprecationWarning",
   "default:unclosed:ResourceWarning", # Python 3.11 Windows
+  "ignore:os.path.commonprefix:DeprecationWarning" # 
https://github.com/pypa/pyproject-hooks/pull/222
 ]
 
 [tool.mypy]
 files = ["src", "tests"]
 exclude = ["tests/packages"]
-python_version = "3.9"
+python_version = "3.10"
 strict = true
 enable_error_code = ["ignore-without-code", "truthy-bool", "redundant-expr"]
 warn_unreachable = true
@@ -214,6 +230,7 @@
 
 [tool.ruff.lint.flake8-tidy-imports.banned-api]
 "typing.TYPE_CHECKING".msg = "Use TYPE_CHECKING=False instead"
+"os.path.commonprefix".msg = "Use os.path.commonpath or manually implement 
string manip"
 
 [tool.ruff.lint.per-file-ignores]
 "tasks/**.py" = ["T20", "INP", "S607"]
@@ -244,8 +261,7 @@
 title_format = false
 issue_format = ":issue:`{issue}`"
 template = "docs/changelog/template.jinja2"
-underlines = ["*", "=", "-"]
-top_underline = "#"
+underlines = ["#", "*", "=", "-"]
 
 [[tool.towncrier.section]]
 path = ""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/build-1.4.3/src/build/__init__.py 
new/build-1.5.0/src/build/__init__.py
--- old/build-1.4.3/src/build/__init__.py       2026-04-10 23:24:52.000000000 
+0200
+++ new/build-1.5.0/src/build/__init__.py       2026-04-30 05:17:22.000000000 
+0200
@@ -26,7 +26,7 @@
 from ._util import check_dependency
 
 
-__version__ = '1.4.3'
+__version__ = '1.5.0'
 
 __all__ = [
     'BuildBackendException',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/build-1.4.3/src/build/__main__.py 
new/build-1.5.0/src/build/__main__.py
--- old/build-1.4.3/src/build/__main__.py       2026-04-10 23:24:52.000000000 
+0200
+++ new/build-1.5.0/src/build/__main__.py       2026-04-30 05:17:22.000000000 
+0200
@@ -105,15 +105,20 @@
 
     def log(message: str, *, kind: tuple[str, ...] | None = None) -> None:
         if _ctx.verbosity >= -1:
-            if kind is None:
-                print(fill(message, initial_indent='  '), file=sys.stderr)  # 
noqa: T201
-            elif kind[0] == 'step':
-                _cprint('{bold}{}{reset}', fill(message, initial_indent='* '), 
file=sys.stderr)
-
-            elif kind[0] == 'subprocess':
-                initial_indent = '> ' if kind[1] == 'cmd' else '< '
-                for line in message.splitlines():
-                    _cprint('{dim}{}{reset}', fill(line, 
initial_indent=initial_indent), file=sys.stderr)
+            match kind:
+                case ('step', *_):
+                    (first, *rest) = message.splitlines()
+                    _cprint('{bold}{}{reset}', fill(first, initial_indent='* 
'), file=sys.stderr)
+                    for line in rest:
+                        print(fill(line, initial_indent='  '), 
file=sys.stderr)  # noqa: T201
+                case ('subprocess', 'cmd'):
+                    for line in message.splitlines():
+                        _cprint('{dim}{}{reset}', fill(line, initial_indent='> 
'), file=sys.stderr)
+                case ('subprocess', 'stdout' | 'stderr'):
+                    for line in message.splitlines():
+                        _cprint('{dim}{}{reset}', fill(line, initial_indent='< 
'), file=sys.stderr)
+                case _:
+                    print(fill(message, initial_indent='  '), file=sys.stderr) 
 # noqa: T201
 
     return log
 
@@ -174,7 +179,7 @@
                     install = partial(install, constraints=set(map(str.strip, 
dependency_constraints_file)))
 
             # first install the build dependencies
-            install(builder.build_system_requires)
+            install(builder.build_system_requires, _fresh=True)
             # then get the extra required dependencies from the backend (which 
was installed in the call above :P)
             install(builder.get_requires_for_build(distribution, 
config_settings))
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/build-1.4.3/src/build/_builder.py 
new/build-1.5.0/src/build/_builder.py
--- old/build-1.4.3/src/build/_builder.py       2026-04-10 23:24:52.000000000 
+0200
+++ new/build-1.5.0/src/build/_builder.py       2026-04-30 05:17:22.000000000 
+0200
@@ -114,21 +114,24 @@
         msg = '`requires` must be an array of strings'
         raise BuildSystemTableValidationError(msg)
 
-    if 'build-backend' not in build_system_table:
-        _find_typo(build_system_table, 'build-backend')
-        # If ``build-backend`` is missing, inject the legacy setuptools backend
-        # but leave ``requires`` intact to emulate pip
-        build_system_table['build-backend'] = _DEFAULT_BACKEND['build-backend']
-    elif not isinstance(build_system_table['build-backend'], str):
-        msg = '`build-backend` must be a string'
-        raise BuildSystemTableValidationError(msg)
+    match build_system_table:
+        case {'build-backend': str()}:
+            pass
+        case {'build-backend': _}:
+            msg = '`build-backend` must be a string'
+            raise BuildSystemTableValidationError(msg)
+        case _:
+            _find_typo(build_system_table, 'build-backend')
+            # If ``build-backend`` is missing, inject the legacy setuptools 
backend
+            # but leave ``requires`` intact to emulate pip
+            build_system_table['build-backend'] = 
_DEFAULT_BACKEND['build-backend']
 
-    if 'backend-path' in build_system_table and (
-        not isinstance(build_system_table['backend-path'], list)
-        or not all(isinstance(i, str) for i in 
build_system_table['backend-path'])
-    ):
-        msg = '`backend-path` must be an array of strings'
-        raise BuildSystemTableValidationError(msg)
+    match build_system_table:
+        case {'backend-path': list() as backend_path} if all(isinstance(i, 
str) for i in backend_path):
+            pass
+        case {'backend-path': _}:
+            msg = '`backend-path` must be an array of strings'
+            raise BuildSystemTableValidationError(msg)
 
     unknown_props = build_system_table.keys() - {'requires', 'build-backend', 
'backend-path'}
     if unknown_props:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/build-1.4.3/src/build/_types.py 
new/build-1.5.0/src/build/_types.py
--- old/build-1.4.3/src/build/_types.py 2026-04-10 23:24:52.000000000 +0200
+++ new/build-1.5.0/src/build/_types.py 2026-04-30 05:17:22.000000000 +0200
@@ -1,21 +1,22 @@
 from __future__ import annotations
 
+import collections.abc
 import os
 import typing
 
 
 __all__ = ['ConfigSettings', 'Distribution', 'StrPath', 'SubprocessRunner']
 
-ConfigSettings = typing.Mapping[str, typing.Union[str, typing.Sequence[str]]]
+ConfigSettings = collections.abc.Mapping[str, str | 
collections.abc.Sequence[str]]
 Distribution = typing.Literal['sdist', 'wheel', 'editable']
 
-StrPath = typing.Union[str, os.PathLike[str]]
+StrPath = str | os.PathLike[str]
 
 TYPE_CHECKING = False
 
 if TYPE_CHECKING:
     from pyproject_hooks import SubprocessRunner
 else:
-    SubprocessRunner = typing.Callable[
-        [typing.Sequence[str], typing.Optional[str], 
typing.Optional[typing.Mapping[str, str]]], None
+    SubprocessRunner = collections.abc.Callable[
+        [collections.abc.Sequence[str], str | None, 
collections.abc.Mapping[str, str] | None], None
     ]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/build-1.4.3/src/build/_util.py 
new/build-1.5.0/src/build/_util.py
--- old/build-1.4.3/src/build/_util.py  2026-04-10 23:24:52.000000000 +0200
+++ new/build-1.5.0/src/build/_util.py  2026-04-30 05:17:22.000000000 +0200
@@ -9,8 +9,6 @@
     from collections.abc import Iterator
     from collections.abc import Set as AbstractSet
 
-    from ._compat.importlib import metadata
-
 
 _WHEEL_FILENAME_REGEX = re.compile(
     r'(?P<distribution>.+)-(?P<version>.+)'
@@ -19,22 +17,6 @@
 )
 
 
-def _url_matches_direct_url(req_url: str, dist: metadata.Distribution) -> bool:
-    """Check if the installed distribution's origin (PEP 610) matches the 
requirement URL."""
-    import json
-
-    if not (raw := dist.read_text('direct_url.json')):
-        return False
-    direct_url: dict[str, object] = json.loads(raw)
-    url = direct_url.get('url', '')
-    if isinstance(vcs_info := direct_url.get('vcs_info'), dict):
-        origin = f'{vcs_info.get("vcs", "")}+{url}'
-        if requested_revision := vcs_info.get('requested_revision'):
-            origin += f'@{requested_revision}'
-        return bool(req_url == origin)
-    return bool(req_url == url)
-
-
 def check_dependency(
     req_string: str, ancestral_req_strings: tuple[str, ...] = (), 
parent_extras: AbstractSet[str] = frozenset()
 ) -> Iterator[tuple[str, ...]]:
@@ -73,10 +55,7 @@
         # dependency is not installed in the environment.
         yield (*ancestral_req_strings, normalised_req_string)
     else:
-        if req.url and not _url_matches_direct_url(req.url, dist):
-            # the installed distribution's origin does not match the URL 
requirement (PEP 610).
-            yield (*ancestral_req_strings, normalised_req_string)
-        elif req.specifier and not req.specifier.contains(dist.version, 
prereleases=True):
+        if req.specifier and not req.specifier.contains(dist.version, 
prereleases=True):
             # the installed version is incompatible.
             yield (*ancestral_req_strings, normalised_req_string)
         elif dist.requires:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/build-1.4.3/src/build/env.py 
new/build-1.5.0/src/build/env.py
--- old/build-1.4.3/src/build/env.py    2026-04-10 23:24:52.000000000 +0200
+++ new/build-1.5.0/src/build/env.py    2026-04-30 05:17:22.000000000 +0200
@@ -161,7 +161,13 @@
             'PYTHONPATH': '',
         }
 
-    def install(self, requirements: Collection[str], constraints: 
Collection[str] = []) -> None:
+    def install(
+        self,
+        requirements: Collection[str],
+        constraints: Collection[str] = [],
+        *,
+        _fresh: bool = False,  # Used internally by CLI to support preset 
PYTHONPATH
+    ) -> None:
         """
         Install packages from PEP 508 requirements in the isolated build 
environment.
 
@@ -173,10 +179,11 @@
         if not requirements:
             return
 
-        _ctx.log('Installing packages in isolated environment:', 
kind=('step',))
-        for r in sorted(requirements):
-            _ctx.log(f'- {r}')
-        self._env_backend.install_dependencies(requirements, constraints)
+        _ctx.log(
+            'Installing packages in isolated environment:\n' + '\n'.join(f'- 
{r}' for r in sorted(requirements)),
+            kind=('step',),
+        )
+        self._env_backend.install_dependencies(requirements, constraints, 
_fresh=_fresh)
 
 
 class _EnvBackend(typing.Protocol):  # pragma: no cover
@@ -185,7 +192,13 @@
 
     def create(self, path: str) -> None: ...
 
-    def install_dependencies(self, requirements: Collection[str], constraints: 
Collection[str]) -> None: ...
+    def install_dependencies(
+        self,
+        requirements: Collection[str],
+        constraints: Collection[str],
+        *,
+        _fresh: bool = False,
+    ) -> None: ...
 
     @property
     def display_name(self) -> str: ...
@@ -323,7 +336,13 @@
                         env=_pip_env(),
                     )
 
-    def install_dependencies(self, requirements: Collection[str], constraints: 
Collection[str]) -> None:
+    def install_dependencies(
+        self,
+        requirements: Collection[str],
+        constraints: Collection[str],
+        *,
+        _fresh: bool = False,
+    ) -> None:
         with contextlib.ExitStack() as exit_stack:
             if self._has_valid_outer_pip:
                 cmd = [sys.executable, '-m', 'pip', '--python', 
self.python_executable]
@@ -333,7 +352,10 @@
             if (verbosity := _ctx.verbosity) > 1:
                 cmd += [f'-{"v" * (verbosity - 1)}']
 
-            cmd += ['install', '--use-pep517', '--no-warn-script-location', 
'--no-compile', '--no-input']
+            cmd += ['install']
+            if _fresh:
+                cmd += ['--ignore-installed']
+            cmd += ['--use-pep517', '--no-warn-script-location', 
'--no-compile', '--no-input']
 
             # pip does not honour environment markers in command line arguments
             # but it does from requirement files.
@@ -384,7 +406,11 @@
         self.python_executable, self.scripts_dir, _ = 
_find_executable_and_scripts(self._env_path)
 
     def install_dependencies(  # pragma: no cover -- uv tests are skipped on 
PyPy, covered on CPython
-        self, requirements: Collection[str], constraints: Collection[str]
+        self,
+        requirements: Collection[str],
+        constraints: Collection[str],
+        *,
+        _fresh: bool = False,
     ) -> None:
         with contextlib.ExitStack() as exit_stack:
             cmd = [self._uv_bin, 'pip']
@@ -392,8 +418,7 @@
             if (verbosity := _ctx.verbosity) > 1:
                 cmd += [f'-{"v" * min(2, verbosity - 1)}']
 
-            cmd += ['install', *requirements]
-            cmd += ['--python', self.python_executable]
+            cmd += ['install', *requirements, '--python', 
self.python_executable]
 
             if constraints:
                 with tempfile.NamedTemporaryFile(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/build-1.4.3/src/build/util.py 
new/build-1.5.0/src/build/util.py
--- old/build-1.4.3/src/build/util.py   2026-04-10 23:24:52.000000000 +0200
+++ new/build-1.5.0/src/build/util.py   2026-04-30 05:17:22.000000000 +0200
@@ -54,7 +54,7 @@
                 source_dir,
                 runner=runner,
             )
-            env.install(builder.build_system_requires)
+            env.install(builder.build_system_requires, _fresh=True)
             env.install(builder.get_requires_for_build('wheel'))
             return _project_wheel_metadata(builder)
     else:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/build-1.4.3/tasks/release.py 
new/build-1.5.0/tasks/release.py
--- old/build-1.4.3/tasks/release.py    2026-04-10 23:24:52.000000000 +0200
+++ new/build-1.5.0/tasks/release.py    2026-04-30 05:17:22.000000000 +0200
@@ -39,12 +39,13 @@
     latest_tag = repo.git.describe('--tags', '--abbrev=0')
     latest_tag = latest_tag.lstrip('v')
     parts = [int(x) for x in latest_tag.split('.')]
-    if version_str == 'major':
-        parts = [parts[0] + 1, 0, 0]
-    elif version_str == 'minor':
-        parts = [parts[0], parts[1] + 1, 0]
-    elif version_str in {'patch', 'auto'}:
-        parts[2] += 1
+    match version_str:
+        case 'major':
+            parts = [parts[0] + 1, 0, 0]
+        case 'minor':
+            parts = [parts[0], parts[1] + 1, 0]
+        case 'patch' | 'auto':
+            parts[2] += 1
     return Version('.'.join(str(p) for p in parts))
 
 
@@ -66,6 +67,7 @@
     print('build changelog from fragments with towncrier')
     check_call(['towncrier', 'build', '--yes', '--version', version.public], 
cwd=str(ROOT_SRC_DIR))  # noqa: S603
     call(['pre-commit', 'run', '--all-files'], cwd=str(ROOT_SRC_DIR))
+    call(['pre-commit', 'run', '--all-files'], cwd=str(ROOT_SRC_DIR))
     repo.git.add('src/build/__init__.py', 'CHANGELOG.rst', 'docs/changelog/*')
     check_call(['pre-commit', 'run', '--all-files', '--show-diff-on-failure'], 
cwd=str(ROOT_SRC_DIR))
     if repo.is_dirty(index=False, working_tree=True, untracked_files=False):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/build-1.4.3/tests/conftest.py 
new/build-1.5.0/tests/conftest.py
--- old/build-1.4.3/tests/conftest.py   2026-04-10 23:24:52.000000000 +0200
+++ new/build-1.5.0/tests/conftest.py   2026-04-30 05:17:22.000000000 +0200
@@ -14,10 +14,10 @@
 import tempfile
 import typing
 
-from collections.abc import Generator
+from collections.abc import Callable, Generator
 from functools import partial, update_wrapper
 from pathlib import Path
-from typing import Any, Callable
+from typing import Any
 
 import pytest
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/build-1.4.3/tests/constraints.txt 
new/build-1.5.0/tests/constraints.txt
--- old/build-1.4.3/tests/constraints.txt       2026-04-10 23:24:52.000000000 
+0200
+++ new/build-1.5.0/tests/constraints.txt       2026-04-30 05:17:22.000000000 
+0200
@@ -1,13 +1,14 @@
 importlib-metadata==4.6
 packaging==24.0
+pip==22.3; python_version < "3.12"
+pip==23.2; python_version >= "3.12" and python_version < "3.15"
+pip==25.3; python_version >= "3.15"
 pyproject_hooks==1.0
-setuptools==42.0.0; python_version < "3.10"
 setuptools==56.0.0; python_version == "3.10"
 setuptools==56.0.0; python_version == "3.11"
 setuptools==67.8.0; python_version >= "3.12"
 setuptools_scm==6.3.1; python_version < "3.12"
 tomli==1.1.0
-virtualenv==20.11; python_version < "3.10"
-virtualenv==20.17; python_version >= "3.10" and python_version < "3.14"
+virtualenv==20.17; python_version < "3.14"
 virtualenv==20.31; python_version >= "3.14"
 wheel==0.36.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/build-1.4.3/tests/packages/test-metadata/pyproject.toml 
new/build-1.5.0/tests/packages/test-metadata/pyproject.toml
--- old/build-1.4.3/tests/packages/test-metadata/pyproject.toml 2026-04-10 
23:24:52.000000000 +0200
+++ new/build-1.5.0/tests/packages/test-metadata/pyproject.toml 2026-04-30 
05:17:22.000000000 +0200
@@ -11,4 +11,3 @@
 [tool.black]
 line-length = 127
 skip-string-normalization = true
-target-version = ['py39', 'py38', 'py37', 'py36']
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/build-1.4.3/tests/test_env.py 
new/build-1.5.0/tests/test_env.py
--- old/build-1.4.3/tests/test_env.py   2026-04-10 23:24:52.000000000 +0200
+++ new/build-1.5.0/tests/test_env.py   2026-04-30 05:17:22.000000000 +0200
@@ -3,6 +3,8 @@
 
 import importlib.util
 import logging
+import os
+import pathlib
 import shutil
 import subprocess
 import sys
@@ -48,11 +50,21 @@
 
 
 @pytest.mark.isolated
-def test_isolation() -> None:
+def test_isolation(monkeypatch: pytest.MonkeyPatch) -> None:
     subprocess.check_call([sys.executable, '-c', 'import build.env'])
+    # Test that demonstrates the PYTHONPATH leak issue (issue #1047)
+    # When PYTHONPATH is set to include build, and the subprocess env
+    # is not properly isolated, the import will succeed instead of failing.
+    # Only fails on 3.15+ (due to lazy loading)
+    monkeypatch.setenv('PYTHONPATH', 
os.path.dirname(os.path.dirname(os.path.abspath(build.__file__))))
     debug = 'import sys; import os; print(os.linesep.join(sys.path));'
-    with build.env.DefaultIsolatedEnv() as env, 
pytest.raises(subprocess.CalledProcessError):
-        subprocess.check_call([env.python_executable, '-c', f'{debug} import 
build.env'])
+    with build.env.DefaultIsolatedEnv() as env:
+        isolated_env = {**os.environ, **env.make_extra_environ()}
+        with pytest.raises(subprocess.CalledProcessError):
+            subprocess.check_call(
+                [env.python_executable, '-c', f'{debug} import build.env'],
+                env=isolated_env,
+            )
 
 
 @pytest.mark.skipif(IS_PYPY, reason='PyPy3 uses get path to create and 
provision venv')
@@ -129,8 +141,7 @@
 
     assert [(record.levelname, record.message) for record in caplog.records] 
== [
         ('INFO', 'Creating isolated environment: venv+pip...'),
-        ('INFO', 'Installing packages in isolated environment:'),
-        ('INFO', '- something'),
+        ('INFO', 'Installing packages in isolated environment:\n- something'),
     ]
 
 
@@ -215,18 +226,20 @@
 
 @pytest.mark.parametrize('verbosity', range(3))
 @pytest.mark.parametrize('constraints', [[], ['foo']])
[email protected]('fresh', [False, True])
 @pytest.mark.usefixtures('local_pip')
 def test_default_impl_install_cmd_well_formed(
     mocker: pytest_mock.MockerFixture,
     verbosity: int,
     constraints: list[str],
+    fresh: bool,
 ) -> None:
     mocker.patch.object(build.env._ctx, 'verbosity', verbosity)  # type: 
ignore[attr-defined]
 
     with build.env.DefaultIsolatedEnv() as env:
         run_subprocess = mocker.patch('build.env.run_subprocess')
 
-        env.install(['some', 'requirements'], constraints)
+        env.install(['some', 'requirements'], constraints, _fresh=fresh)
 
         run_subprocess.assert_called_once_with(
             [
@@ -235,6 +248,7 @@
                 'pip',
                 *([f'-{"v" * (verbosity - 1)}'] if verbosity > 1 else []),
                 'install',
+                *(['--ignore-installed'] if fresh else []),
                 '--use-pep517',
                 '--no-warn-script-location',
                 '--no-compile',
@@ -249,19 +263,21 @@
 
 @pytest.mark.parametrize('verbosity', range(3))
 @pytest.mark.parametrize('constraints', [[], ['foo']])
[email protected]('fresh', [False, True])
 @pytest.mark.skipif(IS_PYPY, reason='uv cannot find PyPy executable')
 @pytest.mark.skipif(MISSING_UV, reason='uv executable not found')
 def test_uv_impl_install_cmd_well_formed(  # pragma: no cover -- uv tests are 
skipped on PyPy, covered on CPython
     mocker: pytest_mock.MockerFixture,
     verbosity: int,
     constraints: list[str],
+    fresh: bool,
 ) -> None:
     mocker.patch.object(build.env._ctx, 'verbosity', verbosity)  # type: 
ignore[attr-defined]
 
     with build.env.DefaultIsolatedEnv(installer='uv') as env:
         run_subprocess = mocker.patch('build.env.run_subprocess')
 
-        env.install(['some', 'requirements'], constraints)
+        env.install(['some', 'requirements'], constraints, _fresh=fresh)
 
         run_subprocess.assert_called_once_with(
             [
@@ -342,12 +358,17 @@
     caplog: pytest.LogCaptureFixture,
     mocker: pytest_mock.MockerFixture,
 ) -> None:
+    # Ensure INFO logs are captured
+    caplog.set_level(logging.INFO)
     mocker.patch.dict(sys.modules, {'uv': None})
 
     with build.env.DefaultIsolatedEnv(installer='uv'):
         pass
 
-    assert any(r.message == f'Using external uv from {shutil.which("uv")}' for 
r in caplog.records)
+    # Only check that we logged using an external uv binary (do not rely on
+    # which() at assertion time because it can find the environment one).
+    # And .text is used instead of .records so a failure message is helpful.
+    assert 'Using external uv' in caplog.text
 
 
 def test_external_uv_detection_failure(
@@ -573,3 +594,19 @@
 
     (install_call,) = run_subprocess.call_args_list
     assert install_call.kwargs['env']['UV_KEYRING_PROVIDER'] == 'disabled'
+
+
[email protected]
+def test_pythonpath_does_not_interfere_with_outer_pip(
+    monkeypatch: pytest.MonkeyPatch,
+    tmp_path: pathlib.Path,
+) -> None:
+    flit_core = tmp_path.joinpath('flit_core-0.0.0.dist-info/')
+    flit_core.mkdir()
+
+    monkeypatch.setenv('PYTHONPATH', str(tmp_path))
+
+    with build.env.DefaultIsolatedEnv(installer='pip') as env:
+        env.install({'flit_core'}, _fresh=True)
+
+        assert subprocess.check_call([env.python_executable, '-c', 'import 
flit_core']) == 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/build-1.4.3/tests/test_main.py 
new/build-1.5.0/tests/test_main.py
--- old/build-1.4.3/tests/test_main.py  2026-04-10 23:24:52.000000000 +0200
+++ new/build-1.5.0/tests/test_main.py  2026-04-30 05:17:22.000000000 +0200
@@ -310,7 +310,7 @@
 
     build.__main__.build_package(package_test_flit, '.', ['sdist'])
 
-    install.assert_any_call({'flit_core >=2,<4'})
+    install.assert_any_call({'flit_core >=2,<4'}, _fresh=True)
 
     required_cmd.assert_called_with('sdist', None)
     install.assert_any_call(['dep1', 'dep2'])
@@ -513,7 +513,7 @@
     with pytest.raises(build.BuildBackendException, match=re.escape("Backend 
'flit_core.buildapi' is not available.")):
         build.__main__.build_package(package_test_flit, tmp_path, ['wheel'], 
dependency_constraints_txt=constraints_txt_path)
 
-    install.assert_called_with({'flit_core >=2,<4'}, 
constraints={'flit-core==12.34', 'foo==wot'})
+    install.assert_any_call({'flit_core >=2,<4'}, 
constraints={'flit-core==12.34', 'foo==wot'}, _fresh=True)
 
 
 @pytest.mark.pypy3323bug
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/build-1.4.3/tests/test_projectbuilder.py 
new/build-1.5.0/tests/test_projectbuilder.py
--- old/build-1.4.3/tests/test_projectbuilder.py        2026-04-10 
23:24:52.000000000 +0200
+++ new/build-1.5.0/tests/test_projectbuilder.py        2026-04-30 
05:17:22.000000000 +0200
@@ -43,11 +43,17 @@
             return self._metadata
         return ''
 
-    _registry: typing.ClassVar[dict[str, type[MockDistribution]]] = {}
-
     @classmethod
     def from_name(cls, name: str) -> MockDistribution:
-        if (dist_cls := cls._registry.get(name)) is not None:
+        registry: dict[str, type[MockDistribution]] = {
+            'extras_dep': ExtraMockDistribution,
+            'requireless_dep': RequirelessMockDistribution,
+            'recursive_dep': RecursiveMockDistribution,
+            'prerelease_dep': PrereleaseMockDistribution,
+            'circular_dep': CircularMockDistribution,
+            'nested_circular_dep': NestedCircularMockDistribution,
+        }
+        if (dist_cls := registry.get(name)) is not None:
             return dist_cls()
         raise _importlib.metadata.PackageNotFoundError
 
@@ -104,18 +110,6 @@
         Requires-Dist: circular_dep""")
 
 
-MockDistribution._registry.update(
-    {
-        'extras_dep': ExtraMockDistribution,
-        'requireless_dep': RequirelessMockDistribution,
-        'recursive_dep': RecursiveMockDistribution,
-        'prerelease_dep': PrereleaseMockDistribution,
-        'circular_dep': CircularMockDistribution,
-        'nested_circular_dep': NestedCircularMockDistribution,
-    }
-)
-
-
 @pytest.mark.parametrize(
     ('requirement_string', 'expected'),
     [
@@ -154,95 +148,6 @@
     assert next(build.check_dependency(requirement_string), None) == expected
 
 
-class _DirectUrlMixin(MockDistribution):
-    _direct_url_json: str = ''
-
-    def read_text(self, filename: str) -> str:
-        if filename == 'direct_url.json':
-            return self._direct_url_json
-        return super().read_text(filename)
-
-
-class DirectUrlMockDistribution(_DirectUrlMixin):
-    _metadata = textwrap.dedent("""\
-        Metadata-Version: 2.2
-        Name: direct_url_dep
-        Version: 1.0.0""")
-    _direct_url_json = '{"url": 
"https://example.com/direct_url_dep-1.0.0.tar.gz";, "archive_info": {}}'
-
-
-class VcsDirectUrlMockDistribution(_DirectUrlMixin):
-    _metadata = textwrap.dedent("""\
-        Metadata-Version: 2.2
-        Name: vcs_dep
-        Version: 1.0.0""")
-    _direct_url_json = (
-        '{"url": "https://github.com/example/vcs_dep.git";,'
-        ' "vcs_info": {"vcs": "git", "requested_revision": "v1.0.0",'
-        ' "commit_id": "abc123"}}'
-    )
-
-
-class VcsNoRevisionMockDistribution(_DirectUrlMixin):
-    _metadata = textwrap.dedent("""\
-        Metadata-Version: 2.2
-        Name: vcs_dep
-        Version: 1.0.0""")
-    _direct_url_json = '{"url": "https://github.com/example/vcs_dep.git";, 
"vcs_info": {"vcs": "git", "commit_id": "abc123"}}'
-
-
-MockDistribution._registry.update(
-    {
-        'direct_url_dep': DirectUrlMockDistribution,
-        'vcs_dep': VcsDirectUrlMockDistribution,
-    }
-)
-
-
[email protected](
-    'requirement_string',
-    [
-        'extras_dep @ https://example.com/extras_dep-1.0.0.tar.gz',
-        'missing_dep @ https://example.com/missing_dep-1.0.0.tar.gz',
-    ],
-)
-def test_check_dependency_url_no_direct_url_is_unmet(monkeypatch: 
pytest.MonkeyPatch, requirement_string: str) -> None:
-    monkeypatch.setattr(_importlib.metadata, 'Distribution', MockDistribution)
-    assert next(build.check_dependency(requirement_string), None) is not None
-
-
-def test_check_dependency_url_matching_direct_url_is_met(monkeypatch: 
pytest.MonkeyPatch) -> None:
-    monkeypatch.setattr(_importlib.metadata, 'Distribution', MockDistribution)
-    assert next(build.check_dependency('direct_url_dep @ 
https://example.com/direct_url_dep-1.0.0.tar.gz'), None) is None
-
-
-def test_check_dependency_url_mismatched_direct_url_is_unmet(monkeypatch: 
pytest.MonkeyPatch) -> None:
-    monkeypatch.setattr(_importlib.metadata, 'Distribution', MockDistribution)
-    assert next(build.check_dependency('direct_url_dep @ 
https://example.com/other-1.0.0.tar.gz'), None) is not None
-
-
-def test_check_dependency_vcs_url_matching_direct_url_is_met(monkeypatch: 
pytest.MonkeyPatch) -> None:
-    monkeypatch.setattr(_importlib.metadata, 'Distribution', MockDistribution)
-    assert next(build.check_dependency('vcs_dep @ 
git+https://github.com/example/[email protected]'), None) is None
-
-
-def test_check_dependency_vcs_url_mismatched_direct_url_is_unmet(monkeypatch: 
pytest.MonkeyPatch) -> None:
-    monkeypatch.setattr(_importlib.metadata, 'Distribution', MockDistribution)
-    assert next(build.check_dependency('vcs_dep @ 
git+https://github.com/example/[email protected]'), None) is not None
-
-
-def test_check_dependency_vcs_url_no_revision_is_met(monkeypatch: 
pytest.MonkeyPatch) -> None:
-    monkeypatch.setattr(_importlib.metadata, 'Distribution', MockDistribution)
-    monkeypatch.setitem(MockDistribution._registry, 'vcs_dep', 
VcsNoRevisionMockDistribution)
-    assert next(build.check_dependency('vcs_dep @ 
git+https://github.com/example/vcs_dep.git'), None) is None
-
-
-def test_check_dependency_vcs_url_no_revision_mismatch_is_unmet(monkeypatch: 
pytest.MonkeyPatch) -> None:
-    monkeypatch.setattr(_importlib.metadata, 'Distribution', MockDistribution)
-    monkeypatch.setitem(MockDistribution._registry, 'vcs_dep', 
VcsNoRevisionMockDistribution)
-    assert next(build.check_dependency('vcs_dep @ 
git+https://github.com/other/repo.git'), None) is not None
-
-
 def test_bad_project(package_test_no_project: str) -> None:
     # Passing a nonexistent project directory
     with pytest.raises(build.BuildException):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/build-1.4.3/tests/test_self_packaging.py 
new/build-1.5.0/tests/test_self_packaging.py
--- old/build-1.4.3/tests/test_self_packaging.py        2026-04-10 
23:24:52.000000000 +0200
+++ new/build-1.5.0/tests/test_self_packaging.py        2026-04-30 
05:17:22.000000000 +0200
@@ -30,7 +30,7 @@
     
'tests/packages/test-cant-build-via-sdist/some-file-that-is-needed-for-build.txt',
     'tests/packages/test-no-project/empty.txt',
     'tests/packages/test-setuptools/MANIFEST.in',
-    'tox.ini',
+    'tox.toml',
 }
 
 sdist_patterns = {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/build-1.4.3/tests/test_util.py 
new/build-1.5.0/tests/test_util.py
--- old/build-1.4.3/tests/test_util.py  2026-04-10 23:24:52.000000000 +0200
+++ new/build-1.5.0/tests/test_util.py  2026-04-30 05:17:22.000000000 +0200
@@ -4,8 +4,10 @@
 
 import importlib.util
 import re
+import unittest.mock
 
 import pytest
+import pytest_mock
 
 import build.util
 
@@ -50,3 +52,25 @@
     assert str(metadata['version']) == '1.0.0'
     assert metadata['summary'] == 'hello!'
     assert isinstance(metadata.json, dict)
+
+
+def test_project_wheel_metadata_installs_build_requires_fresh(mocker: 
pytest_mock.MockerFixture) -> None:
+    env = mocker.MagicMock()
+    env_cm = mocker.MagicMock()
+    env_cm.__enter__.return_value = env
+    env_cm.__exit__.return_value = False
+    mocker.patch('build.util.DefaultIsolatedEnv', return_value=env_cm)
+
+    builder = mocker.MagicMock()
+    builder.build_system_requires = {'dep1'}
+    builder.get_requires_for_build.return_value = {'dep2'}
+    mocker.patch('build.util.ProjectBuilder.from_isolated_env', 
return_value=builder)
+    metadata = unittest.mock.sentinel.metadata
+    mocker.patch('build.util._project_wheel_metadata', return_value=metadata)
+
+    assert build.util.project_wheel_metadata('/tmp/project') is metadata
+
+    assert env.install.call_args_list == [
+        mocker.call({'dep1'}, _fresh=True),
+        mocker.call({'dep2'}),
+    ]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/build-1.4.3/tox.ini new/build-1.5.0/tox.ini
--- old/build-1.4.3/tox.ini     2026-04-10 23:24:52.000000000 +0200
+++ new/build-1.5.0/tox.ini     1970-01-01 01:00:00.000000000 +0100
@@ -1,134 +0,0 @@
-[tox]
-requires =
-    tox>=4.22
-    tox-uv
-    virtualenv>=20.0.34
-env_list =
-    fix
-    type
-    docs
-    path
-    {py314, py313, py312, py311, py310, py39, pypy311, pypy310, pypy39}{, -min}
-skip_missing_interpreters = true
-
-[testenv]
-description =
-    run test suite with {basepython}
-deps =
-    pip
-pass_env =
-    LC_ALL
-    PIP_*
-    PYTEST_*
-    TERM
-set_env =
-    COVERAGE_CORE = sysmon
-    COVERAGE_FILE = {toxworkdir}/.coverage.{envname}
-    PYPY3323BUG = 1
-    PYTHONWARNDEFAULTENCODING = 1
-    TEST_STATUS_DIR = {envtmpdir}
-commands =
-    pytest -ra --cov --cov-config pyproject.toml \
-      --cov-report=html:{envdir}/htmlcov --cov-context=test \
-      --cov-report=xml:{toxworkdir}/coverage.{envname}.xml {posargs:-n auto}
-dependency_groups =
-    test
-
-[testenv:fix]
-description = run static analysis and style checks
-base_python = python3.10
-skip_install = true
-deps =
-    prek
-pass_env =
-    HOMEPATH
-    PROGRAMDATA
-commands =
-    prek run --all-files --show-diff-on-failure
-    python -c 'print("hint: run {envdir}/bin/prek install to add checks as 
pre-commit hook")'
-
-[testenv:type]
-description = run type check on code base
-set_env =
-    PYTHONWARNDEFAULTENCODING =
-commands =
-    mypy {posargs}
-dependency_groups =
-    mypy
-
-[testenv:docs]
-description = build documentations
-base_python = python3.14
-set_env =
-    PYTHONUTF8 = 1
-commands =
-    pre-commit run docstrfmt --all-files
-    proselint check docs
-    sphinx-build -W -n -b html docs {env:READTHEDOCS_OUTPUT:{envtmpdir}}/html
-    python -c 'import os; print("Documentation available under file://" + 
os.environ.get("READTHEDOCS_OUTPUT", "{envtmpdir}") + "/html/index.html")'
-dependency_groups =
-    docs
-
-[testenv:path]
-description = verify build can run from source (bootstrap)
-set_env =
-    COVERAGE_FILE = {toxworkdir}/.coverage.{envname}
-    PYTHONPATH = {toxinidir}/src
-commands_pre =
-    python -E -m pip uninstall -y build colorama
-
-[testenv:{py314, py313, py312, py311, py310, py39, pypy39, pypy310, 
pypy311}-min]
-description = check minimum versions required of all dependencies
-set_env =
-    PIP_CONSTRAINT = {toxinidir}/tests/constraints.txt
-    UV_CONSTRAINT = {toxinidir}/tests/constraints.txt
-
-[testenv:dev]
-description = generate a DEV environment
-package = editable
-deps =
-    virtualenv>=20.0.34
-commands =
-    python -m pip list --format=columns
-    python -c 'import sys; print(sys.executable)'
-dependency_groups =
-    docs
-    test
-
-[testenv:coverage]
-description = combine coverage from test environments
-skip_install = true
-deps =
-    coverage[toml]>=5.1
-    diff_cover>=3
-parallel_show_output = true
-pass_env =
-    DIFF_AGAINST
-set_env =
-commands =
-    - coverage combine {toxworkdir}
-    coverage report --skip-covered --show-missing -i
-    coverage xml -o {toxworkdir}/coverage.xml -i
-    coverage html -d {toxworkdir}/htmlcov -i
-    python -m diff_cover.diff_cover_tool --compare-branch 
{env:DIFF_AGAINST:origin/main} {toxworkdir}/coverage.xml
-depends =
-    path
-    {py314, py313, py312, py311, py310, py39, pypy311, pypy310, pypy39}{, -min}
-
-[testenv:bump]
-description = bump versions, pass major/minor/patch
-skip_install = true
-deps =
-    bump-my-version>=0.10
-set_env =
-commands =
-    bump-my-version bump {posargs}
-
-[testenv:release]
-description = create a release (commit, tag, and push)
-skip_install = true
-change_dir = {toxinidir}/tasks
-commands =
-    python release.py {posargs}
-dependency_groups =
-    release
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/build-1.4.3/tox.toml new/build-1.5.0/tox.toml
--- old/build-1.4.3/tox.toml    1970-01-01 01:00:00.000000000 +0100
+++ new/build-1.5.0/tox.toml    2026-04-30 05:17:22.000000000 +0200
@@ -0,0 +1,119 @@
+requires = ["tox-uv>=1.28"]
+env_list = [
+    "fix",
+    "type",
+    "docs",
+    "path",
+    { product = [{ prefix = "3.", start = 10, stop = 15 }]},
+    { product = [{ prefix = "pypy3.", start = 10, stop = 11 }]},
+    { product = [{ prefix = "min-3.", start = 10, stop = 15 }]},
+    { product = [{ prefix = "min-pypy3.", start = 10, stop = 11 }]},
+]
+skip_missing_interpreters = true
+
+[env_run_base]
+description = "run test suite with {basepython}"
+uv_seed = true
+pass_env = ["LC_ALL", "PIP_*", "PYTEST_*", "TERM"]
+commands = [
+    [
+        "pytest", "-ra", "--cov", "--cov-config", "pyproject.toml",
+        "--cov-report=html:{envdir}/htmlcov", "--cov-context=test",
+        "--cov-report=xml:{toxworkdir}/coverage.{envname}.xml",
+        "--cov-report", "term-missing",
+        { replace = "posargs", default = ["-n", "auto"], extend = true },
+    ],
+]
+dependency_groups = ["test"]
+
+[env_run_base.set_env]
+COVERAGE_CORE = "sysmon"
+COVERAGE_FILE = "{toxworkdir}/.coverage.{envname}"
+PYPY3323BUG = "1"
+PYTHONWARNDEFAULTENCODING = "1"
+TEST_STATUS_DIR = "{envtmpdir}"
+
+[env_base.min]
+factors = [["3.10", "3.11", "3.12", "3.13", "3.14", "3.15", "pypy3.10", 
"pypy3.11"]]
+description = "check minimum versions required of all dependencies"
+set_env = { PIP_CONSTRAINT = "{toxinidir}/tests/constraints.txt", 
UV_CONSTRAINT = "{toxinidir}/tests/constraints.txt" }
+
+[env.fix]
+description = "run static analysis and style checks"
+skip_install = true
+pass_env = ["HOMEPATH", "PROGRAMDATA"]
+commands = [
+    ["prek", "run", "--all-files", "--show-diff-on-failure"],
+    ["python", "-c", 'print("hint: run {envdir}/bin/prek install to add checks 
as pre-commit hook")'],
+]
+dependency_groups = ["lint"]
+
+[env.type]
+description = "run type check on code base"
+set_env = { PYTHONWARNDEFAULTENCODING = "" }
+commands = [["mypy", { replace = "posargs", extend = true }]]
+dependency_groups = ["mypy"]
+
+[env.docs]
+description = "build documentations"
+base_python = "3.14"
+set_env = { PYTHONUTF8 = "1" }
+commands = [
+    ["proselint", "check", "docs"],
+    ["sphinx-build", "-W", "-n", "-b", "html", "docs", 
"{env:READTHEDOCS_OUTPUT:{envtmpdir}}/html"],
+    ["python", "-c", 'import os; print("Documentation available under file://" 
+ os.environ.get("READTHEDOCS_OUTPUT", "{envtmpdir}") + "/html/index.html")'],
+]
+dependency_groups = ["docs"]
+
+[env.path]
+description = "verify build can run from source (bootstrap)"
+set_env = { COVERAGE_FILE = "{toxworkdir}/.coverage.{envname}", PYTHONPATH = 
"{toxinidir}/src" }
+commands_pre = [
+    ["python", "-E", "-m", "pip", "uninstall", "-y", "build", "colorama"],
+]
+
+[env.dev]
+description = "generate a DEV environment"
+package = "editable"
+deps = ["virtualenv>=20.0.34"]
+commands = [
+    ["python", "-m", "pip", "list", "--format=columns"],
+    ["python", "-c", "import sys; print(sys.executable)"],
+]
+dependency_groups = ["docs", "test"]
+
+[env.coverage]
+description = "combine coverage from test environments"
+skip_install = true
+parallel_show_output = true
+dependency_groups = ["coverage"]
+pass_env = ["DIFF_AGAINST"]
+set_env = {}
+commands = [
+    ["-", "coverage", "combine", "{toxworkdir}"],
+    ["coverage", "report", "--skip-covered", "--show-missing", "-i"],
+    ["coverage", "xml", "-o", "{toxworkdir}/coverage.xml", "-i"],
+    ["coverage", "html", "-d", "{toxworkdir}/htmlcov", "-i"],
+    ["python", "-m", "diff_cover.diff_cover_tool", "--compare-branch", 
"{env:DIFF_AGAINST:origin/main}", "{toxworkdir}/coverage.xml"],
+]
+depends = [
+    "path",
+    { product = [{ prefix = "3.", start = 10, stop = 15 }]},
+    { product = [{ prefix = "pypy3.", start = 10, stop = 11 }]},
+    { product = [{ prefix = "min-3.", start = 10, stop = 15 }]},
+    { product = [{ prefix = "min-pypy3.", start = 10, stop = 11 }]},
+]
+
+[env.bump]
+description = "bump versions, pass major/minor/patch"
+skip_install = true
+set_env = {}
+commands = [["bump-my-version", "bump", { replace = "posargs", extend = true 
}]]
+dependency_groups = ["bump"]
+
+[env.release]
+description = "create a release (commit, tag, and push)"
+skip_install = true
+change_dir = "{toxinidir}/tasks"
+commands = [["python", "release.py", { replace = "posargs", extend = true }]]
+dependency_groups = ["release"]

Reply via email to