From 8290c3face8bf5d6580f07bb9892bcbb9af90b37 Mon Sep 17 00:00:00 2001 From: konstin Date: Mon, 25 Aug 2025 18:20:46 +0200 Subject: [PATCH 01/74] Update uv_build version automatically In https://github.com/pypa/packaging.python.org/pull/1880, the concern was raised that the uv_build upper bound in the docs will go stale. This PR adds a GitHub Actions workflow that automatically updates the version daily with the latest uv(-build) version. I tested this change on my fork, but I unfortunately can't test this in pypa/packaging.python.org itself. --- .github/workflows/cron.yml | 26 ++++++++++++++ scripts/update_uv_build_version.py | 56 ++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 scripts/update_uv_build_version.py diff --git a/.github/workflows/cron.yml b/.github/workflows/cron.yml index 8870bb70b..6074c3fbb 100644 --- a/.github/workflows/cron.yml +++ b/.github/workflows/cron.yml @@ -5,10 +5,36 @@ name: Cron on: schedule: - cron: "0 6 * * *" # daily at 6am + workflow_dispatch: jobs: test: if: github.repository_owner == 'pypa' # suppress noise in forks uses: ./.github/workflows/test.yml + update-uv-build-version: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - uses: actions/checkout@v4 + - uses: astral-sh/setup-uv@v5 + - name: Update uv_build version + id: update_script + run: uv run scripts/update_uv_build_version.py + - # If there are no changes, no pull request will be created and the action exits silently. + name: Create Pull Request + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: Update uv_build version to ${{ steps.update_script.outputs.version }} + title: Update uv_build version to ${{ steps.update_script.outputs.version }} + body: | + Automated update of uv_build version bounds for uv ${{ steps.update_script.outputs.version }}. + + This PR was created automatically by the cron workflow, ping `@konstin` for problems. + branch: bot/update-uv-build-version + delete-branch: true + ... diff --git a/scripts/update_uv_build_version.py b/scripts/update_uv_build_version.py new file mode 100644 index 000000000..f71cb821a --- /dev/null +++ b/scripts/update_uv_build_version.py @@ -0,0 +1,56 @@ +# /// script +# requires-python = ">=3.12" +# dependencies = [ +# "httpx>=0.28.1,<0.29", +# "packaging>=25.0", +# ] +# /// +import re +from pathlib import Path + +import httpx +from packaging.utils import parse_wheel_filename +from packaging.version import Version + + +def main(): + response = httpx.get( + "https://pypi.org/simple/uv-build/", + headers={"Accept": "application/vnd.pypi.simple.v1+json"}, + ) + response.raise_for_status() + data = response.json() + current_release = None + for file in data["files"]: + if not file["filename"].endswith(".whl"): + continue + _name, version, _build, _tags = parse_wheel_filename(file["filename"]) + if version.is_prerelease: + continue + if current_release is None or version > current_release: + current_release = version + + [major, minor, _patch] = current_release.release + if major != 0: + raise NotImplementedError("The script needs to be updated for uv 1.x") + upper_bound = Version(f"{major}.{minor + 1}.{0}") + + repository_root = Path(__file__).parent.parent + existing = repository_root.joinpath("source/shared/build-backend-tabs.rst").read_text() + replacement = f'requires = ["uv_build >= {current_release}, <{upper_bound}"]' + searcher = re.compile(re.escape('requires = ["uv_build') + ".*" + re.escape('"]')) + if not searcher.search(existing): + raise RuntimeError("Could not `uv-build` entry") + updated = searcher.sub(replacement, existing) + + if existing != updated: + print("Updating source/shared/build-backend-tabs.rst") + Path("source/shared/build-backend-tabs.rst").write_text(updated) + print(f"::set-output name=version::{current_release}") + print(f"::set-output name=updated::true") + else: + print("Already up-to-date source/shared/build-backend-tabs.rst") + print(f"::set-output name=updated::false") + +if __name__ == '__main__': + main() From a23f1a2d451339755fed3e96bf70a7cb7972378e Mon Sep 17 00:00:00 2001 From: konsti Date: Tue, 26 Aug 2025 11:08:09 +0200 Subject: [PATCH 02/74] Update scripts/update_uv_build_version.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 🇺🇦 Sviatoslav Sydorenko (Святослав Сидоренко) --- scripts/update_uv_build_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/update_uv_build_version.py b/scripts/update_uv_build_version.py index f71cb821a..02eee3434 100644 --- a/scripts/update_uv_build_version.py +++ b/scripts/update_uv_build_version.py @@ -1,5 +1,5 @@ # /// script -# requires-python = ">=3.12" +# requires-python = ">= 3.12" # dependencies = [ # "httpx>=0.28.1,<0.29", # "packaging>=25.0", From 7500df28a55d361c11f971c842beaf30a97995f2 Mon Sep 17 00:00:00 2001 From: konstin Date: Tue, 26 Aug 2025 11:12:28 +0200 Subject: [PATCH 03/74] Review --- .github/workflows/cron.yml | 27 ------------- .github/workflows/update-uv-build-version.yml | 39 +++++++++++++++++++ scripts/update_uv_build_version.py | 18 ++++++--- 3 files changed, 52 insertions(+), 32 deletions(-) create mode 100644 .github/workflows/update-uv-build-version.yml diff --git a/.github/workflows/cron.yml b/.github/workflows/cron.yml index 6074c3fbb..18a63caba 100644 --- a/.github/workflows/cron.yml +++ b/.github/workflows/cron.yml @@ -11,30 +11,3 @@ jobs: test: if: github.repository_owner == 'pypa' # suppress noise in forks uses: ./.github/workflows/test.yml - - update-uv-build-version: - runs-on: ubuntu-latest - permissions: - contents: write - pull-requests: write - steps: - - uses: actions/checkout@v4 - - uses: astral-sh/setup-uv@v5 - - name: Update uv_build version - id: update_script - run: uv run scripts/update_uv_build_version.py - - # If there are no changes, no pull request will be created and the action exits silently. - name: Create Pull Request - uses: peter-evans/create-pull-request@v7 - with: - token: ${{ secrets.GITHUB_TOKEN }} - commit-message: Update uv_build version to ${{ steps.update_script.outputs.version }} - title: Update uv_build version to ${{ steps.update_script.outputs.version }} - body: | - Automated update of uv_build version bounds for uv ${{ steps.update_script.outputs.version }}. - - This PR was created automatically by the cron workflow, ping `@konstin` for problems. - branch: bot/update-uv-build-version - delete-branch: true - -... diff --git a/.github/workflows/update-uv-build-version.yml b/.github/workflows/update-uv-build-version.yml new file mode 100644 index 000000000..8586ecd11 --- /dev/null +++ b/.github/workflows/update-uv-build-version.yml @@ -0,0 +1,39 @@ +--- + +name: Cron + +on: + schedule: + - cron: "0 6 * * 1" # mondays at 6am + workflow_dispatch: + +jobs: + update-uv-build-version: + name: Update uv_build version + if: github.repository_owner == 'pypa' # suppress noise in forks + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - uses: actions/checkout@v4 + - name: Set up uv + uses: astral-sh/setup-uv@v5 + - name: Update uv_build version + id: update_script + run: uv run scripts/update_uv_build_version.py + - # If there are no changes, no pull request will be created and the action exits silently. + name: Create Pull Request + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: Update uv_build version to ${{ steps.update_script.outputs.version }} + title: Update uv_build version to ${{ steps.update_script.outputs.version }} + body: | + Automated update of uv_build version bounds for uv ${{ steps.update_script.outputs.version }}. + + This PR was created automatically by the cron workflow, ping `@konstin` for problems. + branch: bot/update-uv-build-version + delete-branch: true + +... diff --git a/scripts/update_uv_build_version.py b/scripts/update_uv_build_version.py index 02eee3434..8dfd90da8 100644 --- a/scripts/update_uv_build_version.py +++ b/scripts/update_uv_build_version.py @@ -5,6 +5,7 @@ # "packaging>=25.0", # ] # /// +import os import re from pathlib import Path @@ -36,7 +37,9 @@ def main(): upper_bound = Version(f"{major}.{minor + 1}.{0}") repository_root = Path(__file__).parent.parent - existing = repository_root.joinpath("source/shared/build-backend-tabs.rst").read_text() + existing = repository_root.joinpath( + "source/shared/build-backend-tabs.rst" + ).read_text() replacement = f'requires = ["uv_build >= {current_release}, <{upper_bound}"]' searcher = re.compile(re.escape('requires = ["uv_build') + ".*" + re.escape('"]')) if not searcher.search(existing): @@ -46,11 +49,16 @@ def main(): if existing != updated: print("Updating source/shared/build-backend-tabs.rst") Path("source/shared/build-backend-tabs.rst").write_text(updated) - print(f"::set-output name=version::{current_release}") - print(f"::set-output name=updated::true") + if github_output := os.environ.get("GITHUB_OUTPUT"): + with open(github_output, "a") as f: + f.write(f"version={current_release}\n") + f.write(f"updated=true\n") else: print("Already up-to-date source/shared/build-backend-tabs.rst") - print(f"::set-output name=updated::false") + if github_output := os.environ.get("GITHUB_OUTPUT"): + with open(github_output, "a") as f: + f.write(f"updated=false\n") -if __name__ == '__main__': + +if __name__ == "__main__": main() From 77d8c71c11a55da7c26b251b4c61cb5d0d957fd7 Mon Sep 17 00:00:00 2001 From: konstin Date: Tue, 26 Aug 2025 11:14:06 +0200 Subject: [PATCH 04/74] Use same `actions/checkout@v4` as zizmor job --- .github/workflows/update-uv-build-version.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/update-uv-build-version.yml b/.github/workflows/update-uv-build-version.yml index 8586ecd11..54f5ad211 100644 --- a/.github/workflows/update-uv-build-version.yml +++ b/.github/workflows/update-uv-build-version.yml @@ -16,7 +16,10 @@ jobs: contents: write pull-requests: write steps: - - uses: actions/checkout@v4 + - name: Checkout repository + uses: actions/checkout@v4 + with: + persist-credentials: false - name: Set up uv uses: astral-sh/setup-uv@v5 - name: Update uv_build version From 7df08f4ed3a9788801c99635de0ef276389c64cd Mon Sep 17 00:00:00 2001 From: konstin Date: Tue, 26 Aug 2025 11:17:32 +0200 Subject: [PATCH 05/74] Linters --- .github/workflows/update-uv-build-version.yml | 2 +- scripts/update_uv_build_version.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/update-uv-build-version.yml b/.github/workflows/update-uv-build-version.yml index 54f5ad211..184497047 100644 --- a/.github/workflows/update-uv-build-version.yml +++ b/.github/workflows/update-uv-build-version.yml @@ -34,7 +34,7 @@ jobs: title: Update uv_build version to ${{ steps.update_script.outputs.version }} body: | Automated update of uv_build version bounds for uv ${{ steps.update_script.outputs.version }}. - + This PR was created automatically by the cron workflow, ping `@konstin` for problems. branch: bot/update-uv-build-version delete-branch: true diff --git a/scripts/update_uv_build_version.py b/scripts/update_uv_build_version.py index 8dfd90da8..816ab9061 100644 --- a/scripts/update_uv_build_version.py +++ b/scripts/update_uv_build_version.py @@ -52,12 +52,12 @@ def main(): if github_output := os.environ.get("GITHUB_OUTPUT"): with open(github_output, "a") as f: f.write(f"version={current_release}\n") - f.write(f"updated=true\n") + f.write("updated=true\n") else: print("Already up-to-date source/shared/build-backend-tabs.rst") if github_output := os.environ.get("GITHUB_OUTPUT"): with open(github_output, "a") as f: - f.write(f"updated=false\n") + f.write("updated=false\n") if __name__ == "__main__": From 64977629a37b34ab04876706069a88846134cf26 Mon Sep 17 00:00:00 2001 From: konstin Date: Tue, 26 Aug 2025 11:18:25 +0200 Subject: [PATCH 06/74] Undo accidental cosmetic change --- .github/workflows/cron.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/cron.yml b/.github/workflows/cron.yml index 18a63caba..f1eddccb5 100644 --- a/.github/workflows/cron.yml +++ b/.github/workflows/cron.yml @@ -11,3 +11,5 @@ jobs: test: if: github.repository_owner == 'pypa' # suppress noise in forks uses: ./.github/workflows/test.yml + +... From d22b3b9fa10380eb7488986586fb2199719cf3b6 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Tue, 26 Aug 2025 15:07:30 -0700 Subject: [PATCH 07/74] Clarify that the ``License-Expression`` field applies to the containing distribution file, not the project itself --- source/specifications/core-metadata.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/specifications/core-metadata.rst b/source/specifications/core-metadata.rst index 550c6e55a..379805df5 100644 --- a/source/specifications/core-metadata.rst +++ b/source/specifications/core-metadata.rst @@ -473,6 +473,9 @@ Text string that is a valid SPDX :term:`license expression `, as specified in :doc:`/specifications/license-expression`. +Note that the expression in this field only applies to the **distribution** file +containing the metadata, not the project itself or other distribution files. + Examples:: License-Expression: MIT @@ -923,6 +926,9 @@ Example:: History ======= +- August 2025: Clarified that ``License-Expression`` applies to the containing + distribution file and not the project itself. + - August 2024: Core metadata 2.4 was approved through :pep:`639`. - Added the ``License-Expression`` field. From 083e98617f8053ffae61ba13b806d89e69ded647 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Wed, 27 Aug 2025 12:20:05 +0100 Subject: [PATCH 08/74] Clarify that the Dynamic metadata field only applies when building from sdist --- source/specifications/core-metadata.rst | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/source/specifications/core-metadata.rst b/source/specifications/core-metadata.rst index 550c6e55a..6f071233e 100644 --- a/source/specifications/core-metadata.rst +++ b/source/specifications/core-metadata.rst @@ -133,6 +133,18 @@ only, and indicates that the field value was calculated at wheel build time, and may not be the same as the value in the sdist or in other wheels for the project. +Note in particular that if you have a wheel, you cannot assume that a field +which is not marked as ``Dynamic`` will have the same value in other wheels, as +some wheels are not built directly from the sdist, but are modified from +existing wheels (the ``cibuildwheel`` tool does this, for example). Such +modifications *could* include changing metadata (even non-dynamic metadata). +Similarly, if you have a sdist and a wheel which you didn't build from that +sdist, you cannnot assume that the wheel's metadata matches that of the sdist, +even if the field is not marked as ``Dynamic``. + +It is advisable, but not required, that tools which modify wheel metadata add +the modified fields to the generated wheel's ``Dynamic`` field. + Full details of the semantics of ``Dynamic`` are described in :pep:`643`. .. _core-metadata-platform: @@ -923,6 +935,10 @@ Example:: History ======= +- August 2025: Clarified that ``Dynamic`` only affects how fields + must be treated when building a wheel from a sdist, not when modifying + a wheel. + - August 2024: Core metadata 2.4 was approved through :pep:`639`. - Added the ``License-Expression`` field. From 42d1cbbc5be1cd43e156ba04ffde970d17ed22a4 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Wed, 27 Aug 2025 12:25:39 +0100 Subject: [PATCH 09/74] Grr, keyboard is doubling up letters :-( --- source/specifications/core-metadata.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/specifications/core-metadata.rst b/source/specifications/core-metadata.rst index 6f071233e..106922580 100644 --- a/source/specifications/core-metadata.rst +++ b/source/specifications/core-metadata.rst @@ -139,7 +139,7 @@ some wheels are not built directly from the sdist, but are modified from existing wheels (the ``cibuildwheel`` tool does this, for example). Such modifications *could* include changing metadata (even non-dynamic metadata). Similarly, if you have a sdist and a wheel which you didn't build from that -sdist, you cannnot assume that the wheel's metadata matches that of the sdist, +sdist, you cannot assume that the wheel's metadata matches that of the sdist, even if the field is not marked as ``Dynamic``. It is advisable, but not required, that tools which modify wheel metadata add From 875b13fa27bdf28200a364220a249290654f4280 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Wed, 27 Aug 2025 14:37:34 +0100 Subject: [PATCH 10/74] Refer to auditwheel rather than cibuildwheel --- source/specifications/core-metadata.rst | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/source/specifications/core-metadata.rst b/source/specifications/core-metadata.rst index 106922580..b77243e10 100644 --- a/source/specifications/core-metadata.rst +++ b/source/specifications/core-metadata.rst @@ -136,11 +136,12 @@ project. Note in particular that if you have a wheel, you cannot assume that a field which is not marked as ``Dynamic`` will have the same value in other wheels, as some wheels are not built directly from the sdist, but are modified from -existing wheels (the ``cibuildwheel`` tool does this, for example). Such -modifications *could* include changing metadata (even non-dynamic metadata). -Similarly, if you have a sdist and a wheel which you didn't build from that -sdist, you cannot assume that the wheel's metadata matches that of the sdist, -even if the field is not marked as ``Dynamic``. +existing wheels (the ``auditwheel`` tool does this, for example, and it's +commonly used when building wheels for PyPI). Such modifications *could* +include changing metadata (even non-dynamic metadata). Similarly, if you have +a sdist and a wheel which you didn't build from that sdist, you cannot assume +that the wheel's metadata matches that of the sdist, even if the field is not +marked as ``Dynamic``. It is advisable, but not required, that tools which modify wheel metadata add the modified fields to the generated wheel's ``Dynamic`` field. From 6569d5cafecf2243368446e6f1e37d91c10797a7 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Wed, 27 Aug 2025 15:14:50 +0100 Subject: [PATCH 11/74] Clarify prebuilt wheels --- source/specifications/core-metadata.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/source/specifications/core-metadata.rst b/source/specifications/core-metadata.rst index b77243e10..571a13dde 100644 --- a/source/specifications/core-metadata.rst +++ b/source/specifications/core-metadata.rst @@ -133,15 +133,15 @@ only, and indicates that the field value was calculated at wheel build time, and may not be the same as the value in the sdist or in other wheels for the project. -Note in particular that if you have a wheel, you cannot assume that a field -which is not marked as ``Dynamic`` will have the same value in other wheels, as -some wheels are not built directly from the sdist, but are modified from -existing wheels (the ``auditwheel`` tool does this, for example, and it's -commonly used when building wheels for PyPI). Such modifications *could* -include changing metadata (even non-dynamic metadata). Similarly, if you have -a sdist and a wheel which you didn't build from that sdist, you cannot assume -that the wheel's metadata matches that of the sdist, even if the field is not -marked as ``Dynamic``. +Note in particular that if you have obtained a prebuilt wheel, you cannot +assume that a field which is not marked as ``Dynamic`` will have the same value +in other wheels, as some wheels are not built directly from the sdist, but are +modified from existing wheels (the ``auditwheel`` tool does this, for example, +and it's commonly used when building wheels for PyPI). Such modifications +*could* include changing metadata (even non-dynamic metadata). Similarly, if +you have a sdist and a wheel which you didn't build from that sdist, you cannot +assume that the wheel's metadata matches that of the sdist, even if the field +is not marked as ``Dynamic``. It is advisable, but not required, that tools which modify wheel metadata add the modified fields to the generated wheel's ``Dynamic`` field. From cd571af286305cf1e7114a57f13ccff729f706c5 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Wed, 27 Aug 2025 16:20:46 +0100 Subject: [PATCH 12/74] Remove advice for tools that modify wheels --- source/specifications/core-metadata.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/source/specifications/core-metadata.rst b/source/specifications/core-metadata.rst index 571a13dde..c020e1469 100644 --- a/source/specifications/core-metadata.rst +++ b/source/specifications/core-metadata.rst @@ -143,9 +143,6 @@ you have a sdist and a wheel which you didn't build from that sdist, you cannot assume that the wheel's metadata matches that of the sdist, even if the field is not marked as ``Dynamic``. -It is advisable, but not required, that tools which modify wheel metadata add -the modified fields to the generated wheel's ``Dynamic`` field. - Full details of the semantics of ``Dynamic`` are described in :pep:`643`. .. _core-metadata-platform: From 31d727712bb38af2513dc7f741e47f188ed96f98 Mon Sep 17 00:00:00 2001 From: konsti Date: Thu, 28 Aug 2025 16:51:57 +0200 Subject: [PATCH 13/74] Update .github/workflows/update-uv-build-version.yml Co-authored-by: Alyssa Coghlan --- .github/workflows/update-uv-build-version.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-uv-build-version.yml b/.github/workflows/update-uv-build-version.yml index 184497047..a3cead001 100644 --- a/.github/workflows/update-uv-build-version.yml +++ b/.github/workflows/update-uv-build-version.yml @@ -1,6 +1,6 @@ --- -name: Cron +name: Update uv build version on: schedule: From acdb79c4e738cc1f489288219632e6b694209ac2 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Wed, 10 Sep 2025 12:04:16 -0700 Subject: [PATCH 14/74] Try to clarify where `license-expression` applies --- source/specifications/core-metadata.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/specifications/core-metadata.rst b/source/specifications/core-metadata.rst index 379805df5..c79b4e0f7 100644 --- a/source/specifications/core-metadata.rst +++ b/source/specifications/core-metadata.rst @@ -473,8 +473,8 @@ Text string that is a valid SPDX :term:`license expression `, as specified in :doc:`/specifications/license-expression`. -Note that the expression in this field only applies to the **distribution** file -containing the metadata, not the project itself or other distribution files. +Note that the expression in this field only applies to the distribution file +containing the metadata, not the project overall or other distribution files. Examples:: From d73c061cbaa3f1178c8cc1e0bb5bfeaea3ee64ed Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Wed, 10 Sep 2025 13:06:14 -0700 Subject: [PATCH 15/74] Clarify throughout the docs that the `license` key in `pyproject.toml` is for the distribution --- source/glossary.rst | 2 +- .../licensing-examples-and-user-scenarios.rst | 28 +++++++++---------- source/guides/writing-pyproject-toml.rst | 15 +++++----- source/tutorials/packaging-projects.rst | 14 +++++----- 4 files changed, 30 insertions(+), 29 deletions(-) diff --git a/source/glossary.rst b/source/glossary.rst index 6a592125f..630513868 100644 --- a/source/glossary.rst +++ b/source/glossary.rst @@ -160,7 +160,7 @@ Glossary A string with valid SPDX license expression syntax, including one or more SPDX :term:`License Identifier`\(s), - which describes a :term:`Project`'s license(s) + which describes a :term:`Distribution Archive`'s license(s) and how they inter-relate. Examples: ``GPL-3.0-or-later``, diff --git a/source/guides/licensing-examples-and-user-scenarios.rst b/source/guides/licensing-examples-and-user-scenarios.rst index 2c25ddfb0..9f32b6117 100644 --- a/source/guides/licensing-examples-and-user-scenarios.rst +++ b/source/guides/licensing-examples-and-user-scenarios.rst @@ -6,8 +6,8 @@ Licensing examples and user scenarios ===================================== -:pep:`639` has specified the way to declare a project's license and paths to -license files and other legally required information. +:pep:`639` has specified the way to declare a :term:`Distribution Archive`'s +license and paths to license files and other legally required information. This document aims to provide clear guidance how to migrate from the legacy to the standardized way of declaring licenses. Make sure your preferred build backend supports :pep:`639` before @@ -53,7 +53,7 @@ Or, if the project used :file:`setup.cfg`, in its ``[metadata]`` table: [metadata] license = MIT -The output Core Metadata for the distribution packages would then be: +The output Core Metadata for the :term:`Distribution Package` would then be: .. code-block:: email @@ -63,8 +63,9 @@ The output Core Metadata for the distribution packages would then be: The :file:`LICENSE` file would be stored at :file:`/setuptools-{VERSION}/LICENSE` in the sdist and :file:`/setuptools-{VERSION}.dist-info/licenses/LICENSE` in the wheel, and unpacked from there into the site directory (e.g. -:file:`site-packages/`) on installation; :file:`/` is the root of the respective archive -and ``{VERSION}`` the version of the Setuptools release in the Core Metadata. +:file:`site-packages/`) on installation; :file:`/` is the root of the respective +archive and ``{VERSION}`` the version of the Setuptools release in the Core +Metadata. .. _licensing-example-advanced: @@ -83,7 +84,7 @@ directories; specifically: ordered-set==3.1.1 more_itertools==8.8.0 -The license expressions for these projects are: +The appropriate license expressions are: .. code-block:: text @@ -287,7 +288,7 @@ and make sure to remove any legacy ``license`` table subkeys or ``License ::`` classifiers. Your existing ``license`` value may already be valid as one (e.g. ``MIT``, ``Apache-2.0 OR BSD-2-Clause``, etc); otherwise, check the `SPDX license list `__ for the identifier -that matches the license used in your project. +that matches the license used. Make sure to list your license files under ``license-files`` under ``[project]`` in :file:`pyproject.toml` @@ -311,13 +312,12 @@ software, you can construct a license expression to describe the licenses involved and the relationship between them. -In short, ``License-1 AND License-2`` mean that *both* licenses apply -to your project, or parts of it (for example, you included a file -under another license), and ``License-1 OR License-2`` means that -*either* of the licenses can be used, at the user's option (for example, -you want to allow users a choice of multiple licenses). You can use -parenthesis (``()``) for grouping to form expressions that cover even the most -complex situations. +In short, ``License-1 AND License-2`` mean that *both* licenses apply, or parts +of it (for example, you included a file under another license), and +``License-1 OR License-2`` means that *either* of the licenses can be used, at +the user's option (for example, you want to allow users a choice of multiple +licenses). You can use parenthesis (``()``) for grouping to form expressions +that cover even the most complex situations. In your project config file, enter your license expression under ``license`` (``[project]`` table of :file:`pyproject.toml`), diff --git a/source/guides/writing-pyproject-toml.rst b/source/guides/writing-pyproject-toml.rst index 1d035a384..3a8a8e5d4 100644 --- a/source/guides/writing-pyproject-toml.rst +++ b/source/guides/writing-pyproject-toml.rst @@ -296,10 +296,10 @@ You can also specify the format explicitly, like this: ``license`` and ``license-files`` --------------------------------- -As per :pep:`639` licenses should be declared with two fields: +As per :pep:`639`, licenses should be declared with two fields: -- ``license`` is an :term:`SPDX license expression ` consisting - of one or more :term:`license identifiers `. +- ``license`` is an :term:`SPDX license expression ` + consisting of one or more :term:`license identifiers `. - ``license-files`` is a list of license file glob patterns. A previous PEP had specified ``license`` to be a table with a ``file`` or a @@ -350,10 +350,11 @@ As a general rule, it is a good idea to use a standard, well-known license, both to avoid confusion and because some organizations avoid software whose license is unapproved. -If your project is licensed with a license that doesn't have an existing SPDX -identifier, you can create a custom one in format ``LicenseRef-[idstring]``. -The custom identifiers must follow the SPDX specification, -`clause 10.1 `_ of the version 2.2 or any later compatible one. +If your :term:`Distribution Archive` is licensed with a license that doesn't +have an existing SPDX identifier, you can create a custom one in format +``LicenseRef-[idstring]``. The custom identifiers must follow the SPDX +specification, `clause 10.1 `_ of the version 2.2 or any later +compatible one. .. code-block:: toml diff --git a/source/tutorials/packaging-projects.rst b/source/tutorials/packaging-projects.rst index f2c0851ba..4f69de20b 100644 --- a/source/tutorials/packaging-projects.rst +++ b/source/tutorials/packaging-projects.rst @@ -220,7 +220,7 @@ following this tutorial. your package will work on. For a complete list of classifiers, see https://pypi.org/classifiers/. - ``license`` is the :term:`SPDX license expression ` of - your package. + your :term:`Distribution Archive` files. - ``license-files`` is the list of glob paths to the license files, relative to the directory where :file:`pyproject.toml` is located. - ``urls`` lets you list any number of extra links to show on PyPI. @@ -250,12 +250,12 @@ if you'd like. Creating a LICENSE ------------------ -It's important for every package uploaded to the Python Package Index to include -a license. This tells users who install your package the terms under which they -can use your package. For help picking a license, see -https://choosealicense.com/. Once you have chosen a license, open -:file:`LICENSE` and enter the license text. For example, if you had chosen the -MIT license: +It's important for every :term:`Distribution Archive` uploaded to the Python +Package Index to include a license. This tells users who install your +:term:`Distribution Archive` the terms under which they can use it. For help +picking a license, see https://choosealicense.com/. Once you have chosen a +license, open :file:`LICENSE` and enter the license text. For example, if you +had chosen the MIT license: .. code-block:: text From ce4251e775d04f5577ad9b7a843703c3b87bd06c Mon Sep 17 00:00:00 2001 From: konstin Date: Mon, 15 Sep 2025 20:57:37 +0200 Subject: [PATCH 16/74] Create PR as draft --- .github/workflows/update-uv-build-version.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/update-uv-build-version.yml b/.github/workflows/update-uv-build-version.yml index a3cead001..8aadc7052 100644 --- a/.github/workflows/update-uv-build-version.yml +++ b/.github/workflows/update-uv-build-version.yml @@ -32,6 +32,7 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} commit-message: Update uv_build version to ${{ steps.update_script.outputs.version }} title: Update uv_build version to ${{ steps.update_script.outputs.version }} + draft: true # Trigger CI by un-drafting the PR, otherwise `GITHUB_TOKEN` PRs don't trigger CI. body: | Automated update of uv_build version bounds for uv ${{ steps.update_script.outputs.version }}. From 4f0a3c603d3a901bb00e1d52d639d6b1cb3aca5f Mon Sep 17 00:00:00 2001 From: Nick Coghlan Date: Tue, 16 Sep 2025 11:14:09 +1000 Subject: [PATCH 17/74] Vagrant link is failing CI, drop it entirely --- source/overview.rst | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/source/overview.rst b/source/overview.rst index 8c68036a7..70ef2d058 100644 --- a/source/overview.rst +++ b/source/overview.rst @@ -339,7 +339,7 @@ originated and where the technologies below work best: Bringing your own kernel ^^^^^^^^^^^^^^^^^^^^^^^^ -Most operating systems support some form of classical virtualization, +Most desktop operating systems support some form of classical virtualization, running applications packaged as images containing a full operating system of their own. Running these virtual machines, or VMs, is a mature approach, widespread in data center environments. @@ -348,9 +348,13 @@ These techniques are mostly reserved for larger scale deployments in data centers, though certain complex applications can benefit from this packaging. The technologies are Python agnostic, and include: -* `Vagrant `_ -* `VHD `_, `AMI `_, and :doc:`other formats ` -* `OpenStack `_ - A cloud management system in Python, with extensive VM support +* KVM on Linux +* Hyper-V on Windows +* `VHD `_, + `AMI `_, + and :doc:`other formats ` +* `OpenStack `_ - + A cloud management system written in Python, with extensive VM support Bringing your own hardware ^^^^^^^^^^^^^^^^^^^^^^^^^^ From c3274274483e7638d75699678347400b18773144 Mon Sep 17 00:00:00 2001 From: Nick Coghlan Date: Tue, 16 Sep 2025 11:36:49 +1000 Subject: [PATCH 18/74] Avoid binary gender assumptions in example Closes #1907 --- source/guides/creating-command-line-tools.rst | 46 ++++++++----------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/source/guides/creating-command-line-tools.rst b/source/guides/creating-command-line-tools.rst index 8266fffdb..045c221b4 100644 --- a/source/guides/creating-command-line-tools.rst +++ b/source/guides/creating-command-line-tools.rst @@ -40,33 +40,25 @@ named after the main module: def greet( - name: Annotated[str, typer.Argument(help="The (last, if --gender is given) name of the person to greet")] = "", - gender: Annotated[str, typer.Option(help="The gender of the person to greet")] = "", + name: Annotated[str, typer.Argument(help="The (last, if --title is given) name of the person to greet")] = "", + title: Annotated[str, typer.Option(help="The preferred title of the person to greet")] = "", knight: Annotated[bool, typer.Option(help="Whether the person is a knight")] = False, count: Annotated[int, typer.Option(help="Number of times to greet the person")] = 1 ): - greeting = "Greetings, dear " - masculine = gender == "masculine" - feminine = gender == "feminine" - if gender or knight: + greeting = "Greetings, " + if not name: + if title: + name = title.lower().rstrip(".") + else: + name = "friend" + if title or knight: salutation = "" - if knight: + if title: + salutation = title + elif knight: salutation = "Sir " - elif masculine: - salutation = "Mr. " - elif feminine: - salutation = "Ms. " greeting += salutation - if name: - greeting += f"{name}!" - else: - pronoun = "her" if feminine else "his" if masculine or knight else "its" - greeting += f"what's-{pronoun}-name" - else: - if name: - greeting += f"{name}!" - elif not gender: - greeting += "friend!" + greeting += f"{name}!" for i in range(0, count): print(greeting) @@ -145,12 +137,14 @@ Let's test it: .. code-block:: console + $ greet + Greetings, friend! $ greet --knight Lancelot - Greetings, dear Sir Lancelot! - $ greet --gender feminine Parks - Greetings, dear Ms. Parks! - $ greet --gender masculine - Greetings, dear Mr. what's-his-name! + Greetings, Sir Lancelot! + $ greet --title Ms. Parks + Greetings, Ms. Parks! + $ greet --title Mr. + Greetings, Mr. mr! Since this example uses ``typer``, you could now also get an overview of the program's usage by calling it with the ``--help`` option, or configure completions via the ``--install-completion`` option. From 332cc3086f6f1f4e9e53062914733a8a439c7102 Mon Sep 17 00:00:00 2001 From: Nick Coghlan Date: Tue, 16 Sep 2025 11:53:35 +1000 Subject: [PATCH 19/74] Use a more obviously gender neutral title --- source/guides/creating-command-line-tools.rst | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/source/guides/creating-command-line-tools.rst b/source/guides/creating-command-line-tools.rst index 045c221b4..5e96b7da5 100644 --- a/source/guides/creating-command-line-tools.rst +++ b/source/guides/creating-command-line-tools.rst @@ -42,7 +42,7 @@ named after the main module: def greet( name: Annotated[str, typer.Argument(help="The (last, if --title is given) name of the person to greet")] = "", title: Annotated[str, typer.Option(help="The preferred title of the person to greet")] = "", - knight: Annotated[bool, typer.Option(help="Whether the person is a knight")] = False, + doctor: Annotated[bool, typer.Option(help="Whether the person is a doctor (MD or PhD)")] = False, count: Annotated[int, typer.Option(help="Number of times to greet the person")] = 1 ): greeting = "Greetings, " @@ -51,13 +51,10 @@ named after the main module: name = title.lower().rstrip(".") else: name = "friend" - if title or knight: - salutation = "" - if title: - salutation = title - elif knight: - salutation = "Sir " - greeting += salutation + if doctor and not title: + title = "Dr." + if title: + greeting += f"{title} " greeting += f"{name}!" for i in range(0, count): print(greeting) From 159fc06e960d9399a43adf59abcf22d592fbbb3b Mon Sep 17 00:00:00 2001 From: Nick Coghlan Date: Tue, 16 Sep 2025 11:55:30 +1000 Subject: [PATCH 20/74] Update example output --- source/guides/creating-command-line-tools.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/source/guides/creating-command-line-tools.rst b/source/guides/creating-command-line-tools.rst index 5e96b7da5..72e3e37ef 100644 --- a/source/guides/creating-command-line-tools.rst +++ b/source/guides/creating-command-line-tools.rst @@ -46,13 +46,13 @@ named after the main module: count: Annotated[int, typer.Option(help="Number of times to greet the person")] = 1 ): greeting = "Greetings, " + if doctor and not title: + title = "Dr." if not name: if title: name = title.lower().rstrip(".") else: name = "friend" - if doctor and not title: - title = "Dr." if title: greeting += f"{title} " greeting += f"{name}!" @@ -136,8 +136,8 @@ Let's test it: $ greet Greetings, friend! - $ greet --knight Lancelot - Greetings, Sir Lancelot! + $ greet --doctor Brennan + Greetings, Dr. Brennan! $ greet --title Ms. Parks Greetings, Ms. Parks! $ greet --title Mr. @@ -151,7 +151,7 @@ To just run the program without installing it permanently, use ``pipx run``, whi .. code-block:: console - $ pipx run --spec . greet --knight + $ pipx run --spec . greet --doctor This syntax is a bit impractical, however; as the name of the entry point we defined above does not match the package name, we need to state explicitly which executable script to run (even though there is only on in existence). @@ -170,7 +170,7 @@ default one and run it, which makes this command possible: .. code-block:: console - $ pipx run . --knight + $ pipx run . --doctor Conclusion ========== From bceb2644a302db55733492e4489883699f961921 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Mon, 15 Sep 2025 21:59:01 -0400 Subject: [PATCH 21/74] ci: remove workflow_dispatch from cron.yml Signed-off-by: William Woodruff --- .github/workflows/cron.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/cron.yml b/.github/workflows/cron.yml index f1eddccb5..8870bb70b 100644 --- a/.github/workflows/cron.yml +++ b/.github/workflows/cron.yml @@ -5,7 +5,6 @@ name: Cron on: schedule: - cron: "0 6 * * *" # daily at 6am - workflow_dispatch: jobs: test: From c7ffbccf513399c2cddd0dbed7183d4835429419 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Mon, 15 Sep 2025 22:06:31 -0400 Subject: [PATCH 22/74] ci: add pull_request event subtypes Signed-off-by: William Woodruff --- .github/workflows/test.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8503ca720..172fed713 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,12 +6,19 @@ on: branches-ignore: - gh-readonly-queue/** # Temporary merge queue-related GH-made branches pull_request: + types: + - opened # default + - synchronize # default + - reopened # default + - ready_for_review # used in PRs created from GitHub Actions workflows workflow_call: concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} cancel-in-progress: true +permissions: {} + jobs: build: name: ${{ matrix.noxenv }} From b036f24d6fefac29c3b95a7b8810b62117529f5c Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Mon, 15 Sep 2025 22:06:53 -0400 Subject: [PATCH 23/74] update_uv_build_version: remove unneeded format Signed-off-by: William Woodruff --- scripts/update_uv_build_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/update_uv_build_version.py b/scripts/update_uv_build_version.py index 816ab9061..69fefba27 100644 --- a/scripts/update_uv_build_version.py +++ b/scripts/update_uv_build_version.py @@ -34,7 +34,7 @@ def main(): [major, minor, _patch] = current_release.release if major != 0: raise NotImplementedError("The script needs to be updated for uv 1.x") - upper_bound = Version(f"{major}.{minor + 1}.{0}") + upper_bound = Version(f"{major}.{minor + 1}.0") repository_root = Path(__file__).parent.parent existing = repository_root.joinpath( From 71eb39402354a259a151dd2ea837b4b90219edb4 Mon Sep 17 00:00:00 2001 From: woodruffw <3059210+woodruffw@users.noreply.github.com> Date: Tue, 16 Sep 2025 14:15:24 +0000 Subject: [PATCH 24/74] Update uv_build version to 0.8.17 --- source/shared/build-backend-tabs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/shared/build-backend-tabs.rst b/source/shared/build-backend-tabs.rst index 608fcaddd..9efc8b0d7 100644 --- a/source/shared/build-backend-tabs.rst +++ b/source/shared/build-backend-tabs.rst @@ -38,5 +38,5 @@ .. code-block:: toml [build-system] - requires = ["uv_build >= 0.7.19, <0.9.0"] + requires = ["uv_build >= 0.8.17, <0.9.0"] build-backend = "uv_build" From dd267139d93bdc154629f1038b852b8178681102 Mon Sep 17 00:00:00 2001 From: Philip Mallegol-Hansen Date: Tue, 16 Sep 2025 13:25:53 -0700 Subject: [PATCH 25/74] Updates table to contain poetry-core version supporting PEP 639 --- source/guides/writing-pyproject-toml.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/guides/writing-pyproject-toml.rst b/source/guides/writing-pyproject-toml.rst index 1d035a384..b8be3e85d 100644 --- a/source/guides/writing-pyproject-toml.rst +++ b/source/guides/writing-pyproject-toml.rst @@ -319,7 +319,7 @@ backend>` now support the new format as shown in the following table. - 77.0.3 - 3.12 - 2.4.0 - - `not yet `_ + - 2.2.0 - 0.7.19 @@ -587,7 +587,6 @@ A full example .. _pypi-search-pip: https://pypi.org/search?q=pip .. _classifier-list: https://pypi.org/classifiers .. _requires-python-blog-post: https://iscinumpy.dev/post/bound-version-constraints/#pinning-the-python-version-is-special -.. _poetry-pep639-issue: https://github.com/python-poetry/poetry/issues/9670 .. _pytest: https://pytest.org .. _pygments: https://pygments.org .. _rest: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html From 3669181977fc68f686eac4c29ba25564ed964abc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Ram=C3=ADrez-Mondrag=C3=B3n?= Date: Sat, 13 Sep 2025 11:12:38 -0600 Subject: [PATCH 26/74] Fix links to spec schemas --- .../specifications/schemas/build-details-v1.0.schema.json | 0 .../specifications/schemas/direct-url.schema.json | 0 .../specifications/schemas/pylock.schema.json | 0 source/conf.py | 7 +++++++ source/specifications/build-details/v1.0.rst | 2 +- source/specifications/direct-url-data-structure.rst | 2 +- 6 files changed, 9 insertions(+), 2 deletions(-) rename {source => extra}/specifications/schemas/build-details-v1.0.schema.json (100%) rename {source => extra}/specifications/schemas/direct-url.schema.json (100%) rename {source => extra}/specifications/schemas/pylock.schema.json (100%) diff --git a/source/specifications/schemas/build-details-v1.0.schema.json b/extra/specifications/schemas/build-details-v1.0.schema.json similarity index 100% rename from source/specifications/schemas/build-details-v1.0.schema.json rename to extra/specifications/schemas/build-details-v1.0.schema.json diff --git a/source/specifications/schemas/direct-url.schema.json b/extra/specifications/schemas/direct-url.schema.json similarity index 100% rename from source/specifications/schemas/direct-url.schema.json rename to extra/specifications/schemas/direct-url.schema.json diff --git a/source/specifications/schemas/pylock.schema.json b/extra/specifications/schemas/pylock.schema.json similarity index 100% rename from source/specifications/schemas/pylock.schema.json rename to extra/specifications/schemas/pylock.schema.json diff --git a/source/conf.py b/source/conf.py index a8a040d6c..3ffa98b0f 100644 --- a/source/conf.py +++ b/source/conf.py @@ -83,6 +83,10 @@ # https://plausible.io/packaging.python.org html_js_files.extend(_metrics_js_files) +html_extra_path = [ + "../extra", +] + # -- Options for HTML help output ------------------------------------------------------ # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-help-output @@ -157,6 +161,9 @@ # https://github.com/pypa/packaging.python.org/issues/1744 r"https://pypi\.org/", ] +linkcheck_exclude_documents = [ + "specifications/schemas/index", +] # -- Options for extlinks ---------------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/extensions/extlinks.html#configuration diff --git a/source/specifications/build-details/v1.0.rst b/source/specifications/build-details/v1.0.rst index cfe902e1e..3a8cfe277 100644 --- a/source/specifications/build-details/v1.0.rst +++ b/source/specifications/build-details/v1.0.rst @@ -8,7 +8,7 @@ Specification ------------- -.. jsonschema:: ../schemas/build-details-v1.0.schema.json +.. jsonschema:: ../../../extra/specifications/schemas/build-details-v1.0.schema.json :lift_title: false diff --git a/source/specifications/direct-url-data-structure.rst b/source/specifications/direct-url-data-structure.rst index 5f3af0fae..a82537f0a 100644 --- a/source/specifications/direct-url-data-structure.rst +++ b/source/specifications/direct-url-data-structure.rst @@ -236,7 +236,7 @@ JSON Schema The following JSON Schema can be used to validate the contents of ``direct_url.json``: -.. literalinclude:: schemas/direct-url.schema.json +.. literalinclude:: ../../extra/specifications/schemas/direct-url.schema.json Examples ======== From 6ae0da519af5615f4f28b28d3d738755075866a3 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Wed, 10 Sep 2025 12:26:26 -0700 Subject: [PATCH 27/74] Clarify that the `license` key in `pyprojcet.toml` should only be set if it is consistent across all distribution files This change is approved at https://discuss.python.org/t/split-from-pep-639-expressing-project-vs-distribution-licenses-post-pep-639-mod-titled/90314/179 . --- source/specifications/pyproject-toml.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/specifications/pyproject-toml.rst b/source/specifications/pyproject-toml.rst index 4ce9b7484..c94e78d83 100644 --- a/source/specifications/pyproject-toml.rst +++ b/source/specifications/pyproject-toml.rst @@ -259,6 +259,11 @@ Text string that is a valid SPDX as specified in :doc:`/specifications/license-expression`. Tools SHOULD validate and perform case normalization of the expression. +This key should **only** be specified if the license expression for any +and all distribution files generated from the ``pyproject.toml`` is the +same as the one specified. If the license expression will differ then +it should either be specified as dynamic or not set at all. + Legacy specification '''''''''''''''''''' From 3504230284d0802c38859fcd18f9ca59970daaec Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Wed, 10 Sep 2025 12:30:49 -0700 Subject: [PATCH 28/74] Add a history entry --- source/specifications/pyproject-toml.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/specifications/pyproject-toml.rst b/source/specifications/pyproject-toml.rst index c94e78d83..7950bccbc 100644 --- a/source/specifications/pyproject-toml.rst +++ b/source/specifications/pyproject-toml.rst @@ -545,5 +545,8 @@ History - December 2024: The ``license`` key was redefined, the ``license-files`` key was added and ``License::`` classifiers were deprecated through :pep:`639`. +- September 2025: Clarity that the ``license`` key applies to all distribution + files generated from the ``pyproject.toml`` file. + .. _TOML: https://toml.io From b947936259353b85c34252dc01c2e11a97762482 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Mon, 15 Sep 2025 17:09:25 +0100 Subject: [PATCH 29/74] Apply suggestion from @webknjaz MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 🇺🇦 Sviatoslav Sydorenko (Святослав Сидоренко) --- source/specifications/pyproject-toml.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/specifications/pyproject-toml.rst b/source/specifications/pyproject-toml.rst index 7950bccbc..4a14615b9 100644 --- a/source/specifications/pyproject-toml.rst +++ b/source/specifications/pyproject-toml.rst @@ -260,7 +260,7 @@ as specified in :doc:`/specifications/license-expression`. Tools SHOULD validate and perform case normalization of the expression. This key should **only** be specified if the license expression for any -and all distribution files generated from the ``pyproject.toml`` is the +and all distribution files generated from the :file:`pyproject.toml` is the same as the one specified. If the license expression will differ then it should either be specified as dynamic or not set at all. From ed6f9704411531d46756ef7b49f7109aa73fd6e6 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Mon, 15 Sep 2025 17:09:31 +0100 Subject: [PATCH 30/74] Apply suggestion from @webknjaz MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 🇺🇦 Sviatoslav Sydorenko (Святослав Сидоренко) --- source/specifications/pyproject-toml.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/specifications/pyproject-toml.rst b/source/specifications/pyproject-toml.rst index 4a14615b9..3c47b9d50 100644 --- a/source/specifications/pyproject-toml.rst +++ b/source/specifications/pyproject-toml.rst @@ -546,7 +546,7 @@ History added and ``License::`` classifiers were deprecated through :pep:`639`. - September 2025: Clarity that the ``license`` key applies to all distribution - files generated from the ``pyproject.toml`` file. + files generated from the :file:`pyproject.toml` file. .. _TOML: https://toml.io From 3851b070abb3ed435f1b52572593e96970eb9431 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Mon, 15 Sep 2025 17:11:00 +0100 Subject: [PATCH 31/74] Fix wording in pyproject-toml.rst license section --- source/specifications/pyproject-toml.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/source/specifications/pyproject-toml.rst b/source/specifications/pyproject-toml.rst index 3c47b9d50..bb0e56ff7 100644 --- a/source/specifications/pyproject-toml.rst +++ b/source/specifications/pyproject-toml.rst @@ -260,9 +260,10 @@ as specified in :doc:`/specifications/license-expression`. Tools SHOULD validate and perform case normalization of the expression. This key should **only** be specified if the license expression for any -and all distribution files generated from the :file:`pyproject.toml` is the -same as the one specified. If the license expression will differ then -it should either be specified as dynamic or not set at all. +and all distribution files created by a build backend using the +:file:`pyproject.toml` is the same as the one specified. If the license +expression will differ then it should either be specified as dynamic or +not set at all. Legacy specification '''''''''''''''''''' From 5a822ab5af0d305d175e5cb475bfcbcdd9497b74 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 3 Oct 2025 22:41:35 +0000 Subject: [PATCH 32/74] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- source/specifications/core-metadata.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/specifications/core-metadata.rst b/source/specifications/core-metadata.rst index 665f8704a..42c6b9ec6 100644 --- a/source/specifications/core-metadata.rst +++ b/source/specifications/core-metadata.rst @@ -938,7 +938,7 @@ History - October 2025: Clarified that ``License-Expression`` applies to the containing distribution file and not the project itself. - + - August 2025: Clarified that ``Dynamic`` only affects how fields must be treated when building a wheel from a sdist, not when modifying a wheel. From 4a44bffed7f86296599e0dd5ab968343e5450654 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Fri, 3 Oct 2025 15:45:25 -0700 Subject: [PATCH 33/74] Fix formatting of license expression explanation --- source/guides/licensing-examples-and-user-scenarios.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/guides/licensing-examples-and-user-scenarios.rst b/source/guides/licensing-examples-and-user-scenarios.rst index 9f32b6117..b6cdfe327 100644 --- a/source/guides/licensing-examples-and-user-scenarios.rst +++ b/source/guides/licensing-examples-and-user-scenarios.rst @@ -312,8 +312,8 @@ software, you can construct a license expression to describe the licenses involved and the relationship between them. -In short, ``License-1 AND License-2`` mean that *both* licenses apply, or parts -of it (for example, you included a file under another license), and +In short, ``License-1 AND License-2`` mean that *both* licenses apply +(for example, you included a file under another license), and ``License-1 OR License-2`` means that *either* of the licenses can be used, at the user's option (for example, you want to allow users a choice of multiple licenses). You can use parenthesis (``()``) for grouping to form expressions From 465a5bfa5e8da07656e20ab46df41489c29629da Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Tue, 7 Oct 2025 09:37:57 -0700 Subject: [PATCH 34/74] Try to clarify what a "distribution archive" is --- source/specifications/core-metadata.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/specifications/core-metadata.rst b/source/specifications/core-metadata.rst index 42c6b9ec6..b6d92e6f2 100644 --- a/source/specifications/core-metadata.rst +++ b/source/specifications/core-metadata.rst @@ -483,8 +483,10 @@ Text string that is a valid SPDX :term:`license expression `, as specified in :doc:`/specifications/license-expression`. -Note that the expression in this field only applies to the distribution file -containing the metadata, not the project overall or other distribution files. +Note that the expression in this field only applies to the +:term:`Distribution Archive` containing the metadata with this field (e.g., +:term:`Source Distribution` or :term:`Wheel`), not the project overall or +other files related to the project (including other distribution archives). Examples:: From db0173577ef2328967b06043d7cacfb6f3a536c0 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Tue, 7 Oct 2025 11:04:31 -0700 Subject: [PATCH 35/74] Add PEP 794: Import name metadata --- source/specifications/core-metadata.rst | 134 ++++++++++++++++++++--- source/specifications/pyproject-toml.rst | 96 ++++++++++++++++ 2 files changed, 213 insertions(+), 17 deletions(-) diff --git a/source/specifications/core-metadata.rst b/source/specifications/core-metadata.rst index c020e1469..0ea469fd8 100644 --- a/source/specifications/core-metadata.rst +++ b/source/specifications/core-metadata.rst @@ -6,7 +6,7 @@ Core metadata specifications ============================ -This page describes version 2.4, approved in August 2024. +This page describes version 2.5, approved in September 2025. Fields defined in the following specification should be considered valid, complete and not subject to change. The required fields are: @@ -50,7 +50,7 @@ Metadata-Version .. versionadded:: 1.0 Version of the file format; legal values are "1.0", "1.1", "1.2", "2.1", -"2.2", "2.3", and "2.4". +"2.2", "2.3", "2.4", and "2.5". Automated tools consuming metadata SHOULD warn if ``metadata_version`` is greater than the highest version they support, and MUST fail if @@ -718,6 +718,101 @@ user SHOULD be warned and the value ignored to avoid ambiguity. Tools MAY choose to raise an error when reading an invalid name for older metadata versions. +.. _core-metadata-import-name: + +Import-Name (multiple use) +=========================== + +.. versionadded:: 2.5 + +A string containing an import name that the project exclusively provides when +installed. The specified import name MUST be a valid Python identifier or can +be empty. The import names listed in this field MUST be importable when the +project is installed on *some* platform for the same version of the project. +This implies that the metadata MUST be consistent across all sdists and wheels +for a project release. + +An import name MAY be followed by a semicolon and the term "private" +(e.g. ``; private``) with any amount of whitespace surrounding the semicolon. +This signals to tools that the import name is not part of the public API for +the project. + +Projects SHOULD list all the shortest import names that are exclusively provided +by the project. If any of the shortest names are dotted names, all intervening +names from that name to the top-level name should also be listed appropriately +in ``Import-Name`` and/or ``Import-Namespace``. + +If a project lists the same name in both ``Import-Name`` and +``Import-Namespace``, tools MUST raise an error due to ambiguity. + +Tools SHOULD raise an error when two projects that are about to be installed +list names that overlap in each other's ``Import-Name`` entries, or when a +project has an entry in ``Import-Name`` that overlaps with another project's +``Import-Namespace`` entries. This is to avoid projects unexpectedly shadowing +another project's code. Tools MAY warn or raise an error when installing a +project into a preexisting environment where there is import name overlap with +a project that is already installed. + +Projects MAY have an empty ``Import-Name`` field in their metadata to represent +a project with no import names (i.e. there are no Python modules of any kind in +the distribution file). + +Since projects MAY have no ``Import-Name`` metadata (either because the +project uses an older metadata version, or because it didn't specify any), then +tools have no information about what names the project provides. However, in +practice the majority of projects have their project name match what their +import name would be. As such, it is a reasonable assumption to make that a +project name that is normalized in some way to an import name +(e.g. ``packaging.utils.canonicalize_name(name, validate=True).replace("-", "_")``) +can be used if some answer is needed. + +Examples:: + + Import-Name: PIL + Import-Name: _private_module ; private + Import-Name: zope.interface + Import-Name: + + +.. _core-metadata-import-namespace: + +Import-Namespace (multiple use) +================================ + +.. versionadded:: 2.5 + +A string containing an import name that the project provides when installed, but +not exclusively. The specified import name MUST be a valid Python identifier. +This field is used for namespace packages where multiple projects can contribute +to the same import namespace. Projects all listing the same import name in +``Import-Namespace`` can be installed together without shadowing each other. + +An import name MAY be followed by a semicolon and the term "private" (e.g. +``; private``) with any amount of whitespace surrounding the semicolon. This +signals to tools that the import name is not part of the public API for the +project. + +Projects SHOULD list all the shortest import names that are exclusively provided +by the project. If any of the shortest names are dotted names, all intervening +names from that name to the top-level name should also be listed appropriately +in ``Import-Name`` and/or ``Import-Namespace``. + +The import names listed in this field MUST be importable when the project is +installed on *some* platform for the same version of the project. This implies +that the metadata MUST be consistent across all sdists and wheels for a project +release. + +If a project lists the same name in both ``Import-Name`` and +``Import-Namespace``, tools MUST raise an error due to ambiguity. + +Note that ``Import-Namespace`` CANNOT be empty like ``Import-Name``. + +Examples:: + + Import-Namespace: zope + Import-Name: _private_module ; private + + Rarely Used Fields ================== @@ -933,34 +1028,39 @@ Example:: History ======= -- August 2025: Clarified that ``Dynamic`` only affects how fields - must be treated when building a wheel from a sdist, not when modifying - a wheel. +- March 2001: Core metadata 1.0 was approved through :pep:`241`. -- August 2024: Core metadata 2.4 was approved through :pep:`639`. +- April 2003: Core metadata 1.1 was approved through :pep:`314`. - - Added the ``License-Expression`` field. - - Added the ``License-File`` field. +- February 2010: Core metadata 1.2 was approved through :pep:`345`. -- March 2022: Core metadata 2.3 was approved through :pep:`685`. +- February 2018: Core metadata 2.1 was approved through :pep:`566`. - - Restricted extra names to be normalized. + - Added ``Description-Content-Type`` and ``Provides-Extra``. + - Added canonical method for transforming metadata to JSON. + - Restricted the grammar of the ``Name`` field. - October 2020: Core metadata 2.2 was approved through :pep:`643`. - Added the ``Dynamic`` field. -- February 2018: Core metadata 2.1 was approved through :pep:`566`. +- March 2022: Core metadata 2.3 was approved through :pep:`685`. - - Added ``Description-Content-Type`` and ``Provides-Extra``. - - Added canonical method for transforming metadata to JSON. - - Restricted the grammar of the ``Name`` field. + - Restricted extra names to be normalized. -- February 2010: Core metadata 1.2 was approved through :pep:`345`. +- August 2024: Core metadata 2.4 was approved through :pep:`639`. -- April 2003: Core metadata 1.1 was approved through :pep:`314`: + - Added the ``License-Expression`` field. + - Added the ``License-File`` field. -- March 2001: Core metadata 1.0 was approved through :pep:`241`. +- August 2025: Clarified that ``Dynamic`` only affects how fields + must be treated when building a wheel from a sdist, not when modifying + a wheel. + +- September 2025: Core metadata 2.5 was approved through :pep:`794`. + + - Added the ``Import-Name`` field. + - Added the ``Import-Namespace`` field. ---- diff --git a/source/specifications/pyproject-toml.rst b/source/specifications/pyproject-toml.rst index 4ce9b7484..25004dfd5 100644 --- a/source/specifications/pyproject-toml.rst +++ b/source/specifications/pyproject-toml.rst @@ -136,6 +136,8 @@ The complete list of keys allowed in the ``[project]`` table are: - ``dynamic`` - ``entry-points`` - ``gui-scripts`` +- ``import-names`` +- ``import-namespaces`` - ``keywords`` - ``license`` - ``license-files`` @@ -466,6 +468,97 @@ matching :ref:`Provides-Extra ` metadata. +.. _pyproject-toml-import-names: + +``import-names`` +---------------- + +- TOML_ type: array of strings +- Corresponding :ref:`core metadata ` field: + :ref:`Import-Name ` + +An array of strings specifying the import names that the project exclusively +provides when installed. Each string MUST be a valid Python identifier or can +be empty. An import name MAY be followed by a semicolon and the term "private" +(e.g. ``"; private"``) with any amount of whitespace surrounding the semicolon. + +Projects SHOULD list all the shortest import names that are exclusively provided +by the project. If any of the shortest names are dotted names, all intervening +names from that name to the top-level name should also be listed appropriately +in ``import-names`` and/or ``import-namespaces``. For instance, a project which +is a single package named spam with multiple submodules would only list +``project.import-names = ["spam"]``. A project that lists ``spam.bacon.eggs`` +would also need to account for ``spam`` and ``spam.bacon`` appropriately in +``import-names`` and ``import-namespaces``. Listing all names acts as a check +that the intent of the import names is as expected. As well, projects SHOULD +list all import names, public or private, using the ``; private`` modifier as +appropriate. + +If a project lists the same name in both ``import-names`` and +``import-namespaces``, then tools MUST raise an error due to ambiguity. + +Projects MAY set ``import-names`` to an empty array to represent a project with +no import names (i.e. there are no Python modules of any kind in the +distribution file). + +Build back-ends MAY support dynamically calculating the value if the user +declares the key in ``project.dynamic``. + +Examples: + +.. code-block:: toml + + [project] + name = "pillow" + import-names = ["PIL"] + +.. code-block:: toml + + [project] + name = "myproject" + import-names = ["mypackage", "_private_module ; private"] + + +.. _pyproject-toml-import-namespaces: + +``import-namespaces`` +--------------------- + +- TOML_ type: array of strings +- Corresponding :ref:`core metadata ` field: + :ref:`Import-Namespace ` + +An array of strings specifying the import names that the project provides when +installed, but not exclusively. Each string MUST be a valid Python identifier. +An import name MAY be followed by a semicolon and the term "private" (e.g. +``"; private"``) with any amount of whitespace surrounding the semicolon. Note +that unlike ``import-names``, ``import-namespaces`` CANNOT be an empty array. + +Projects SHOULD list all the shortest import names that are exclusively provided +by the project. If any of the shortest names are dotted names, all intervening +names from that name to the top-level name should also be listed appropriately +in ``import-names`` and/or ``import-namespaces``. + +This field is used for namespace packages where multiple projects can contribute +to the same import namespace. Projects all listing the same import name in +``import-namespaces`` can be installed together without shadowing each other. + +If a project lists the same name in both ``import-names`` and +``import-namespaces``, then tools MUST raise an error due to ambiguity. + +Build back-ends MAY support dynamically calculating the value if the user +declares the key in ``project.dynamic``. + +Example: + +.. code-block:: toml + + [project] + name = "zope-interface" + import-namespaces = ["zope"] + import-names = ["zope.interface"] + + .. _pyproject-toml-dynamic: .. _declaring-project-metadata-dynamic: @@ -540,5 +633,8 @@ History - December 2024: The ``license`` key was redefined, the ``license-files`` key was added and ``License::`` classifiers were deprecated through :pep:`639`. +- September 2025: The ``import-names`` and ``import-namespaces`` keys were added + through :pep:`794`. + .. _TOML: https://toml.io From 85b31ffb80b6d59f752441b07323ab00eea90eaa Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Tue, 7 Oct 2025 11:45:33 -0700 Subject: [PATCH 36/74] Fix glossary link --- source/specifications/core-metadata.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/specifications/core-metadata.rst b/source/specifications/core-metadata.rst index b6d92e6f2..68cc4851f 100644 --- a/source/specifications/core-metadata.rst +++ b/source/specifications/core-metadata.rst @@ -485,8 +485,9 @@ as specified in :doc:`/specifications/license-expression`. Note that the expression in this field only applies to the :term:`Distribution Archive` containing the metadata with this field (e.g., -:term:`Source Distribution` or :term:`Wheel`), not the project overall or -other files related to the project (including other distribution archives). +:term:`Source Distribution ` or :term:`Wheel`), +not the project overall or other files related to the project (including other +distribution archives). Examples:: From e05eb7ac60ae9778da4073d17dcd8260efdd3261 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Wed, 8 Oct 2025 16:09:31 -0700 Subject: [PATCH 37/74] Add npmjs.com to linkcheck regex patterns --- source/conf.py | 1 + 1 file changed, 1 insertion(+) diff --git a/source/conf.py b/source/conf.py index a8a040d6c..95f6f3421 100644 --- a/source/conf.py +++ b/source/conf.py @@ -146,6 +146,7 @@ r"https://math-atlas\.sourceforge\.net/?", r"https://click\.palletsprojects\.com/.*", r"https://typer\.tiangolo\.com/.*", + r"https://www.npmjs.com/.*", ] linkcheck_retries = 5 # Ignore anchors for common targets when we know they likely won't be found From 3d1bcf33a28453b026355a0bfa55a639895d32f5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 16 Oct 2025 22:57:31 +0000 Subject: [PATCH 38/74] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- source/specifications/core-metadata.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/specifications/core-metadata.rst b/source/specifications/core-metadata.rst index 448e468c4..b49abee71 100644 --- a/source/specifications/core-metadata.rst +++ b/source/specifications/core-metadata.rst @@ -1067,7 +1067,7 @@ History - Added the ``Import-Name`` field. - Added the ``Import-Namespace`` field. - + - October 2025: Clarified that ``License-Expression`` applies to the containing distribution file and not the project itself. From d470a9fc70fc035f2f35854597f0ccae1501188c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=87=BA=F0=9F=87=A6=20Sviatoslav=20Sydorenko=20=28?= =?UTF-8?q?=D0=A1=D0=B2=D1=8F=D1=82=D0=BE=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1?= =?UTF-8?q?=D0=B8=D0=B4=D0=BE=D1=80=D0=B5=D0=BD=D0=BA=D0=BE=29?= Date: Fri, 17 Oct 2025 01:36:37 +0200 Subject: [PATCH 39/74] Match RST underlines with title lengths --- source/specifications/core-metadata.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/specifications/core-metadata.rst b/source/specifications/core-metadata.rst index b49abee71..06562e18d 100644 --- a/source/specifications/core-metadata.rst +++ b/source/specifications/core-metadata.rst @@ -727,7 +727,7 @@ to raise an error when reading an invalid name for older metadata versions. .. _core-metadata-import-name: Import-Name (multiple use) -=========================== +========================== .. versionadded:: 2.5 @@ -783,7 +783,7 @@ Examples:: .. _core-metadata-import-namespace: Import-Namespace (multiple use) -================================ +=============================== .. versionadded:: 2.5 From 1f731d298bc18db1e015b8e37e783ae53acd4780 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 19:05:07 +0000 Subject: [PATCH 40/74] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/pre-commit-hooks: v5.0.0 → v6.0.0](https://github.com/pre-commit/pre-commit-hooks/compare/v5.0.0...v6.0.0) - [github.com/astral-sh/ruff-pre-commit: v0.12.2 → v0.13.3](https://github.com/astral-sh/ruff-pre-commit/compare/v0.12.2...v0.13.3) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e092c419c..615970dda 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,7 +3,7 @@ ci: repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v5.0.0 + rev: v6.0.0 hooks: - id: check-added-large-files - id: check-case-conflict @@ -37,7 +37,7 @@ repos: - id: rst-inline-touching-normal - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.12.2 + rev: v0.13.3 hooks: - id: ruff - id: ruff-format From 1b0bd3162a664de2ae2c0628cf3da1cc2eac58fb Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Tue, 12 Aug 2025 15:12:47 -0400 Subject: [PATCH 41/74] simple-repository-api: remove partial TUF section Signed-off-by: William Woodruff --- .../specifications/simple-repository-api.rst | 40 ------------------- 1 file changed, 40 deletions(-) diff --git a/source/specifications/simple-repository-api.rst b/source/specifications/simple-repository-api.rst index 4f5bb0043..3b9a2ccac 100644 --- a/source/specifications/simple-repository-api.rst +++ b/source/specifications/simple-repository-api.rst @@ -910,46 +910,6 @@ which version+format a specific repository URL was configured for, and when maki a request to that server, emit an ``Accept`` header that *only* includes the correct content type. - -TUF Support - PEP 458 ---------------------- - -:pep:`458` requires that all API responses are hashable and that they can be uniquely -identified by a path relative to the repository root. For a Simple API repository, the -target path is the Root of our API (e.g. ``/simple/`` on PyPI). This creates -challenges when accessing the API using a TUF client instead of directly using a -standard HTTP client, as the TUF client cannot handle the fact that a target could -have multiple different representations that all hash differently. - -:pep:`458` does not specify what the target path should be for the Simple API, but -TUF requires that the target paths be "file-like", in other words, a path like -``simple/PROJECT/`` is not acceptable, because it technically points to a -directory. - -The saving grace is that the target path does not *have* to actually match the URL -being fetched from the Simple API, and it can just be a sigil that the fetching code -knows how to transform into the actual URL that needs to be fetched. This same thing -can hold true for other aspects of the actual HTTP request, such as the ``Accept`` -header. - -Ultimately figuring out how to map a directory to a filename is out of scope for this -spec (but it would be in scope for :pep:`458`), and this spec defers making a decision -about how exactly to represent this inside of :pep:`458` metadata. - -However, it appears that the current WIP branch against pip that attempts to implement -:pep:`458` is using a target path like ``simple/PROJECT/index.html``. This could be -modified to include the API version and serialization format using something like -``simple/PROJECT/vnd.pypi.simple.vN.FORMAT``. So the v1 HTML format would be -``simple/PROJECT/vnd.pypi.simple.v1.html`` and the v1 JSON format would be -``simple/PROJECT/vnd.pypi.simple.v1.json``. - -In this case, since ``text/html`` is an alias to ``application/vnd.pypi.simple.v1+html`` -when interacting through TUF, it likely will make the most sense to normalize to the -more explicit name. - -Likewise the ``latest`` metaversion should not be included in the targets, only -explicitly declared versions should be supported. - Recommendations --------------- From 71295b0302931d34a9d9f1e61a7a3ff0e8185a01 Mon Sep 17 00:00:00 2001 From: github-merge-queue <118344674+github-merge-queue@users.noreply.github.com> Date: Mon, 13 Oct 2025 06:11:04 +0000 Subject: [PATCH 42/74] Update uv_build version to 0.9.2 --- source/shared/build-backend-tabs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/shared/build-backend-tabs.rst b/source/shared/build-backend-tabs.rst index 9efc8b0d7..c753563dc 100644 --- a/source/shared/build-backend-tabs.rst +++ b/source/shared/build-backend-tabs.rst @@ -38,5 +38,5 @@ .. code-block:: toml [build-system] - requires = ["uv_build >= 0.8.17, <0.9.0"] + requires = ["uv_build >= 0.9.2, <0.10.0"] build-backend = "uv_build" From db0ef80312ead420058be7c95f4bb63d865ce202 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Thu, 16 Oct 2025 21:30:42 -0400 Subject: [PATCH 43/74] chore(ci): address zizmor findings This is part 1 of N. The main focus in this PR is on unpinned references and inadvertent/unnecessary credential persistence. Signed-off-by: William Woodruff --- .github/workflows/pr-preview-links.yml | 2 +- .github/workflows/test-translations.yml | 10 ++++++---- .github/workflows/test.yml | 8 +++++--- .github/workflows/translation.yml | 7 ++++--- .github/workflows/update-uv-build-version.yml | 6 +++--- .github/workflows/zizmor.yml | 6 +++--- 6 files changed, 22 insertions(+), 17 deletions(-) diff --git a/.github/workflows/pr-preview-links.yml b/.github/workflows/pr-preview-links.yml index 90ea9cc73..291ec3ad2 100644 --- a/.github/workflows/pr-preview-links.yml +++ b/.github/workflows/pr-preview-links.yml @@ -17,6 +17,6 @@ jobs: documentation-links: runs-on: ubuntu-latest steps: - - uses: readthedocs/actions/preview@v1 + - uses: readthedocs/actions/preview@b8bba1484329bda1a3abe986df7ebc80a8950333 # v1.5 with: project-slug: "python-packaging-user-guide" diff --git a/.github/workflows/test-translations.yml b/.github/workflows/test-translations.yml index 45dc60aa3..ca6cb08f0 100644 --- a/.github/workflows/test-translations.yml +++ b/.github/workflows/test-translations.yml @@ -31,9 +31,10 @@ jobs: steps: - name: Grab the repo src - uses: actions/checkout@v4 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: ref: ${{ env.I18N_BRANCH }} + persist-credentials: false - name: List languages id: languages @@ -53,12 +54,13 @@ jobs: steps: - name: Grab the repo src - uses: actions/checkout@v4 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: ref: ${{ env.I18N_BRANCH }} + persist-credentials: false - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 with: python-version: >- 3.10 @@ -67,7 +69,7 @@ jobs: run: python -m pip install --upgrade nox virtualenv sphinx-lint - name: Set Sphinx problem matcher - uses: sphinx-doc/github-problem-matcher@v1.0 + uses: sphinx-doc/github-problem-matcher@1f74d6599f4a5e89a20d3c99aab4e6a70f7bda0f # v1.1 - name: Build translated docs in ${{ matrix.language }} run: nox -s build -- -q -D language=${{ matrix.language }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 172fed713..1f67bad8e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -31,10 +31,12 @@ jobs: - linkcheck steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + persist-credentials: false - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 with: python-version: "3.11" cache: 'pip' @@ -62,6 +64,6 @@ jobs: steps: - name: Decide whether the needed jobs succeeded or failed - uses: re-actors/alls-green@release/v1 + uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2 with: jobs: ${{ toJSON(needs) }} diff --git a/.github/workflows/translation.yml b/.github/workflows/translation.yml index 7cfae2991..1a3f71487 100644 --- a/.github/workflows/translation.yml +++ b/.github/workflows/translation.yml @@ -19,14 +19,15 @@ jobs: steps: - name: Grab the repo src - uses: actions/checkout@v3 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: fetch-depth: 0 # To reach the common commit + persist-credentials: true # For `git push` - name: Set up git user as [bot] # Refs: # * https://github.community/t/github-actions-bot-email-address/17204/6 # * https://github.com/actions/checkout/issues/13#issuecomment-724415212 - uses: fregante/setup-git-user@v1.1.0 + uses: fregante/setup-git-user@024bc0b8e177d7e77203b48dab6fb45666854b35 # v2.0.2 - name: Switch to the translation source branch run: | @@ -51,7 +52,7 @@ jobs: git merge '${{ github.event.repository.default_branch }}' - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 with: python-version: >- 3.10 diff --git a/.github/workflows/update-uv-build-version.yml b/.github/workflows/update-uv-build-version.yml index 8aadc7052..d204bd391 100644 --- a/.github/workflows/update-uv-build-version.yml +++ b/.github/workflows/update-uv-build-version.yml @@ -17,17 +17,17 @@ jobs: pull-requests: write steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - name: Set up uv - uses: astral-sh/setup-uv@v5 + uses: astral-sh/setup-uv@3259c6206f993105e3a61b142c2d97bf4b9ef83d # v7.1.0 - name: Update uv_build version id: update_script run: uv run scripts/update_uv_build_version.py - # If there are no changes, no pull request will be created and the action exits silently. name: Create Pull Request - uses: peter-evans/create-pull-request@v7 + uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 with: token: ${{ secrets.GITHUB_TOKEN }} commit-message: Update uv_build version to ${{ steps.update_script.outputs.version }} diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index d99b6473c..6c8c62f7d 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -19,12 +19,12 @@ jobs: actions: read steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - name: Install the latest version of uv - uses: astral-sh/setup-uv@v5 + uses: astral-sh/setup-uv@3259c6206f993105e3a61b142c2d97bf4b9ef83d # v7.1.0 - name: Run zizmor 🌈 run: uvx zizmor --format sarif source/guides/github-actions-ci-cd-sample/* > results.sarif @@ -32,7 +32,7 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Upload SARIF file - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v4.30.8 with: sarif_file: results.sarif category: zizmor From e5a97fb662b96ebc3baccbc6765e2afc6a3c5b73 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Thu, 16 Oct 2025 21:38:27 -0400 Subject: [PATCH 44/74] chore(ci): fix some template injections too Signed-off-by: William Woodruff --- .github/workflows/test-translations.yml | 8 ++++++-- .github/workflows/translation.yml | 7 ++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-translations.yml b/.github/workflows/test-translations.yml index ca6cb08f0..537a8df72 100644 --- a/.github/workflows/test-translations.yml +++ b/.github/workflows/test-translations.yml @@ -72,7 +72,9 @@ jobs: uses: sphinx-doc/github-problem-matcher@1f74d6599f4a5e89a20d3c99aab4e6a70f7bda0f # v1.1 - name: Build translated docs in ${{ matrix.language }} - run: nox -s build -- -q -D language=${{ matrix.language }} + run: nox -s build -- -q -D language=${LANGUAGE} + env: + LANGUAGE: ${{ matrix.language }} - name: Set Sphinx Lint problem matcher if: always() @@ -80,4 +82,6 @@ jobs: - name: Lint translation file if: always() - run: sphinx-lint locales/${{ matrix.language }}/LC_MESSAGES/messages.po + run: sphinx-lint locales/${LANGUAGE}/LC_MESSAGES/messages.po + env: + LANGUAGE: ${{ matrix.language }} diff --git a/.github/workflows/translation.yml b/.github/workflows/translation.yml index 1a3f71487..67fcb5edf 100644 --- a/.github/workflows/translation.yml +++ b/.github/workflows/translation.yml @@ -17,6 +17,9 @@ jobs: runs-on: ubuntu-latest if: github.repository_owner == 'pypa' + permissions: + contents: write # to push to I18N_BRANCH + steps: - name: Grab the repo src uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 @@ -49,7 +52,9 @@ jobs: run: | sh -x - git merge '${{ github.event.repository.default_branch }}' + git merge "${DEFAULT_BRANCH}" + env: + DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} - name: Set up Python uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 From 1700f858e4066beda60c1fab2650013b9a789af9 Mon Sep 17 00:00:00 2001 From: Stephen Rosen Date: Sat, 27 Sep 2025 00:21:18 -0500 Subject: [PATCH 45/74] Convert 'Dependency Groups' to lowercase Outside of titles and other contexts, convert this term to lowercase. This usage better matches other terms defined in the packaging specifications, such as "script metadata" and "dependency specifiers". For reference, this change was inspired by: https://github.com/pypa/packaging.python.org/pull/1847#discussion_r2266571023 --- source/specifications/dependency-groups.rst | 26 ++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/source/specifications/dependency-groups.rst b/source/specifications/dependency-groups.rst index 22e4cba0d..a35afb475 100644 --- a/source/specifications/dependency-groups.rst +++ b/source/specifications/dependency-groups.rst @@ -4,15 +4,15 @@ Dependency Groups ================= -This specification defines Dependency Groups, a mechanism for storing package +This specification defines dependency groups, a mechanism for storing package requirements in ``pyproject.toml`` files such that they are not included in project metadata when it is built. -Dependency Groups are suitable for internal development use-cases like linting +Dependency groups are suitable for internal development use-cases like linting and testing, as well as for projects which are not built for distribution, like collections of related scripts. -Fundamentally, Dependency Groups should be thought of as being a standardized +Fundamentally, dependency groups should be thought of as being a standardized subset of the capabilities of ``requirements.txt`` files (which are ``pip``-specific). @@ -38,7 +38,7 @@ and a similar table which defines ``docs``, ``test``, and ``coverage`` groups:: The ``[dependency-groups]`` Table --------------------------------- -Dependency Groups are defined as a table in ``pyproject.toml`` named +Dependency groups are defined as a table in ``pyproject.toml`` named ``dependency-groups``. The ``dependency-groups`` table contains an arbitrary number of user-defined keys, each of which has, as its value, a list of requirements. @@ -103,9 +103,9 @@ Package Building Build backends MUST NOT include Dependency Group data in built distributions as package metadata. This means that sdist ``PKG-INFO`` and wheel ``METADATA`` -files should not include referenceable fields containing Dependency Groups. +files should not include referenceable fields containing dependency groups. -It is, however, valid to use Dependency Groups in the evaluation of dynamic +It is, however, valid to use dependency groups in the evaluation of dynamic metadata, and ``pyproject.toml`` files included in sdists will still contain ``[dependency-groups]``. However, the table's contents are not part of a built package's interfaces. @@ -114,28 +114,28 @@ Installing Dependency Groups & Extras ------------------------------------- There is no syntax or specification-defined interface for installing or -referring to Dependency Groups. Tools are expected to provide dedicated +referring to dependency groups. Tools are expected to provide dedicated interfaces for this purpose. Tools MAY choose to provide the same or similar interfaces for interacting -with Dependency Groups as they do for managing extras. Tools authors are +with dependency groups as they do for managing extras. Tools authors are advised that the specification does not forbid having an extra whose name matches a Dependency Group. Separately, users are advised to avoid creating -Dependency Groups whose names match extras, and tools MAY treat such matching +dependency groups whose names match extras, and tools MAY treat such matching as an error. Validation and Compatibility ---------------------------- -Tools supporting Dependency Groups may want to validate data before using it. +Tools supporting dependency groups may want to validate data before using it. When implementing such validation, authors should be aware of the possibility of future extensions to the specification, so that they do not unnecessarily emit errors or warnings. Tools SHOULD error when evaluating or processing unrecognized data in -Dependency Groups. +dependency groups. -Tools SHOULD NOT eagerly validate the contents of *all* Dependency Groups +Tools SHOULD NOT eagerly validate the contents of *all* dependency groups unless they have a need to do so. This means that in the presence of the following data, most tools should allow @@ -151,7 +151,7 @@ the ``foo`` group to be used and only error if the ``bar`` group is used: There are several known cases of tools which have good cause to be stricter. Linters and validators are an example, as their purpose is to - validate the contents of all Dependency Groups. + validate the contents of all dependency groups. Reference Implementation ======================== From c6f6be53438286173bb3d2417103a2b91bce4f2f Mon Sep 17 00:00:00 2001 From: woodruffw <3059210+woodruffw@users.noreply.github.com> Date: Tue, 21 Oct 2025 17:54:46 +0000 Subject: [PATCH 46/74] Update uv_build version to 0.9.5 --- source/shared/build-backend-tabs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/shared/build-backend-tabs.rst b/source/shared/build-backend-tabs.rst index c753563dc..b80d92b39 100644 --- a/source/shared/build-backend-tabs.rst +++ b/source/shared/build-backend-tabs.rst @@ -38,5 +38,5 @@ .. code-block:: toml [build-system] - requires = ["uv_build >= 0.9.2, <0.10.0"] + requires = ["uv_build >= 0.9.5, <0.10.0"] build-backend = "uv_build" From 1b5fa563617a71b1ab9b49f959004ee1fe3bcad6 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Mon, 27 Oct 2025 14:55:37 -0700 Subject: [PATCH 47/74] Update import name guidelines to use 'SHOULD' for intermediate names --- source/specifications/core-metadata.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/specifications/core-metadata.rst b/source/specifications/core-metadata.rst index 06562e18d..a43d92ff6 100644 --- a/source/specifications/core-metadata.rst +++ b/source/specifications/core-metadata.rst @@ -745,7 +745,7 @@ the project. Projects SHOULD list all the shortest import names that are exclusively provided by the project. If any of the shortest names are dotted names, all intervening -names from that name to the top-level name should also be listed appropriately +names from that name to the top-level name SHOULD also be listed appropriately in ``Import-Name`` and/or ``Import-Namespace``. If a project lists the same name in both ``Import-Name`` and @@ -800,7 +800,7 @@ project. Projects SHOULD list all the shortest import names that are exclusively provided by the project. If any of the shortest names are dotted names, all intervening -names from that name to the top-level name should also be listed appropriately +names from that name to the top-level name SHOULD also be listed appropriately in ``Import-Name`` and/or ``Import-Namespace``. The import names listed in this field MUST be importable when the project is From 4be49e6632a5987ab438d605ede1bd37c04e994c Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Tue, 28 Oct 2025 10:14:08 -0400 Subject: [PATCH 48/74] fix: links to pip's pyproject.toml pages are dead with 25.3 Signed-off-by: Henry Schreiner --- source/guides/modernize-setup-py-project.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/guides/modernize-setup-py-project.rst b/source/guides/modernize-setup-py-project.rst index 5b6ab3c26..1f71d1973 100644 --- a/source/guides/modernize-setup-py-project.rst +++ b/source/guides/modernize-setup-py-project.rst @@ -67,7 +67,7 @@ For more details: * :ref:`distributing-packages` * :ref:`pyproject-build-system-table` -* :doc:`pip:reference/build-system/pyproject-toml` +* :doc:`pip:reference/build-system` How to handle additional build-time dependencies? @@ -128,7 +128,7 @@ For some projects this isolation is unwanted and it can be deactivated as follow For more details: -* :doc:`pip:reference/build-system/pyproject-toml` +* :doc:`pip:reference/build-system` How to handle packaging metadata? @@ -244,5 +244,5 @@ Where to read more about this? ============================== * :ref:`pyproject-toml-spec` -* :doc:`pip:reference/build-system/pyproject-toml` +* :doc:`pip:reference/build-system` * :doc:`setuptools:build_meta` From 4e8a3d24f166250ce1e9249d39f644526542633c Mon Sep 17 00:00:00 2001 From: Ben Tucker Date: Fri, 7 Nov 2025 16:54:35 +0000 Subject: [PATCH 49/74] docs: update spec for the macOS platform tag --- source/specifications/platform-compatibility-tags.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/source/specifications/platform-compatibility-tags.rst b/source/specifications/platform-compatibility-tags.rst index 0502c8c03..fcb317cfe 100644 --- a/source/specifications/platform-compatibility-tags.rst +++ b/source/specifications/platform-compatibility-tags.rst @@ -199,10 +199,11 @@ artefact of Apple's official macOS naming scheme). The schema for compatibility tags is :file:`macosx_{x}_{y}_{arch}`, indicating that the wheel is compatible with macOS ``x.y`` or later on the architecture ``arch``. -The values of ``x`` and ``y`` correspond to the major and minor version number of -the macOS release, respectively. They must both be positive integers, with the -``x`` value being ``>= 10``. The version number always includes a major *and* -minor version, even if Apple's official version numbering only refers to +The values of ``x`` and ``y`` correspond to the major and minor version number +of the macOS release, respectively. They must both be positive integers, with +the ``x`` value being either ``10 <= x <= 15``, or ``>=26`` and corresponding +to the year of the macOS release. The version number always includes a major +*and* minor version, even if Apple's official version numbering only refers to the major value. For example, ``macosx_11_0_arm64`` indicates compatibility with macOS 11 or later. From ac13541a8e340996da605841e0ca278eb5bc2eb9 Mon Sep 17 00:00:00 2001 From: Pradyun Gedam Date: Sun, 9 Nov 2025 02:51:38 +0000 Subject: [PATCH 50/74] Allow errors for missing `[build-system]` table with no metadata Permit installers to present an error if the working directory does not seem like a location that the user intended to install from. --- source/specifications/pyproject-toml.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/specifications/pyproject-toml.rst b/source/specifications/pyproject-toml.rst index 74dbe34e3..48f35599e 100644 --- a/source/specifications/pyproject-toml.rst +++ b/source/specifications/pyproject-toml.rst @@ -61,6 +61,10 @@ table then the default values as specified above should be used. If the table is specified but is missing required fields then the tool should consider it an error. +Tools may choose to present an error to the user if the file exists, +``[build-system]`` table is missing, and there is no clear indication +that the project should be built (e.g., no setup.py/setup.cfg or other +build configuration files, and no ``[project]`` table). To provide a type-specific representation of the resulting data from the TOML file for illustrative purposes only, the following From 82f35b5a2abcf1989574e9363cd2c3a5a6c1835f Mon Sep 17 00:00:00 2001 From: Pradyun Gedam Date: Sun, 9 Nov 2025 02:57:19 +0000 Subject: [PATCH 51/74] Drop warehouse's intersphinx entry Warehouse is not referenced from these docs and their docs have moved to mkdocs-material. --- source/conf.py | 1 - 1 file changed, 1 deletion(-) diff --git a/source/conf.py b/source/conf.py index 95f6f3421..030a167e4 100644 --- a/source/conf.py +++ b/source/conf.py @@ -210,7 +210,6 @@ "tox": ("https://tox.wiki/en/latest/", None), "twine": ("https://twine.readthedocs.io/en/stable/", None), "virtualenv": ("https://virtualenv.pypa.io/en/stable/", None), - "warehouse": ("https://warehouse.pypa.io/", None), } # -- Options for todo extension -------------------------------------------------------- From 44af965c54008fe7bdd16ce7522e1b5398041c9c Mon Sep 17 00:00:00 2001 From: github-merge-queue <118344674+github-merge-queue@users.noreply.github.com> Date: Mon, 10 Nov 2025 06:11:10 +0000 Subject: [PATCH 52/74] Update uv_build version to 0.9.8 --- source/shared/build-backend-tabs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/shared/build-backend-tabs.rst b/source/shared/build-backend-tabs.rst index b80d92b39..621eb4177 100644 --- a/source/shared/build-backend-tabs.rst +++ b/source/shared/build-backend-tabs.rst @@ -38,5 +38,5 @@ .. code-block:: toml [build-system] - requires = ["uv_build >= 0.9.5, <0.10.0"] + requires = ["uv_build >= 0.9.8, <0.10.0"] build-backend = "uv_build" From dc58ce94e84fa8e0b99ed5031d9b723951f3e9f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filipe=20La=C3=ADns?= Date: Wed, 12 Nov 2025 13:45:06 +0000 Subject: [PATCH 53/74] nox: allow passing arguments to linkcheck MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Filipe Laíns --- noxfile.py | 1 + 1 file changed, 1 insertion(+) diff --git a/noxfile.py b/noxfile.py index 698e82f9d..484a8d39a 100644 --- a/noxfile.py +++ b/noxfile.py @@ -89,6 +89,7 @@ def linkcheck(session): "--keep-going", # be strict "source", # where the rst files are located "build", # where to put the check output + *session.posargs, ) From 7a8eb853713eea644af3d5885d88c2d0e3c7390f Mon Sep 17 00:00:00 2001 From: github-merge-queue <118344674+github-merge-queue@users.noreply.github.com> Date: Mon, 17 Nov 2025 06:11:01 +0000 Subject: [PATCH 54/74] Update uv_build version to 0.9.9 --- source/shared/build-backend-tabs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/shared/build-backend-tabs.rst b/source/shared/build-backend-tabs.rst index 621eb4177..23918e388 100644 --- a/source/shared/build-backend-tabs.rst +++ b/source/shared/build-backend-tabs.rst @@ -38,5 +38,5 @@ .. code-block:: toml [build-system] - requires = ["uv_build >= 0.9.8, <0.10.0"] + requires = ["uv_build >= 0.9.9, <0.10.0"] build-backend = "uv_build" From 761f6bdc1ebfd6885488dab57b8f4f4b9ae0ceb7 Mon Sep 17 00:00:00 2001 From: konstin Date: Fri, 21 Nov 2025 11:21:51 +0100 Subject: [PATCH 55/74] Document `macosx_0_{y}_{arch}` pattern Following https://discuss.python.org/t/document-that-macos-platform-tags-use-minor-version-0-for-macos-11/104616: * Document that for macOS 11 and later, the platform tag is `macosx_0_{y}_{arch}` * Document that platform tags may change over time. --- .../platform-compatibility-tags.rst | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/source/specifications/platform-compatibility-tags.rst b/source/specifications/platform-compatibility-tags.rst index fcb317cfe..b4c14a4c0 100644 --- a/source/specifications/platform-compatibility-tags.rst +++ b/source/specifications/platform-compatibility-tags.rst @@ -82,6 +82,11 @@ decide how to best use the ABI tag. Platform Tag ============ +.. important:: + Platform tags are dependent on the versioning of the operating system or + platform they represent and may change over time as the underlying platform + changes its versioning. + Basic platform tags ------------------- @@ -199,13 +204,13 @@ artefact of Apple's official macOS naming scheme). The schema for compatibility tags is :file:`macosx_{x}_{y}_{arch}`, indicating that the wheel is compatible with macOS ``x.y`` or later on the architecture ``arch``. -The values of ``x`` and ``y`` correspond to the major and minor version number -of the macOS release, respectively. They must both be positive integers, with -the ``x`` value being either ``10 <= x <= 15``, or ``>=26`` and corresponding -to the year of the macOS release. The version number always includes a major -*and* minor version, even if Apple's official version numbering only refers to -the major value. For example, ``macosx_11_0_arm64`` indicates compatibility -with macOS 11 or later. +For macOS 10, the tag is :file:`macosx_10_{y}_{arch}`, where ``y`` corresponds +to the minor version number of the macOS release. For macOS 11 and higher, the +tag is :file:`macosx_{x}_0_{arch}`, where ``x`` corresponds to the major +version number of the macOS release. Following the published macOS major +versions, the ``x`` value is either ``10 <= x <= 15``, or ``>=26`` and +corresponding to the year of the macOS release. For example, +``macosx_11_0_arm64`` indicates compatibility with macOS 11 or later. macOS binaries can be compiled for a single architecture, or can include support for multiple architectures in the same binary (sometimes called "fat" binaries). From 7a7d7ba624c842b224ed904cd0c7bae1dfda3f56 Mon Sep 17 00:00:00 2001 From: Damian Shaw Date: Sat, 22 Nov 2025 12:31:58 -0500 Subject: [PATCH 56/74] Specify arbitrary equality case insensitivity. --- source/specifications/version-specifiers.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/specifications/version-specifiers.rst b/source/specifications/version-specifiers.rst index c0b544160..f620c9054 100644 --- a/source/specifications/version-specifiers.rst +++ b/source/specifications/version-specifiers.rst @@ -1016,8 +1016,9 @@ Arbitrary equality Arbitrary equality comparisons are simple string equality operations which do not take into account any of the semantic information such as zero padding or -local versions. This operator also does not support prefix matching as the -``==`` operator does. +local versions. The comparison MUST treat ASCII letters case-insensitively, e.g. +by lowercasing, and is unspecified for non-ASCII text. This operator also does +not support prefix matching as the ``==`` operator does. The primary use case for arbitrary equality is to allow for specifying a version which cannot otherwise be represented by this specification. This operator is @@ -1271,3 +1272,4 @@ History - August 2014: This specification was approved through :pep:`440`. - May 2025: Clarify that development releases are a form of pre-release when they are handled. +- Nov 2025: Specify arbitrary equality case insensitivity. From 5e9c85eefa28bb369c1187e61504a8c78d55a054 Mon Sep 17 00:00:00 2001 From: Stefaan Lippens Date: Sun, 23 Nov 2025 21:42:54 +0100 Subject: [PATCH 57/74] Rename publish-to-test-pypi.yml to publish-to-pypi.yml #1935 --- ...lish-to-test-pypi.yml => publish-to-pypi.yml} | 0 ...ases-using-github-actions-ci-cd-workflows.rst | 16 ++++++++-------- 2 files changed, 8 insertions(+), 8 deletions(-) rename source/guides/github-actions-ci-cd-sample/{publish-to-test-pypi.yml => publish-to-pypi.yml} (100%) diff --git a/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml b/source/guides/github-actions-ci-cd-sample/publish-to-pypi.yml similarity index 100% rename from source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml rename to source/guides/github-actions-ci-cd-sample/publish-to-pypi.yml diff --git a/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst b/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst index e9f601e03..a3d893c9f 100644 --- a/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst +++ b/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst @@ -87,13 +87,13 @@ Creating a workflow definition GitHub CI/CD workflows are declared in YAML files stored in the ``.github/workflows/`` directory of your repository. -Let's create a ``.github/workflows/publish-to-test-pypi.yml`` +Let's create a ``.github/workflows/publish-to-pypi.yml`` file. Start it with a meaningful name and define the event that should make GitHub run this workflow: -.. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml +.. literalinclude:: github-actions-ci-cd-sample/publish-to-pypi.yml :language: yaml :end-before: jobs: @@ -107,7 +107,7 @@ build the distribution packages. First, we'll define the job for building the dist packages of your project and storing them for later use: -.. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml +.. literalinclude:: github-actions-ci-cd-sample/publish-to-pypi.yml :language: yaml :start-at: jobs: :end-before: Install pypa/build @@ -119,7 +119,7 @@ And now we can build the dists from source and store them. In this example, we'll use the ``build`` package. So add this to the steps list: -.. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml +.. literalinclude:: github-actions-ci-cd-sample/publish-to-pypi.yml :language: yaml :start-at: Install pypa/build :end-before: publish-to-pypi @@ -136,7 +136,7 @@ UI nicely. Additionally, it allows acquiring an OpenID Connect token that the ``pypi-publish`` actions needs to implement secretless Trusted Publishing to PyPI. -.. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml +.. literalinclude:: github-actions-ci-cd-sample/publish-to-pypi.yml :language: yaml :start-after: path: dist/ :end-before: steps: @@ -149,7 +149,7 @@ Publishing the distribution to PyPI Finally, add the following steps at the end: -.. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml +.. literalinclude:: github-actions-ci-cd-sample/publish-to-pypi.yml :language: yaml :start-after: id-token: write :end-before: publish-to-testpypi: @@ -175,7 +175,7 @@ Now, repeat these steps and create another job for publishing to the TestPyPI package index under the ``jobs`` section: -.. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml +.. literalinclude:: github-actions-ci-cd-sample/publish-to-pypi.yml :language: yaml :start-at: publish-to-testpypi @@ -191,7 +191,7 @@ This paragraph showcases the whole workflow after following the above guide. .. collapse:: Click here to display the entire GitHub Actions CI/CD workflow definition - .. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml + .. literalinclude:: github-actions-ci-cd-sample/publish-to-pypi.yml :language: yaml That's all, folks! From 43060740c4109e24f8dd6902b731d9d288fc5c21 Mon Sep 17 00:00:00 2001 From: github-merge-queue <118344674+github-merge-queue@users.noreply.github.com> Date: Mon, 24 Nov 2025 06:10:56 +0000 Subject: [PATCH 58/74] Update uv_build version to 0.9.11 --- source/shared/build-backend-tabs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/shared/build-backend-tabs.rst b/source/shared/build-backend-tabs.rst index 23918e388..c732ed2e9 100644 --- a/source/shared/build-backend-tabs.rst +++ b/source/shared/build-backend-tabs.rst @@ -38,5 +38,5 @@ .. code-block:: toml [build-system] - requires = ["uv_build >= 0.9.9, <0.10.0"] + requires = ["uv_build >= 0.9.11, <0.10.0"] build-backend = "uv_build" From 97a72c521adb07961e4766039a30bc3e0159ac09 Mon Sep 17 00:00:00 2001 From: Damian Shaw Date: Tue, 25 Nov 2025 14:37:04 -0500 Subject: [PATCH 59/74] Update source/specifications/version-specifiers.rst Co-authored-by: Alyssa Coghlan --- source/specifications/version-specifiers.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/specifications/version-specifiers.rst b/source/specifications/version-specifiers.rst index f620c9054..13015794f 100644 --- a/source/specifications/version-specifiers.rst +++ b/source/specifications/version-specifiers.rst @@ -1272,4 +1272,4 @@ History - August 2014: This specification was approved through :pep:`440`. - May 2025: Clarify that development releases are a form of pre-release when they are handled. -- Nov 2025: Specify arbitrary equality case insensitivity. +- Nov 2025: Make arbitrary equality case insensitivity explicit. From 22d9ddf8899b615ee51fe46f0cd9dff8c108bcbf Mon Sep 17 00:00:00 2001 From: Benjamin Rodenberg Date: Thu, 6 Nov 2025 13:18:09 +0100 Subject: [PATCH 60/74] Fix typo in creating-command-line-tools.rst --- source/guides/creating-command-line-tools.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/guides/creating-command-line-tools.rst b/source/guides/creating-command-line-tools.rst index 72e3e37ef..cbe8b3bb0 100644 --- a/source/guides/creating-command-line-tools.rst +++ b/source/guides/creating-command-line-tools.rst @@ -154,7 +154,7 @@ To just run the program without installing it permanently, use ``pipx run``, whi $ pipx run --spec . greet --doctor This syntax is a bit impractical, however; as the name of the entry point we defined above does not match the package name, -we need to state explicitly which executable script to run (even though there is only on in existence). +we need to state explicitly which executable script to run (even though there is only one in existence). There is, however, a more practical solution to this problem, in the form of an entry point specific to ``pipx run``. The same can be defined as follows in :file:`pyproject.toml`: From 870e6fe9799b8885d547dc88cc2c2b62057f3eb0 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Mon, 27 Jan 2025 16:57:03 -0800 Subject: [PATCH 61/74] Fix the use of underscores when a hyphen is more accurate --- source/specifications/core-metadata.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/specifications/core-metadata.rst b/source/specifications/core-metadata.rst index a43d92ff6..eb9a03ff6 100644 --- a/source/specifications/core-metadata.rst +++ b/source/specifications/core-metadata.rst @@ -52,9 +52,9 @@ Metadata-Version Version of the file format; legal values are "1.0", "1.1", "1.2", "2.1", "2.2", "2.3", "2.4", and "2.5". -Automated tools consuming metadata SHOULD warn if ``metadata_version`` is +Automated tools consuming metadata SHOULD warn if ``metadata-version`` is greater than the highest version they support, and MUST fail if -``metadata_version`` has a greater major version than the highest +``metadata-version`` has a greater major version than the highest version they support (as described in the :ref:`Version specifier specification `, the major version is the value before the first dot). From 2ee73e02c90f7d7429e0e80120380aee759ce12e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filipe=20La=C3=ADns?= Date: Wed, 12 Nov 2025 13:37:02 +0000 Subject: [PATCH 62/74] Restore linkcheck for specs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Filipe Laíns --- pug_sphinx_extensions/__init__.py | 76 +++++++++++++++++++++++++++++++ source/conf.py | 10 ++-- 2 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 pug_sphinx_extensions/__init__.py diff --git a/pug_sphinx_extensions/__init__.py b/pug_sphinx_extensions/__init__.py new file mode 100644 index 000000000..ae495bb60 --- /dev/null +++ b/pug_sphinx_extensions/__init__.py @@ -0,0 +1,76 @@ +import os +import urllib + +import sphinx.application +import sphinx.util.logging + + +DOMAIN = 'packaging.python.org' + + +logger = sphinx.util.logging.getLogger(__name__) + + +def resolve_local_html_link(app: sphinx.application.Sphinx, url_path: str) -> str: + """Takes path of a link pointing an HTML render of the current project, + and returns local path of the referenced document. + + Support links to renders from both the `html` and `dirhtml` builders. + + Example: + + .. code-block:: python + + >>> resolve_local_html_link('https://packaging.python.org/en/latest/flow/') + '{srcdir}/flow.rst' + >>> resolve_local_html_link('https://packaging.python.org/en/latest/flow.html') + '{srcdir}/flow.rst' + >>> resolve_local_html_link('https://packaging.python.org/en/latest/specifications/schemas/') + '{srcdir}/specifications/schemas/index.rst' + >>> resolve_local_html_link('https://packaging.python.org/en/latest/specifications/schemas/build-details-v1.0.schema.json') + '{html_extra_path0}/specifications/schemas/build-details-v1.0.schema.json' + + """ + # Search for document in html_extra_path + for entry in app.config.html_extra_path: + candidate = (app.confdir / entry / url_path).resolve() + if candidate.is_dir(): + candidate = candidate / 'index.html' + if candidate.exists(): + return os.fspath(candidate) + # Convert html path to source path + url_path = url_path.removesuffix('/') # Normalize + if url_path.endswith('.html'): + document = url_path.removesuffix('.html') + elif (candidate := f'{url_path}/index') in app.project.docnames: + document = candidate + else: + document = url_path + return app.env.doc2path(document) + + +def rewrite_local_uri(app: sphinx.application.Sphinx, uri: str) -> str: + """Replace remote URIs targeting https://packaging.python.org/en/latest/... + with local ones, so that local changes are taken into account by linkcheck. + """ + local_uri = uri + parsed = urllib.parse.urlparse(uri) + if parsed.hostname == DOMAIN and parsed.path.startswith('/en/latest/'): + document = parsed.path.removeprefix('/en/latest/') + local_uri = resolve_local_html_link(app, document) + logger.verbose( + f'{uri!s} is a remote URL that points to local sources, ' + 'replacing it with a local URL in linkcheck to take new changes ' + 'into account (pass -vv for more info)' + ) + logger.debug(f'Replacing linkcheck URL {uri!r} with {local_uri!r}') + return local_uri + + +def setup(app: sphinx.application.Sphinx) -> dict[str, bool]: + app.connect('linkcheck-process-uri', rewrite_local_uri) + + return { + 'parallel_read_safe': True, + 'parallel_write_safe': True, + } diff --git a/source/conf.py b/source/conf.py index d18faf662..ccb828b6e 100644 --- a/source/conf.py +++ b/source/conf.py @@ -2,6 +2,11 @@ # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information import os +import pathlib +import sys + +_ROOT = pathlib.Path(__file__).resolve().parent.parent +sys.path.append(os.fspath(_ROOT)) # Some options are only enabled for the main packaging.python.org deployment builds RTD_BUILD = bool(os.getenv("READTHEDOCS")) @@ -22,6 +27,7 @@ root_doc = "index" extensions = [ + "pug_sphinx_extensions", "sphinx.ext.extlinks", "sphinx.ext.intersphinx", "sphinx.ext.todo", @@ -133,7 +139,6 @@ linkcheck_ignore = [ r"http://localhost:\d+", - r"https://packaging\.python\.org/en/latest/specifications/schemas/.*", r"https://test\.pypi\.org/project/example-package-YOUR-USERNAME-HERE", r"https://pypi\.org/manage/.*", r"https://test\.pypi\.org/manage/.*", @@ -162,9 +167,6 @@ # https://github.com/pypa/packaging.python.org/issues/1744 r"https://pypi\.org/", ] -linkcheck_exclude_documents = [ - "specifications/schemas/index", -] # -- Options for extlinks ---------------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/extensions/extlinks.html#configuration From 0cef54ccf1a3cf5dc4302e66e57740f2ea046cd3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 12 Nov 2025 14:23:22 +0000 Subject: [PATCH 63/74] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pug_sphinx_extensions/__init__.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/pug_sphinx_extensions/__init__.py b/pug_sphinx_extensions/__init__.py index ae495bb60..82abe6997 100644 --- a/pug_sphinx_extensions/__init__.py +++ b/pug_sphinx_extensions/__init__.py @@ -5,7 +5,7 @@ import sphinx.util.logging -DOMAIN = 'packaging.python.org' +DOMAIN = "packaging.python.org" logger = sphinx.util.logging.getLogger(__name__) @@ -35,14 +35,14 @@ def resolve_local_html_link(app: sphinx.application.Sphinx, url_path: str) -> st for entry in app.config.html_extra_path: candidate = (app.confdir / entry / url_path).resolve() if candidate.is_dir(): - candidate = candidate / 'index.html' + candidate = candidate / "index.html" if candidate.exists(): return os.fspath(candidate) # Convert html path to source path - url_path = url_path.removesuffix('/') # Normalize - if url_path.endswith('.html'): - document = url_path.removesuffix('.html') - elif (candidate := f'{url_path}/index') in app.project.docnames: + url_path = url_path.removesuffix("/") # Normalize + if url_path.endswith(".html"): + document = url_path.removesuffix(".html") + elif (candidate := f"{url_path}/index") in app.project.docnames: document = candidate else: document = url_path @@ -55,22 +55,22 @@ def rewrite_local_uri(app: sphinx.application.Sphinx, uri: str) -> str: """ local_uri = uri parsed = urllib.parse.urlparse(uri) - if parsed.hostname == DOMAIN and parsed.path.startswith('/en/latest/'): - document = parsed.path.removeprefix('/en/latest/') + if parsed.hostname == DOMAIN and parsed.path.startswith("/en/latest/"): + document = parsed.path.removeprefix("/en/latest/") local_uri = resolve_local_html_link(app, document) logger.verbose( - f'{uri!s} is a remote URL that points to local sources, ' - 'replacing it with a local URL in linkcheck to take new changes ' - 'into account (pass -vv for more info)' + f"{uri!s} is a remote URL that points to local sources, " + "replacing it with a local URL in linkcheck to take new changes " + "into account (pass -vv for more info)" ) - logger.debug(f'Replacing linkcheck URL {uri!r} with {local_uri!r}') + logger.debug(f"Replacing linkcheck URL {uri!r} with {local_uri!r}") return local_uri def setup(app: sphinx.application.Sphinx) -> dict[str, bool]: - app.connect('linkcheck-process-uri', rewrite_local_uri) + app.connect("linkcheck-process-uri", rewrite_local_uri) return { - 'parallel_read_safe': True, - 'parallel_write_safe': True, + "parallel_read_safe": True, + "parallel_write_safe": True, } From c2fe979382110513c6515c4f7c14d6f922f76846 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filipe=20La=C3=ADns?= Date: Fri, 14 Nov 2025 22:41:54 +0000 Subject: [PATCH 64/74] Resolve local relative links to html_extra_path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Filipe Laíns --- pug_sphinx_extensions/__init__.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pug_sphinx_extensions/__init__.py b/pug_sphinx_extensions/__init__.py index 82abe6997..00d91da3c 100644 --- a/pug_sphinx_extensions/__init__.py +++ b/pug_sphinx_extensions/__init__.py @@ -1,4 +1,5 @@ import os +import pathlib import urllib import sphinx.application @@ -52,9 +53,12 @@ def resolve_local_html_link(app: sphinx.application.Sphinx, url_path: str) -> st def rewrite_local_uri(app: sphinx.application.Sphinx, uri: str) -> str: """Replace remote URIs targeting https://packaging.python.org/en/latest/... with local ones, so that local changes are taken into account by linkcheck. + + Additionally, resolve local relative links to html_extra_path. """ local_uri = uri parsed = urllib.parse.urlparse(uri) + # Links to https://packaging.python.org/en/latest/... if parsed.hostname == DOMAIN and parsed.path.startswith("/en/latest/"): document = parsed.path.removeprefix("/en/latest/") local_uri = resolve_local_html_link(app, document) @@ -64,6 +68,12 @@ def rewrite_local_uri(app: sphinx.application.Sphinx, uri: str) -> str: "into account (pass -vv for more info)" ) logger.debug(f"Replacing linkcheck URL {uri!r} with {local_uri!r}") + # Local relative links + if not parsed.scheme and not parsed.netloc and parsed.path: + full_path = pathlib.Path(app.env.docname).parent / parsed.path + local_uri = resolve_local_html_link(app, os.fspath(full_path)) + if local_uri != uri: + logger.verbose(f"Local linkcheck URL {uri!r} resolved as {local_uri!r}") return local_uri From 5a56b2e46ef12ff3fed57b78c79622d357c90a9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filipe=20La=C3=ADns?= Date: Wed, 19 Nov 2025 12:51:42 +0000 Subject: [PATCH 65/74] Add myself to the pug_sphinx_extensions codeowners MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Filipe Laíns --- .github/CODEOWNERS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index ecd85064f..0b7c7b289 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,6 +1,9 @@ source/guides/github-actions-ci-cd-sample/* @webknjaz source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst @webknjaz +# Sphinx extension +pug_sphinx_extensions/ @FFY00 + # build-details.json source/specifications/build-details/ @FFY00 source/specifications/specs/build-details-*.json @FFY00 From 9daa2ef1184a805e6634ab16f8bd6560cd1c5d2a Mon Sep 17 00:00:00 2001 From: Damian Shaw Date: Mon, 1 Dec 2025 20:30:45 -0500 Subject: [PATCH 66/74] Fix grammar for arbitrary equality comparisons in version specifiers --- source/specifications/dependency-specifiers.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/specifications/dependency-specifiers.rst b/source/specifications/dependency-specifiers.rst index d9466c26e..99886563c 100644 --- a/source/specifications/dependency-specifiers.rst +++ b/source/specifications/dependency-specifiers.rst @@ -63,7 +63,7 @@ Versions may be specified according to the rules of the :ref:`Version specifier specification `. (Note: URI is defined in :rfc:`std-66 <3986>`):: - version_cmp = wsp* '<' | '<=' | '!=' | '==' | '>=' | '>' | '~=' | '===' + version_cmp = wsp* '<=' | '<' | '!=' | '===' | '==' | '>=' | '>' | '~=' version = wsp* ( letterOrDigit | '-' | '_' | '.' | '*' | '+' | '!' )+ version_one = version_cmp version wsp* version_many = version_one (',' version_one)* (',' wsp*)? @@ -339,7 +339,7 @@ Complete Grammar The complete parsley grammar:: wsp = ' ' | '\t' - version_cmp = wsp* <'<=' | '<' | '!=' | '==' | '>=' | '>' | '~=' | '==='> + version_cmp = wsp* <'<=' | '<' | '!=' | '===' | '==' | '>=' | '>' | '~='> version = wsp* <( letterOrDigit | '-' | '_' | '.' | '*' | '+' | '!' )+> version_one = version_cmp:op version:v wsp* -> (op, v) version_many = version_one:v1 (',' version_one)*:v2 (',' wsp*)? -> [v1] + v2 @@ -529,6 +529,8 @@ History - August 2025: The suggested name validation regex was fixed to match the field specification (it previously finished with ``$`` instead of ``\Z``, incorrectly permitting trailing newlines) +- December 2025: Ensure ``===`` before ``==`` in grammar, to allow arbitrary + equality comparisons to be parsed. References From d255619f85b966d6fa7e77855a706638d51bf17a Mon Sep 17 00:00:00 2001 From: Gene Wood Date: Tue, 2 Dec 2025 13:23:06 -0800 Subject: [PATCH 67/74] Update versions of GitHub actions used This updates the versions of the GitHub actions used to the current major releases. --- .../github-actions-ci-cd-sample/publish-to-pypi.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/guides/github-actions-ci-cd-sample/publish-to-pypi.yml b/source/guides/github-actions-ci-cd-sample/publish-to-pypi.yml index 8813a0392..155f82555 100644 --- a/source/guides/github-actions-ci-cd-sample/publish-to-pypi.yml +++ b/source/guides/github-actions-ci-cd-sample/publish-to-pypi.yml @@ -8,11 +8,11 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: persist-credentials: false - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: "3.x" - name: Install pypa/build @@ -24,7 +24,7 @@ jobs: - name: Build a binary wheel and a source tarball run: python3 -m build - name: Store the distribution packages - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: python-package-distributions path: dist/ @@ -44,7 +44,7 @@ jobs: steps: - name: Download all the dists - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v6 with: name: python-package-distributions path: dist/ @@ -66,7 +66,7 @@ jobs: steps: - name: Download all the dists - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v6 with: name: python-package-distributions path: dist/ From ad086b91742c9cc22e6db9d490fbb35646dda524 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Thu, 11 Dec 2025 16:15:57 +0100 Subject: [PATCH 68/74] Add subheading for Build backends for extension modules --- source/guides/tool-recommendations.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/guides/tool-recommendations.rst b/source/guides/tool-recommendations.rst index 1ba36ed61..bf8d93d5a 100644 --- a/source/guides/tool-recommendations.rst +++ b/source/guides/tool-recommendations.rst @@ -109,6 +109,11 @@ Do **not** use :ref:`distutils`, which is deprecated, and has been removed from the standard library in Python 3.12, although it still remains available from setuptools. +.. _extension-module-tool-recommendations: + +Build backends for extension modules +------------------------------------ + For packages with :term:`extension modules `, it is best to use a build system with dedicated support for the language the extension is written in, for example: From 3e4b6ec014e6e722e493322b0e755c5b35facf7a Mon Sep 17 00:00:00 2001 From: github-merge-queue <118344674+github-merge-queue@users.noreply.github.com> Date: Mon, 15 Dec 2025 06:12:11 +0000 Subject: [PATCH 69/74] Update uv_build version to 0.9.17 --- source/shared/build-backend-tabs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/shared/build-backend-tabs.rst b/source/shared/build-backend-tabs.rst index c732ed2e9..f81423ca1 100644 --- a/source/shared/build-backend-tabs.rst +++ b/source/shared/build-backend-tabs.rst @@ -38,5 +38,5 @@ .. code-block:: toml [build-system] - requires = ["uv_build >= 0.9.11, <0.10.0"] + requires = ["uv_build >= 0.9.17, <0.10.0"] build-backend = "uv_build" From 0f6ac8de0005553909725085d90cca807bd50888 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Sun, 21 Dec 2025 18:37:01 -0500 Subject: [PATCH 70/74] fix: bitbucket org gone Signed-off-by: Henry Schreiner --- source/glossary.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/glossary.rst b/source/glossary.rst index 630513868..40c041f4c 100644 --- a/source/glossary.rst +++ b/source/glossary.rst @@ -287,8 +287,7 @@ Glossary PyPA is a working group that maintains many of the relevant projects in Python packaging. They maintain a site at :doc:`pypa.io `, host projects on `GitHub - `_ and `Bitbucket - `_, and discuss issues on the + `_, and discuss issues on the `distutils-sig mailing list `_ and `the Python Discourse forum `__. From ca4013df271d79c79c1424a047805f92e3d8e7ed Mon Sep 17 00:00:00 2001 From: github-merge-queue <118344674+github-merge-queue@users.noreply.github.com> Date: Mon, 22 Dec 2025 06:11:58 +0000 Subject: [PATCH 71/74] Update uv_build version to 0.9.18 --- source/shared/build-backend-tabs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/shared/build-backend-tabs.rst b/source/shared/build-backend-tabs.rst index f81423ca1..70f5733d0 100644 --- a/source/shared/build-backend-tabs.rst +++ b/source/shared/build-backend-tabs.rst @@ -38,5 +38,5 @@ .. code-block:: toml [build-system] - requires = ["uv_build >= 0.9.17, <0.10.0"] + requires = ["uv_build >= 0.9.18, <0.10.0"] build-backend = "uv_build" From 90034b530d029679155d3c7ce4ba50f8ade19aca Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Mon, 22 Dec 2025 17:33:14 -0500 Subject: [PATCH 72/74] docs: fix links to Travis Signed-off-by: Henry Schreiner --- source/guides/supporting-multiple-python-versions.rst | 2 +- source/guides/supporting-windows-using-appveyor.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/guides/supporting-multiple-python-versions.rst b/source/guides/supporting-multiple-python-versions.rst index 8c128ed91..7e945aa53 100644 --- a/source/guides/supporting-multiple-python-versions.rst +++ b/source/guides/supporting-multiple-python-versions.rst @@ -62,7 +62,7 @@ of many continuous-integration systems. There are two hosted services which when used in conjunction provide automated testing across Linux, Mac and Windows: - - `Travis CI `_ provides both a Linux and a macOS + - `Travis CI `_ provides both a Linux and a macOS environment. The Linux environment is Ubuntu 12.04 LTS Server Edition 64 bit while the macOS is 10.9.2 at the time of writing. - `Appveyor `_ provides a Windows environment diff --git a/source/guides/supporting-windows-using-appveyor.rst b/source/guides/supporting-windows-using-appveyor.rst index 0044d8c5e..e884dd976 100644 --- a/source/guides/supporting-windows-using-appveyor.rst +++ b/source/guides/supporting-windows-using-appveyor.rst @@ -237,6 +237,6 @@ For reference, the SDK setup support script is listed here: :linenos: .. _Appveyor: https://www.appveyor.com/ -.. _Travis: https://travis-ci.org/ +.. _Travis: https://travis-ci.com/ .. _GitHub: https://github.com .. _Bitbucket: https://bitbucket.org/ From b14f944a186f2b27b0a89f5a710a63cd71461bd5 Mon Sep 17 00:00:00 2001 From: github-merge-queue <118344674+github-merge-queue@users.noreply.github.com> Date: Mon, 5 Jan 2026 06:13:45 +0000 Subject: [PATCH 73/74] Update uv_build version to 0.9.21 --- source/shared/build-backend-tabs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/shared/build-backend-tabs.rst b/source/shared/build-backend-tabs.rst index 70f5733d0..64ef0bf2f 100644 --- a/source/shared/build-backend-tabs.rst +++ b/source/shared/build-backend-tabs.rst @@ -38,5 +38,5 @@ .. code-block:: toml [build-system] - requires = ["uv_build >= 0.9.18, <0.10.0"] + requires = ["uv_build >= 0.9.21, <0.10.0"] build-backend = "uv_build" From 712f24a877b533bcca4a637f6a1cf165edf4fdc1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 5 Jan 2026 18:37:47 +0000 Subject: [PATCH 74/74] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.13.3 → v0.14.10](https://github.com/astral-sh/ruff-pre-commit/compare/v0.13.3...v0.14.10) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 615970dda..47b864808 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,7 +37,7 @@ repos: - id: rst-inline-touching-normal - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.13.3 + rev: v0.14.10 hooks: - id: ruff - id: ruff-format