From 397de33ae16184bd8a23941c163d4c2d174c19ea Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Tue, 3 Jun 2025 10:42:15 -0400 Subject: [PATCH 001/187] specifications: clarify "sorted, set" to "sorted, collection" This will hopefully clarify/eliminate a contradiction in terms in the current specification text: the current text says both "sorted" and "set", where "set" conventionally implies an unordered collection. In context that *appears* to have not been the intention, since the context is the wheel filename encoding and not the internal (i.e. parsed) representation of a wheel filename's tags. Signed-off-by: William Woodruff --- source/specifications/platform-compatibility-tags.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/specifications/platform-compatibility-tags.rst b/source/specifications/platform-compatibility-tags.rst index 6feb18cda..0502c8c03 100644 --- a/source/specifications/platform-compatibility-tags.rst +++ b/source/specifications/platform-compatibility-tags.rst @@ -351,7 +351,7 @@ Compressed Tag Sets To allow for compact filenames of bdists that work with more than one compatibility tag triple, each tag in a filename can instead be a -'.'-separated, sorted, set of tags. For example, pip, a pure-Python +'.'-separated, sorted, collection of tags. For example, pip, a pure-Python package that is written to run under Python 2 and 3 with the same source code, could distribute a bdist with the tag ``py2.py3-none-any``. The full list of simple tags is:: From 2989d20d2fb0a7577267729500fc4b9e8efa9bcf Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Fri, 27 Jun 2025 15:59:11 -0700 Subject: [PATCH 002/187] Fix references in pylock-toml.rst A few had spaces after the opening backtick. --- source/specifications/pylock-toml.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/specifications/pylock-toml.rst b/source/specifications/pylock-toml.rst index d21294cf9..342e608c5 100644 --- a/source/specifications/pylock-toml.rst +++ b/source/specifications/pylock-toml.rst @@ -672,12 +672,12 @@ See :ref:`pylock-packages-archive-hashes`. - **Type**: array of tables - **Required?**: no -- **Inspiration**: :ref:` provenance-object` +- **Inspiration**: :ref:`provenance-object` - A recording of the attestations for **any** file recorded for this package. - If available, tools SHOULD include the attestation identities found. - Publisher-specific keys are to be included in the table as-is (i.e. top-level), following the spec at - :ref:` index-hosted-attestations`. + :ref:`index-hosted-attestations`. .. _pylock-packages-attestation-identities-kind: @@ -687,7 +687,7 @@ See :ref:`pylock-packages-archive-hashes`. - **Type**: string - **Required?**: yes -- **Inspiration**: :ref:` provenance-object` +- **Inspiration**: :ref:`provenance-object` - The unique identity of the Trusted Publisher. @@ -698,9 +698,9 @@ See :ref:`pylock-packages-archive-hashes`. - **Type**: table - **Required?**: no -- **Inspiration**: :ref:` pyproject-tool-table` +- **Inspiration**: :ref:`pyproject-tool-table` - Similar usage as that of the :ref:`pylock-tool` table from the - :ref:` pyproject-toml-spec`, but at the package version level instead + :ref:`pyproject-toml-spec`, but at the package version level instead of at the lock file level (which is also available via :ref:`pylock-tool`). - Data recorded in the table MUST be disposable (i.e. it MUST NOT affect installation). From 19a7a03595d6f9e7e25fbd3abf6decda739b91e0 Mon Sep 17 00:00:00 2001 From: Yuki Kobayashi Date: Sat, 28 Jun 2025 01:14:42 +0000 Subject: [PATCH 003/187] Fix a small markup error in the contribute guide The "Do not translate ..." part shoule be a definition list, not a blockquote, like the rest of this page. --- source/contribute.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/source/contribute.rst b/source/contribute.rst index cf5314b8d..f512dd30d 100644 --- a/source/contribute.rst +++ b/source/contribute.rst @@ -103,7 +103,6 @@ If you are not familiar with reStructuredText (RST) syntax, please read `this gu before translating on Weblate. **Do not translate the text in reference directly** - When translating the text in reference, please do not translate them directly. | Wrong: Translate the following text directly: From 6b10bd2efbec7091f21973c1824db32573b4c010 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Fri, 11 Jul 2025 22:33:52 -0400 Subject: [PATCH 004/187] simple-repository-api: add PEP 792, clean up layout --- source/specifications/file-yanking.rst | 92 +++++ .../specifications/project-status-markers.rst | 89 +++++ .../section-package-indices.rst | 2 + .../specifications/simple-repository-api.rst | 369 +++++++++--------- 4 files changed, 377 insertions(+), 175 deletions(-) create mode 100644 source/specifications/file-yanking.rst create mode 100644 source/specifications/project-status-markers.rst diff --git a/source/specifications/file-yanking.rst b/source/specifications/file-yanking.rst new file mode 100644 index 000000000..4ab8cd5cc --- /dev/null +++ b/source/specifications/file-yanking.rst @@ -0,0 +1,92 @@ +.. _file-yanking: + +============ +File Yanking +============ + +.. note:: + + This specification was originally defined in + :pep:`592`. + +.. note:: + + :pep:`592` includes changes to the HTML and JSON index APIs. + These changes are documented in the :ref:`simple-repository-api` + under :ref:`HTML - Project Detail ` + and :ref:`JSON - Project Detail `. + +Specification +============= + +Links in the simple repository **MAY** have a ``data-yanked`` attribute +which may have no value, or may have an arbitrary string as a value. The +presence of a ``data-yanked`` attribute **SHOULD** be interpreted as +indicating that the file pointed to by this particular link has been +"Yanked", and should not generally be selected by an installer, except +under specific scenarios. + +The value of the ``data-yanked`` attribute, if present, is an arbitrary +string that represents the reason for why the file has been yanked. Tools +that process the simple repository API **MAY** surface this string to +end users. + +The yanked attribute is not immutable once set, and may be rescinded in +the future (and once rescinded, may be reset as well). Thus API users +**MUST** be able to cope with a yanked file being "unyanked" (and even +yanked again). + +Installers +---------- + +The desirable experience for users is that once a file is yanked, when +a human being is currently trying to directly install a yanked file, that +it fails as if that file had been deleted. However, when a human did that +awhile ago, and now a computer is just continuing to mechanically follow +the original order to install the now yanked file, then it acts as if it +had not been yanked. + +An installer **MUST** ignore yanked releases, if the selection constraints +can be satisfied with a non-yanked version, and **MAY** refuse to use a +yanked release even if it means that the request cannot be satisfied at all. +An implementation **SHOULD** choose a policy that follows the spirit of the +intention above, and that prevents "new" dependencies on yanked +releases/files. + +What this means is left up to the specific installer, to decide how to best +fit into the overall usage of their installer. However, there are two +suggested approaches to take: + +1. Yanked files are always ignored, unless they are the only file that + matches a version specifier that "pins" to an exact version using + either ``==`` (without any modifiers that make it a range, such as + ``.*``) or ``===``. Matching this version specifier should otherwise + be done as per :ref:`the version specifiers specification + ` for things like local versions, zero padding, + etc. +2. Yanked files are always ignored, unless they are the only file that + matches what a lock file (such as ``Pipfile.lock`` or ``poetry.lock``) + specifies to be installed. In this case, a yanked file **SHOULD** not + be used when creating or updating a lock file from some input file or + command. + +Regardless of the specific strategy that an installer chooses for deciding +when to install yanked files, an installer **SHOULD** emit a warning when +it does decide to install a yanked file. That warning **MAY** utilize the +value of the ``data-yanked`` attribute (if it has a value) to provide more +specific feedback to the user about why that file had been yanked. + + +Mirrors +------- + +Mirrors can generally treat yanked files one of two ways: + +1. They may choose to omit them from their simple repository API completely, + providing a view over the repository that shows only "active", unyanked + files. +2. They may choose to include yanked files, and additionally mirror the + ``data-yanked`` attribute as well. + +Mirrors **MUST NOT** mirror a yanked file without also mirroring the +``data-yanked`` attribute for it. diff --git a/source/specifications/project-status-markers.rst b/source/specifications/project-status-markers.rst new file mode 100644 index 000000000..90df74441 --- /dev/null +++ b/source/specifications/project-status-markers.rst @@ -0,0 +1,89 @@ +.. _project-status-markers: + +====================== +Project Status Markers +====================== + +.. note:: + + This specification was originally defined in + :pep:`792`. + +.. note:: + + :pep:`792` includes changes to the HTML and JSON index APIs. + These changes are documented in the :ref:`simple-repository-api` + under :ref:`HTML - Project Detail ` + and :ref:`JSON - Project Detail `. + +Specification +============= + +A project always has exactly one status. If no status is explicitly noted, +then the project is considered to be in the ``active`` state. + +Indices **MAY** implement any subset of the status markers specified, +as applicable to their needs. + +This standard does not prescribe *which* principals (i.e. project maintainers, +index administrators, etc.) are allowed to set and unset which statuses. + +``active`` +---------- + +Description: The project is active. This is the default status for a project. + +Index semantics: + +* The index hosting the project **MUST** allow uploads of new distributions to + the project. +* The index **MUST** offer existing distributions of the project for download. + +Installer semantics: none. + +``archived`` +------------ + +Description: The project does not expect to be updated in the future. + +Index semantics: + +* The index hosting the project **MUST NOT** allow uploads of new distributions to + the project. +* The index **MUST** offer existing distributions of the project for download. + +Installer semantics: + +* Installers **MAY** produce warnings about a project's archival. + +``quarantined`` +--------------- + +Description: The project is considered generally unsafe for use, e.g. due to +malware. + +Index semantics: + +* The index hosting the project **MUST NOT** allow uploads of new distributions to + the project. +* The index **MUST NOT** offer any distributions of the project for download. + +Installer semantics: + +* Installers **MAY** produce warnings about a project's quarantine, although + doing so is effectively moot (as the index will not offer any distributions + for installation). + +``deprecated`` +-------------- + +Description: The project is considered obsolete, and may have been superseded +by another project. + +Index semantics: + +* This status shares the same semantics as ``active``. + +Installer semantics: + +* Installers **MAY** produce warnings about a project's deprecation. diff --git a/source/specifications/section-package-indices.rst b/source/specifications/section-package-indices.rst index 73004b4d3..1fcefe6ff 100644 --- a/source/specifications/section-package-indices.rst +++ b/source/specifications/section-package-indices.rst @@ -7,4 +7,6 @@ Package Index Interfaces pypirc simple-repository-api + file-yanking index-hosted-attestations + project-status-markers diff --git a/source/specifications/simple-repository-api.rst b/source/specifications/simple-repository-api.rst index d18c425db..afc932e4e 100644 --- a/source/specifications/simple-repository-api.rst +++ b/source/specifications/simple-repository-api.rst @@ -12,12 +12,13 @@ and "**OPTIONAL**"" in this document are to be interpreted as described in The interface for querying available package versions and retrieving packages from an index server comes in two forms: -HTML and JSON. +:ref:`HTML ` and +:ref:`JSON `. .. _simple-repository-api-base: -Base HTML API -============= +Base API +======== A repository that implements the simple API is defined by its base URL, this is the top level URL that all additional URLs are below. The API is named the @@ -28,11 +29,115 @@ the top level URL that all additional URLs are below. The API is named the URL (so given PyPI's URL, a URL of ``/foo/`` would be ``https://pypi.org/simple/foo/``. +Normalized Names +---------------- + +This spec references the concept of a "normalized" project name. As per +:ref:`the name normalization specification ` +the only valid characters in a name are the ASCII alphabet, ASCII numbers, +``.``, ``-``, and ``_``. The name should be lowercased with all runs of the +characters ``.``, ``-``, or ``_`` replaced with a single ``-`` character. This +can be implemented in Python with the ``re`` module:: + + import re + + def normalize(name): + return re.sub(r"[-_.]+", "-", name).lower() + +.. _simple-repository-api-versioning: + +Versioning PyPI's Simple API +---------------------------- + +This spec proposes the inclusion of a meta tag on the responses of every +successful request to a simple API page, which contains a name attribute +of ``pypi:repository-version``, and a content that is a :ref:`version specifiers +specification ` compatible +version number, which is further constrained to ONLY be Major.Minor, and +none of the additional features supported by :ref:`the version specifiers +specification `. + +This would end up looking like: + +.. code-block:: html + + + +When interpreting the repository version: + +* Incrementing the major version is used to signal a backwards + incompatible change such that existing clients would no longer be + expected to be able to meaningfully use the API. +* Incrementing the minor version is used to signal a backwards + compatible change such that existing clients would still be + expected to be able to meaningfully use the API. + +It is left up to the discretion of any future specs as to what +specifically constitutes a backwards incompatible vs compatible change +beyond the broad suggestion that existing clients will be able to +"meaningfully" continue to use the API, and can include adding, +modifying, or removing existing features. + +It is expectation of this spec that the major version will never be +incremented, and any future major API evolutions would utilize a +different mechanism for API evolution. However the major version +is included to disambiguate with future versions (e.g. a hypothetical +simple api v2 that lived at /v2/, but which would be confusing if the +repository-version was set to a version >= 2). + +API Version History +~~~~~~~~~~~~~~~~~~~ + +This section contains only an abbreviated history of changes, +as marked by the API version number. For a full history of changes including +changes made before API versioning, see :ref:`History `. + +- API version 1.0: Initial version of the API, declared with :pep:`629`. +- API version 1.1: Added ``versions``, ``files[].size``, and ``files[].upload-time`` metadata + to the JSON serialization, declared with :pep:`700`. +- API version 1.2: Added repository "tracks" metadata, declared with :pep:`708`. +- API version 1.3: Added provenance metadata, declared with :pep:`740`. +- API version 1.4: Added status markers, declared with :pep:`792`. + +Clients +~~~~~~~ + +Clients interacting with the simple API **SHOULD** introspect each +response for the repository version, and if that data does not exist +**MUST** assume that it is version 1.0. + +When encountering a major version greater than expected, clients +**MUST** hard fail with an appropriate error message for the user. + +When encountering a minor version greater than expected, clients +**SHOULD** warn users with an appropriate message. + +Clients **MAY** still continue to use feature detection in order to +determine what features a repository uses. + +.. _simple-repository-html-serialization: + +HTML Serialization +------------------ + +.. _simple-repository-html-project-list: + +The following constraints apply to all HTML serialized responses described in +this spec: + +* All HTML responses **MUST** be a valid HTML5 document. +* HTML responses **MAY** contain one or more ``meta`` tags in the + ```` section. The semantics of these tags are defined below. + +Project List +~~~~~~~~~~~~ Within a repository, the root URL (``/`` for this spec which represents the base URL) **MUST** be a valid HTML5 page with a single anchor element per project in -the repository. The text of the anchor tag **MUST** be the name of -the project and the href attribute **MUST** link to the URL for that particular +the repository. + +The text of each anchor tag **MUST** be the name of +the project and the ``href`` attribute **MUST** link to the URL for that particular project. As an example: .. code-block:: html @@ -45,14 +150,26 @@ project. As an example: +.. _simple-repository-html-project-detail: + +Project Detail +~~~~~~~~~~~~~~ + Below the root URL is another URL for each individual project contained within -a repository. The format of this URL is ``//`` where the ```` -is replaced by the normalized name for that project, so a project named -"HolyGrail" would have a URL like ``/holygrail/``. This URL must respond with -a valid HTML5 page with a single anchor element per file for the project. The -href attribute **MUST** be a URL that links to the location of the file for -download, and the text of the anchor tag **MUST** match the final path -component (the filename) of the URL. The URL **SHOULD** include a hash in the +a repository. The format of this URL is ``//``, where the ```` +is replaced by the normalized name for that project. + +.. tip:: + + For example, a project named "HolyGrail" would have a URL like + ``/holygrail/``. + +The project detail URL must respond with a valid HTML5 page with a single +anchor element per file for the project. The ``href`` attribute **MUST** be a +URL that links to the location of the file for download, and the text of the +anchor tag **MUST** match the final path component (the filename) of the URL. + +Each file URL **SHOULD** include a hash in the form of a URL fragment with the following syntax: ``#=``, where ```` is the lowercase name of the hash function (such as ``sha256``) and ```` is the hex encoded digest. @@ -125,6 +242,22 @@ In addition to the above, the following constraints are placed on the API: In the attribute value, < and > have to be HTML encoded as ``<`` and ``>``, respectively. +* A repository **MAY** include a ``data-yanked`` attribute on a file link. + + The ``data-yanked`` attribute may have no value, or may have an + arbitrary string as a value. The presence of a ``data-yanked`` attribute + **SHOULD** be interpreted as indicating that the file pointed to by this + particular link has been "Yanked", and should not generally be selected by + an installer, except under specific scenarios. + + The value of the ``data-yanked`` attribute, if present, is an arbitrary + string that represents the reason for why the file has been yanked. + + .. note:: + + The semantics of how tools should handle yanked files is + described in :ref:`file-yanking`. + * A repository **MAY** include a ``data-provenance`` attribute on a file link. The value of this attribute **MUST** be a fully qualified URL, signaling that the file's provenance can be found at that URL. This URL **MUST** represent @@ -138,168 +271,22 @@ In addition to the above, the following constraints are placed on the API: The format of the linked provenance is defined in :ref:`index-hosted-attestations`. -Normalized Names ----------------- - -This spec references the concept of a "normalized" project name. As per -:ref:`the name normalization specification ` -the only valid characters in a name are the ASCII alphabet, ASCII numbers, -``.``, ``-``, and ``_``. The name should be lowercased with all runs of the -characters ``.``, ``-``, or ``_`` replaced with a single ``-`` character. This -can be implemented in Python with the ``re`` module:: - - import re - - def normalize(name): - return re.sub(r"[-_.]+", "-", name).lower() - -.. _simple-repository-api-yank: - -Adding "Yank" Support to the Simple API -======================================= - -Links in the simple repository **MAY** have a ``data-yanked`` attribute -which may have no value, or may have an arbitrary string as a value. The -presence of a ``data-yanked`` attribute **SHOULD** be interpreted as -indicating that the file pointed to by this particular link has been -"Yanked", and should not generally be selected by an installer, except -under specific scenarios. - -The value of the ``data-yanked`` attribute, if present, is an arbitrary -string that represents the reason for why the file has been yanked. Tools -that process the simple repository API **MAY** surface this string to -end users. - -The yanked attribute is not immutable once set, and may be rescinded in -the future (and once rescinded, may be reset as well). Thus API users -**MUST** be able to cope with a yanked file being "unyanked" (and even -yanked again). - - -Installers ----------- - -The desirable experience for users is that once a file is yanked, when -a human being is currently trying to directly install a yanked file, that -it fails as if that file had been deleted. However, when a human did that -awhile ago, and now a computer is just continuing to mechanically follow -the original order to install the now yanked file, then it acts as if it -had not been yanked. - -An installer **MUST** ignore yanked releases, if the selection constraints -can be satisfied with a non-yanked version, and **MAY** refuse to use a -yanked release even if it means that the request cannot be satisfied at all. -An implementation **SHOULD** choose a policy that follows the spirit of the -intention above, and that prevents "new" dependencies on yanked -releases/files. - -What this means is left up to the specific installer, to decide how to best -fit into the overall usage of their installer. However, there are two -suggested approaches to take: - -1. Yanked files are always ignored, unless they are the only file that - matches a version specifier that "pins" to an exact version using - either ``==`` (without any modifiers that make it a range, such as - ``.*``) or ``===``. Matching this version specifier should otherwise - be done as per :ref:`the version specifiers specification - ` for things like local versions, zero padding, - etc. -2. Yanked files are always ignored, unless they are the only file that - matches what a lock file (such as ``Pipfile.lock`` or ``poetry.lock``) - specifies to be installed. In this case, a yanked file **SHOULD** not - be used when creating or updating a lock file from some input file or - command. - -Regardless of the specific strategy that an installer chooses for deciding -when to install yanked files, an installer **SHOULD** emit a warning when -it does decide to install a yanked file. That warning **MAY** utilize the -value of the ``data-yanked`` attribute (if it has a value) to provide more -specific feedback to the user about why that file had been yanked. - - -Mirrors -------- - -Mirrors can generally treat yanked files one of two ways: - -1. They may choose to omit them from their simple repository API completely, - providing a view over the repository that shows only "active", unyanked - files. -2. They may choose to include yanked files, and additionally mirror the - ``data-yanked`` attribute as well. - -Mirrors **MUST NOT** mirror a yanked file without also mirroring the -``data-yanked`` attribute for it. - -.. _simple-repository-api-versioning: - -Versioning PyPI's Simple API -============================ - -This spec proposes the inclusion of a meta tag on the responses of every -successful request to a simple API page, which contains a name attribute -of ``pypi:repository-version``, and a content that is a :ref:`version specifiers -specification ` compatible -version number, which is further constrained to ONLY be Major.Minor, and -none of the additional features supported by :ref:`the version specifiers -specification `. - -This would end up looking like: - -.. code-block:: html - - - -When interpreting the repository version: - -* Incrementing the major version is used to signal a backwards - incompatible change such that existing clients would no longer be - expected to be able to meaningfully use the API. -* Incrementing the minor version is used to signal a backwards - compatible change such that existing clients would still be - expected to be able to meaningfully use the API. - -It is left up to the discretion of any future specs as to what -specifically constitutes a backwards incompatible vs compatible change -beyond the broad suggestion that existing clients will be able to -"meaningfully" continue to use the API, and can include adding, -modifying, or removing existing features. - -It is expectation of this spec that the major version will never be -incremented, and any future major API evolutions would utilize a -different mechanism for API evolution. However the major version -is included to disambiguate with future versions (e.g. a hypothetical -simple api v2 that lived at /v2/, but which would be confusing if the -repository-version was set to a version >= 2). - -API Version History -------------------- +* A repository **MAY** include ``pypi:project-status`` and + ``pypi:project-status-reason`` meta tags on the response itself. -This section contains only an abbreviated history of changes, -as marked by the API version number. For a full history of changes including -changes made before API versioning, see :ref:`History `. + The value of ``pypi:project-status`` **MUST** be a valid + project status marker, while the value of + ``pypi:project-status-reason`` **MUST** be an arbitrary string if present. -- API version 1.0: Initial version of the API, declared with :pep:`629`. -- API version 1.1: Added ``versions``, ``files[].size``, and ``files[].upload-time`` metadata - to the JSON serialization, declared with :pep:`700`. -- API version 1.2: Added repository "tracks" metadata, declared with :pep:`708`. -- API version 1.3: Added provenance metadata, declared with :pep:`740`. - -Clients -------- - -Clients interacting with the simple API **SHOULD** introspect each -response for the repository version, and if that data does not exist -**MUST** assume that it is version 1.0. + .. note:: -When encountering a major version greater than expected, clients -**MUST** hard fail with an appropriate error message for the user. + The set of valid project status markers and their semantics is described + in :ref:`project-status-markers`. -When encountering a minor version greater than expected, clients -**SHOULD** warn users with an appropriate message. + .. note:: -Clients **MAY** still continue to use feature detection in order to -determine what features a repository uses. + The ``pypi:project-status`` and ``pypi:project-status-reason`` meta tags + were added with API version 1.4. .. _simple-repository-api-metadata-file: @@ -403,8 +390,8 @@ JSON Serialization ------------------ The URL structure from :ref:`the base HTML API specification -` still applies, as this spec only adds an additional -serialization format for the already existing API. +` still applies, as this spec only adds +an additional serialization format for the already existing API. The following constraints apply to all JSON serialized responses described in this spec: @@ -435,6 +422,8 @@ spec: * Keys (at any level) with a leading underscore are reserved as private for index server use. No future standard will assign a meaning to any such key. +.. _simple-repository-json-project-list: + Project List ~~~~~~~~~~~~ @@ -450,7 +439,7 @@ As an example: { "meta": { - "api-version": "1.3" + "api-version": "1.4" }, "projects": [ {"name": "Frob"}, @@ -478,6 +467,7 @@ As an example: best thought of as a set, but both JSON and HTML lack the functionality to have sets. +.. _simple-repository-json-project-detail: Project Detail ~~~~~~~~~~~~~~ @@ -492,6 +482,28 @@ This URL must respond with a JSON encoded dictionary that has four keys: - ``name``: The normalized name of the project. - ``files``: A list of dictionaries, each one representing an individual file. - ``meta``: The general response metadata as `described earlier `__. + + In addition to the general response metadata, the project detail ``meta`` + dictionary **MAY** also include the following: + + - ``project-status``: If present, this **MUST** be a valid project status marker. + + .. note:: + + The set of valid project status markers and their semantics is described + in :ref:`project-status-markers`. + + .. note:: + + The ``project-status`` key was added with API version 1.4. + + - ``project-status-reason``: If present, this **MUST** be an arbitrary string + description of the project status. + + .. note:: + + The ``project-status-reason`` key was added with API version 1.4. + - ``versions``: A list of version strings specifying all of the project versions uploaded for this project. The value of ``versions`` is logically a set, and as such may not contain duplicates, and the order of the versions is @@ -582,8 +594,13 @@ Each individual file dictionary has the following keys: file has been yanked, or a non empty, but otherwise arbitrary, string to indicate that a file has been yanked with a specific reason. If the ``yanked`` key is present and is a truthy value, then it **SHOULD** be interpreted as indicating that the - file pointed to by the ``url`` field has been "Yanked" as per :ref:`the API - yank specification `. + file pointed to by the ``url`` field has been "Yanked". + + .. note:: + + The semantics of how tools should handle yanked files is + described in :ref:`file-yanking`. + - ``size``: A **mandatory** key. It **MUST** contain an integer which is the file size in bytes. .. note:: @@ -618,7 +635,8 @@ As an example: { "meta": { - "api-version": "1.3" + "api-version": "1.4", + "project-status": "active" }, "name": "holygrail", "files": [ @@ -1006,3 +1024,4 @@ History * June 2023: renaming the field which provides package metadata independently from a package, in :pep:`714` * November 2024: provenance metadata in the HTML and JSON formats, in :pep:`740` +* July 2025: project status markers in the HTML and JSON formats, in :pep:`792` From 9a6a4358ce484d2d76b27f0cadde85b174171d5e Mon Sep 17 00:00:00 2001 From: Clemens Brunner Date: Wed, 16 Jul 2025 08:41:19 +0200 Subject: [PATCH 005/187] Add uv-build to table --- source/guides/writing-pyproject-toml.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/guides/writing-pyproject-toml.rst b/source/guides/writing-pyproject-toml.rst index 318fe0d51..1d035a384 100644 --- a/source/guides/writing-pyproject-toml.rst +++ b/source/guides/writing-pyproject-toml.rst @@ -314,11 +314,13 @@ backend>` now support the new format as shown in the following table. - flit-core [#flit-core-pep639]_ - pdm-backend - poetry-core + - uv-build * - 1.27.0 - 77.0.3 - 3.12 - 2.4.0 - `not yet `_ + - 0.7.19 .. _license: From bfd629be54786fe443354a239b9fedfe4341477c Mon Sep 17 00:00:00 2001 From: Clemens Brunner Date: Fri, 18 Jul 2025 08:58:33 +0200 Subject: [PATCH 006/187] Add uv in other places --- source/shared/build-backend-tabs.rst | 8 ++++++++ source/tutorials/managing-dependencies.rst | 2 ++ 2 files changed, 10 insertions(+) diff --git a/source/shared/build-backend-tabs.rst b/source/shared/build-backend-tabs.rst index 7fc3a61da..a4c49a3b4 100644 --- a/source/shared/build-backend-tabs.rst +++ b/source/shared/build-backend-tabs.rst @@ -32,3 +32,11 @@ [build-system] requires = ["pdm-backend >= 2.4.0"] build-backend = "pdm.backend" + +.. tab:: uv-build + + .. code-block:: toml + + [build-system] + requires = ["uv_build >= 0.8.0, <0.9.0"] + build-backend = "uv_build" \ No newline at end of file diff --git a/source/tutorials/managing-dependencies.rst b/source/tutorials/managing-dependencies.rst index db3b82533..da12d8a91 100644 --- a/source/tutorials/managing-dependencies.rst +++ b/source/tutorials/managing-dependencies.rst @@ -177,3 +177,5 @@ and techniques, listed in alphabetical order, to see if one of them is a better structured as a distributable Python package with a valid ``pyproject.toml`` file. By contrast, Pipenv explicitly avoids making the assumption that the application being worked on will support distribution as a ``pip``-installable Python package. +* `uv `__ for a single tool that covers the entire project + management workflow, including dependency management, packaging, and publishing. \ No newline at end of file From 4bd633068206553f8d14375223eb261b2856ac0a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 18 Jul 2025 06:59:04 +0000 Subject: [PATCH 007/187] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- source/shared/build-backend-tabs.rst | 2 +- source/tutorials/managing-dependencies.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/shared/build-backend-tabs.rst b/source/shared/build-backend-tabs.rst index a4c49a3b4..2c58654a8 100644 --- a/source/shared/build-backend-tabs.rst +++ b/source/shared/build-backend-tabs.rst @@ -39,4 +39,4 @@ [build-system] requires = ["uv_build >= 0.8.0, <0.9.0"] - build-backend = "uv_build" \ No newline at end of file + build-backend = "uv_build" diff --git a/source/tutorials/managing-dependencies.rst b/source/tutorials/managing-dependencies.rst index da12d8a91..bb67a60e3 100644 --- a/source/tutorials/managing-dependencies.rst +++ b/source/tutorials/managing-dependencies.rst @@ -178,4 +178,4 @@ and techniques, listed in alphabetical order, to see if one of them is a better By contrast, Pipenv explicitly avoids making the assumption that the application being worked on will support distribution as a ``pip``-installable Python package. * `uv `__ for a single tool that covers the entire project - management workflow, including dependency management, packaging, and publishing. \ No newline at end of file + management workflow, including dependency management, packaging, and publishing. From f57c5bf67535b018d93d1e970352110f0774293d Mon Sep 17 00:00:00 2001 From: Clemens Brunner Date: Fri, 18 Jul 2025 09:04:49 +0200 Subject: [PATCH 008/187] Use first version that supported PEP 639 --- 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 2c58654a8..608fcaddd 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.0, <0.9.0"] + requires = ["uv_build >= 0.7.19, <0.9.0"] build-backend = "uv_build" From 9cbbdbce133316d11272545ae8bf8394fc17cbfe Mon Sep 17 00:00:00 2001 From: Clemens Brunner Date: Tue, 22 Jul 2025 13:40:55 +0200 Subject: [PATCH 009/187] Ignore linkcheck for ATLAS URL --- source/conf.py | 1 + 1 file changed, 1 insertion(+) diff --git a/source/conf.py b/source/conf.py index 7a05613ea..21cac0e9b 100644 --- a/source/conf.py +++ b/source/conf.py @@ -147,6 +147,7 @@ "https://anaconda.org", "https://www.cisa.gov/sbom", "https://developers.redhat.com/products/softwarecollections/overview", + "https://math-atlas.sourceforge.net/", ] linkcheck_retries = 5 # Ignore anchors for common targets when we know they likely won't be found From 7f675d8e701ce55924a0f8eb9f7dc995b92018e7 Mon Sep 17 00:00:00 2001 From: Clemens Brunner Date: Tue, 22 Jul 2025 13:53:44 +0200 Subject: [PATCH 010/187] Fix regex --- source/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/conf.py b/source/conf.py index 21cac0e9b..2995ce190 100644 --- a/source/conf.py +++ b/source/conf.py @@ -147,7 +147,7 @@ "https://anaconda.org", "https://www.cisa.gov/sbom", "https://developers.redhat.com/products/softwarecollections/overview", - "https://math-atlas.sourceforge.net/", + "https://math-atlas\\.sourceforge\\.net/?", ] linkcheck_retries = 5 # Ignore anchors for common targets when we know they likely won't be found From fa92ece30c88874efb4611e0e679a08ad7c174e1 Mon Sep 17 00:00:00 2001 From: Clemens Brunner Date: Tue, 22 Jul 2025 15:24:05 +0200 Subject: [PATCH 011/187] Quick sanity check --- source/guides/installing-scientific-packages.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/guides/installing-scientific-packages.rst b/source/guides/installing-scientific-packages.rst index a1aeae567..152a8350c 100644 --- a/source/guides/installing-scientific-packages.rst +++ b/source/guides/installing-scientific-packages.rst @@ -19,8 +19,7 @@ of different levels of vectorized instructions available in modern CPUs. Starting with version 1.10.4 of NumPy and version 1.0.0 of SciPy, pre-built 32-bit and 64-bit binaries in the ``wheel`` format are available for all major operating systems (Windows, macOS, and Linux) on PyPI. Note, however, that on -Windows, NumPy binaries are linked against the `ATLAS -`__ BLAS/LAPACK library, restricted to SSE2 +Windows, NumPy binaries are linked against the ATLAS BLAS/LAPACK library, restricted to SSE2 instructions, so they may not provide optimal linear algebra performance. There are a number of alternative options for obtaining scientific Python From 0fcbcccf4c1e6253cfa1221914e5da79e6a850f9 Mon Sep 17 00:00:00 2001 From: Clemens Brunner Date: Tue, 22 Jul 2025 15:30:48 +0200 Subject: [PATCH 012/187] Verbose --- noxfile.py | 1 + 1 file changed, 1 insertion(+) diff --git a/noxfile.py b/noxfile.py index 698e82f9d..de3106445 100644 --- a/noxfile.py +++ b/noxfile.py @@ -87,6 +87,7 @@ def linkcheck(session): "-n", "-W", "--keep-going", # be strict + "-vvv", "source", # where the rst files are located "build", # where to put the check output ) From 403e8ac53f06daf832dd35a5d6b1c994ca1b6964 Mon Sep 17 00:00:00 2001 From: Clemens Brunner Date: Tue, 22 Jul 2025 15:35:06 +0200 Subject: [PATCH 013/187] Revert "Quick sanity check" This reverts commit fa92ece30c88874efb4611e0e679a08ad7c174e1. --- noxfile.py | 1 - source/guides/installing-scientific-packages.rst | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/noxfile.py b/noxfile.py index de3106445..698e82f9d 100644 --- a/noxfile.py +++ b/noxfile.py @@ -87,7 +87,6 @@ def linkcheck(session): "-n", "-W", "--keep-going", # be strict - "-vvv", "source", # where the rst files are located "build", # where to put the check output ) diff --git a/source/guides/installing-scientific-packages.rst b/source/guides/installing-scientific-packages.rst index 152a8350c..a1aeae567 100644 --- a/source/guides/installing-scientific-packages.rst +++ b/source/guides/installing-scientific-packages.rst @@ -19,7 +19,8 @@ of different levels of vectorized instructions available in modern CPUs. Starting with version 1.10.4 of NumPy and version 1.0.0 of SciPy, pre-built 32-bit and 64-bit binaries in the ``wheel`` format are available for all major operating systems (Windows, macOS, and Linux) on PyPI. Note, however, that on -Windows, NumPy binaries are linked against the ATLAS BLAS/LAPACK library, restricted to SSE2 +Windows, NumPy binaries are linked against the `ATLAS +`__ BLAS/LAPACK library, restricted to SSE2 instructions, so they may not provide optimal linear algebra performance. There are a number of alternative options for obtaining scientific Python From b9bb306c0069088f5f7bc18839e94f64ab71daed Mon Sep 17 00:00:00 2001 From: Clemens Brunner Date: Tue, 22 Jul 2025 15:45:31 +0200 Subject: [PATCH 014/187] Fix ignores --- source/conf.py | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/source/conf.py b/source/conf.py index 2995ce190..5e79a80fe 100644 --- a/source/conf.py +++ b/source/conf.py @@ -132,28 +132,32 @@ # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-the-linkcheck-builder linkcheck_ignore = [ - "http://localhost:\\d+", - "https://packaging.python.org/en/latest/specifications/schemas/.*", - "https://test.pypi.org/project/example-package-YOUR-USERNAME-HERE", - "https://pypi.org/manage/*", - "https://test.pypi.org/manage/*", + 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/.*", # Temporarily ignored. Ref: # https://github.com/pypa/packaging.python.org/pull/1308#issuecomment-1775347690 - "https://www.breezy-vcs.org/*", + r"https://www.breezy-vcs.org/.*", # Ignore while StackOverflow is blocking GitHub CI. Ref: # https://github.com/pypa/packaging.python.org/pull/1474 - "https://stackoverflow.com/*", - "https://pyscaffold.org/*", - "https://anaconda.org", - "https://www.cisa.gov/sbom", - "https://developers.redhat.com/products/softwarecollections/overview", - "https://math-atlas\\.sourceforge\\.net/?", + r"https://stackoverflow.com/.*", + r"https://pyscaffold.org/.*", + r"https://anaconda.org", + r"https://www.cisa.gov/sbom", + r"https://developers.redhat.com/products/softwarecollections/overview", + r"https://math-atlas\.sourceforge\.net/?", + # Self-signed certificate, fails in CI + r"https://click\.palletsprojects\.com/.*", + r"https://typer\.tiangolo\.com/.*", ] linkcheck_retries = 5 # Ignore anchors for common targets when we know they likely won't be found linkcheck_anchors_ignore_for_url = [ # GitHub synthesises anchors in JavaScript, so Sphinx can't find them in the HTML r"https://github\.com/", + r"https://docs\.github\.com/", # While PyPI has its botscraping defenses active, Sphinx can't resolve the anchors # https://github.com/pypa/packaging.python.org/issues/1744 r"https://pypi\.org/", From 403649c5f0892f0b74e291a3dcd3338cf8e1c022 Mon Sep 17 00:00:00 2001 From: Clemens Brunner Date: Tue, 22 Jul 2025 15:46:48 +0200 Subject: [PATCH 015/187] Fix regexes --- source/conf.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/source/conf.py b/source/conf.py index 5e79a80fe..5a7e43e91 100644 --- a/source/conf.py +++ b/source/conf.py @@ -133,20 +133,20 @@ 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/.*", + 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/.*", # Temporarily ignored. Ref: # https://github.com/pypa/packaging.python.org/pull/1308#issuecomment-1775347690 - r"https://www.breezy-vcs.org/.*", + r"https://www\.breezy-vcs\.org/.*", # Ignore while StackOverflow is blocking GitHub CI. Ref: # https://github.com/pypa/packaging.python.org/pull/1474 - r"https://stackoverflow.com/.*", - r"https://pyscaffold.org/.*", - r"https://anaconda.org", - r"https://www.cisa.gov/sbom", - r"https://developers.redhat.com/products/softwarecollections/overview", + r"https://stackoverflow\.com/.*", + r"https://pyscaffold\.org/.*", + r"https://anaconda\.org", + r"https://www\.cisa\.gov/sbom", + r"https://developers\.redhat\.com/products/softwarecollections/overview", r"https://math-atlas\.sourceforge\.net/?", # Self-signed certificate, fails in CI r"https://click\.palletsprojects\.com/.*", From 2fb1f527789c65d558ae20bb6708887e134aed2f Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Tue, 22 Jul 2025 14:34:01 -0400 Subject: [PATCH 016/187] add an example project-status-reason --- source/specifications/simple-repository-api.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/specifications/simple-repository-api.rst b/source/specifications/simple-repository-api.rst index afc932e4e..f9a32bc78 100644 --- a/source/specifications/simple-repository-api.rst +++ b/source/specifications/simple-repository-api.rst @@ -20,7 +20,7 @@ retrieving packages from an index server comes in two forms: Base API ======== -A repository that implements the simple API is defined by its base URL, this is +A repository that implements the simple API is defined by its base URL. This is the top level URL that all additional URLs are below. The API is named the "simple" repository due to the fact that PyPI's base URL is ``https://pypi.org/simple/``. @@ -636,7 +636,8 @@ As an example: { "meta": { "api-version": "1.4", - "project-status": "active" + "project-status": "active", + "project-status-reason": "this project is not yet haunted" }, "name": "holygrail", "files": [ From 3a66caf08a8668aff7c43a50dd756079bf79b7b0 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Thu, 24 Jul 2025 17:12:43 -0400 Subject: [PATCH 017/187] Update source/specifications/simple-repository-api.rst Co-authored-by: Alyssa Coghlan --- source/specifications/simple-repository-api.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/source/specifications/simple-repository-api.rst b/source/specifications/simple-repository-api.rst index f9a32bc78..4f5bb0043 100644 --- a/source/specifications/simple-repository-api.rst +++ b/source/specifications/simple-repository-api.rst @@ -1026,3 +1026,4 @@ History from a package, in :pep:`714` * November 2024: provenance metadata in the HTML and JSON formats, in :pep:`740` * July 2025: project status markers in the HTML and JSON formats, in :pep:`792` +* July 2025: layout changes (dedicated page for file yanking, introduce concepts before API details) From 8f7b5a833a30ea541dcfd4db7b7d42e5533cc535 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Thu, 24 Jul 2025 17:23:54 -0400 Subject: [PATCH 018/187] fix broken anchor --- ...stribution-releases-using-github-actions-ci-cd-workflows.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 1ee562cf7..e9f601e03 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 @@ -75,7 +75,7 @@ Let's begin! 🚀 .. attention:: - For security reasons, you must require `manual approval `_ + For security reasons, you must require `manual approval `_ on each run for the ``pypi`` environment. From 79f33bd76d31f4312faa5ab8464121651dc9c3e9 Mon Sep 17 00:00:00 2001 From: Clemens Brunner Date: Thu, 31 Jul 2025 10:11:17 +0200 Subject: [PATCH 019/187] Revert unrelated changes --- source/conf.py | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/source/conf.py b/source/conf.py index 5a7e43e91..8b20a28b3 100644 --- a/source/conf.py +++ b/source/conf.py @@ -132,23 +132,22 @@ # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-the-linkcheck-builder 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/.*", + "http://localhost:\\d+", + "https://packaging.python.org/en/latest/specifications/schemas/.*", + "https://test.pypi.org/project/example-package-YOUR-USERNAME-HERE", + "https://pypi.org/manage/*", + "https://test.pypi.org/manage/*", # Temporarily ignored. Ref: # https://github.com/pypa/packaging.python.org/pull/1308#issuecomment-1775347690 - r"https://www\.breezy-vcs\.org/.*", + "https://www.breezy-vcs.org/*", # Ignore while StackOverflow is blocking GitHub CI. Ref: # https://github.com/pypa/packaging.python.org/pull/1474 - r"https://stackoverflow\.com/.*", - r"https://pyscaffold\.org/.*", - r"https://anaconda\.org", - r"https://www\.cisa\.gov/sbom", - r"https://developers\.redhat\.com/products/softwarecollections/overview", + "https://stackoverflow.com/*", + "https://pyscaffold.org/*", + "https://anaconda.org", + "https://www.cisa.gov/sbom", + "https://developers.redhat.com/products/softwarecollections/overview", r"https://math-atlas\.sourceforge\.net/?", - # Self-signed certificate, fails in CI r"https://click\.palletsprojects\.com/.*", r"https://typer\.tiangolo\.com/.*", ] @@ -157,7 +156,6 @@ linkcheck_anchors_ignore_for_url = [ # GitHub synthesises anchors in JavaScript, so Sphinx can't find them in the HTML r"https://github\.com/", - r"https://docs\.github\.com/", # While PyPI has its botscraping defenses active, Sphinx can't resolve the anchors # https://github.com/pypa/packaging.python.org/issues/1744 r"https://pypi\.org/", From c44686e6759fa75cd377bae84693928fed5bb826 Mon Sep 17 00:00:00 2001 From: Clemens Brunner Date: Thu, 31 Jul 2025 10:18:15 +0200 Subject: [PATCH 020/187] Add docs.github.com --- source/conf.py | 1 + 1 file changed, 1 insertion(+) diff --git a/source/conf.py b/source/conf.py index 8b20a28b3..961e2e0a6 100644 --- a/source/conf.py +++ b/source/conf.py @@ -156,6 +156,7 @@ linkcheck_anchors_ignore_for_url = [ # GitHub synthesises anchors in JavaScript, so Sphinx can't find them in the HTML r"https://github\.com/", + r"https://docs\.github\.com/", # While PyPI has its botscraping defenses active, Sphinx can't resolve the anchors # https://github.com/pypa/packaging.python.org/issues/1744 r"https://pypi\.org/", From 6e2333a3b3bec72a63789f10455c27a9e5c69c4d Mon Sep 17 00:00:00 2001 From: Clemens Brunner Date: Thu, 31 Jul 2025 14:58:34 +0200 Subject: [PATCH 021/187] Convert linkcheck_ignore entries to regexes --- source/conf.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/source/conf.py b/source/conf.py index 961e2e0a6..4c6d8bea4 100644 --- a/source/conf.py +++ b/source/conf.py @@ -132,21 +132,21 @@ # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-the-linkcheck-builder linkcheck_ignore = [ - "http://localhost:\\d+", - "https://packaging.python.org/en/latest/specifications/schemas/.*", - "https://test.pypi.org/project/example-package-YOUR-USERNAME-HERE", - "https://pypi.org/manage/*", - "https://test.pypi.org/manage/*", + 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/.*", # Temporarily ignored. Ref: # https://github.com/pypa/packaging.python.org/pull/1308#issuecomment-1775347690 - "https://www.breezy-vcs.org/*", + r"https://www\.breezy-vcs\.org/.*", # Ignore while StackOverflow is blocking GitHub CI. Ref: # https://github.com/pypa/packaging.python.org/pull/1474 - "https://stackoverflow.com/*", - "https://pyscaffold.org/*", - "https://anaconda.org", - "https://www.cisa.gov/sbom", - "https://developers.redhat.com/products/softwarecollections/overview", + r"https://stackoverflow\.com/.*", + r"https://pyscaffold\.org/.*", + r"https://anaconda\.org", + r"https://www\.cisa\.gov/sbom", + r"https://developers\.redhat\.com/products/softwarecollections/overview", r"https://math-atlas\.sourceforge\.net/?", r"https://click\.palletsprojects\.com/.*", r"https://typer\.tiangolo\.com/.*", From 1c6736c7aefb0086b1ded32676732ad0b1072e02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Ram=C3=ADrez=20Mondrag=C3=B3n?= Date: Sun, 3 Aug 2025 18:56:00 -0600 Subject: [PATCH 022/187] Host PyPA spec schemas in packaging.python.org/ --- source/conf.py | 4 - source/specifications/build-details/v1.0.rst | 2 +- .../direct-url-data-structure.rst | 117 +----- source/specifications/index.rst | 1 + .../schemas/build-details-v1.0.schema.json | 0 .../schemas/direct-url.schema.json | 99 +++++ source/specifications/schemas/index.rst | 8 + .../specifications/schemas/pylock.schema.json | 345 ++++++++++++++++++ 8 files changed, 455 insertions(+), 121 deletions(-) rename {extra => source}/specifications/schemas/build-details-v1.0.schema.json (100%) create mode 100644 source/specifications/schemas/direct-url.schema.json create mode 100644 source/specifications/schemas/index.rst create mode 100644 source/specifications/schemas/pylock.schema.json diff --git a/source/conf.py b/source/conf.py index 4c6d8bea4..a8a040d6c 100644 --- a/source/conf.py +++ b/source/conf.py @@ -83,10 +83,6 @@ # 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 diff --git a/source/specifications/build-details/v1.0.rst b/source/specifications/build-details/v1.0.rst index 3a8cfe277..cfe902e1e 100644 --- a/source/specifications/build-details/v1.0.rst +++ b/source/specifications/build-details/v1.0.rst @@ -8,7 +8,7 @@ Specification ------------- -.. jsonschema:: ../../../extra/specifications/schemas/build-details-v1.0.schema.json +.. jsonschema:: ../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 0d243652d..5f3af0fae 100644 --- a/source/specifications/direct-url-data-structure.rst +++ b/source/specifications/direct-url-data-structure.rst @@ -236,122 +236,7 @@ JSON Schema The following JSON Schema can be used to validate the contents of ``direct_url.json``: -.. code-block:: - - { - "$schema": "https://json-schema.org/draft/2019-09/schema", - "title": "Direct URL Data", - "description": "Data structure that can represent URLs to python projects and distribution artifacts such as VCS source trees, local source trees, source distributions and wheels.", - "definitions": { - "URL": { - "type": "string", - "format": "uri" - }, - "DirInfo": { - "type": "object", - "properties": { - "editable": { - "type": ["boolean", "null"] - } - } - }, - "VCSInfo": { - "type": "object", - "properties": { - "vcs": { - "type": "string", - "enum": [ - "git", - "hg", - "bzr", - "svn" - ] - }, - "requested_revision": { - "type": "string" - }, - "commit_id": { - "type": "string" - }, - "resolved_revision": { - "type": "string" - } - }, - "required": [ - "vcs", - "commit_id" - ] - }, - "ArchiveInfo": { - "type": "object", - "properties": { - "hash": { - "type": "string", - "pattern": "^\\w+=[a-f0-9]+$", - "deprecated": true - }, - "hashes": { - "type": "object", - "patternProperties": { - "^[a-f0-9]+$": { - "type": "string" - } - } - } - } - } - }, - "allOf": [ - { - "type": "object", - "properties": { - "url": { - "$ref": "#/definitions/URL" - } - }, - "required": [ - "url" - ] - }, - { - "anyOf": [ - { - "type": "object", - "properties": { - "dir_info": { - "$ref": "#/definitions/DirInfo" - } - }, - "required": [ - "dir_info" - ] - }, - { - "type": "object", - "properties": { - "vcs_info": { - "$ref": "#/definitions/VCSInfo" - } - }, - "required": [ - "vcs_info" - ] - }, - { - "type": "object", - "properties": { - "archive_info": { - "$ref": "#/definitions/ArchiveInfo" - } - }, - "required": [ - "archive_info" - ] - } - ] - } - ] - } +.. literalinclude:: schemas/direct-url.schema.json Examples ======== diff --git a/source/specifications/index.rst b/source/specifications/index.rst index 68d95ab98..c375654a2 100644 --- a/source/specifications/index.rst +++ b/source/specifications/index.rst @@ -17,3 +17,4 @@ and for proposing new ones, is documented on section-package-indices section-python-description-formats section-reproducible-environments + schemas/index.rst diff --git a/extra/specifications/schemas/build-details-v1.0.schema.json b/source/specifications/schemas/build-details-v1.0.schema.json similarity index 100% rename from extra/specifications/schemas/build-details-v1.0.schema.json rename to source/specifications/schemas/build-details-v1.0.schema.json diff --git a/source/specifications/schemas/direct-url.schema.json b/source/specifications/schemas/direct-url.schema.json new file mode 100644 index 000000000..d1f4c860a --- /dev/null +++ b/source/specifications/schemas/direct-url.schema.json @@ -0,0 +1,99 @@ +{ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "$id": "https://packaging.python.org/en/latest/specifications/schemas/direct-url.schema.json", + "title": "Direct URL Data", + "description": "Data structure that can represent URLs to python projects and distribution artifacts such as VCS source trees, local source trees, source distributions and wheels.", + "definitions": { + "url": { + "type": "string", + "format": "uri" + }, + "DirInfo": { + "type": "object", + "properties": { + "editable": { + "type": ["boolean", "null"] + } + } + }, + "VCSInfo": { + "type": "object", + "properties": { + "vcs": { + "type": "string", + "enum": ["git", "hg", "bzr", "svn"] + }, + "requested_revision": { + "type": "string" + }, + "commit_id": { + "type": "string" + }, + "resolved_revision": { + "type": "string" + } + }, + "required": ["vcs", "commit_id"] + }, + "ArchiveInfo": { + "type": "object", + "properties": { + "hash": { + "type": "string", + "pattern": "^\\w+=[a-f0-9]+$", + "deprecated": true + }, + "hashes": { + "type": "object", + "patternProperties": { + "^[a-f0-9]+$": { + "type": "string" + } + } + } + } + } + }, + "allOf": [ + { + "type": "object", + "properties": { + "url": { + "$ref": "#/definitions/url" + } + }, + "required": ["url"] + }, + { + "anyOf": [ + { + "type": "object", + "properties": { + "dir_info": { + "$ref": "#/definitions/DirInfo" + } + }, + "required": ["dir_info"] + }, + { + "type": "object", + "properties": { + "vcs_info": { + "$ref": "#/definitions/VCSInfo" + } + }, + "required": ["vcs_info"] + }, + { + "type": "object", + "properties": { + "archive_info": { + "$ref": "#/definitions/ArchiveInfo" + } + }, + "required": ["archive_info"] + } + ] + } + ] +} diff --git a/source/specifications/schemas/index.rst b/source/specifications/schemas/index.rst new file mode 100644 index 000000000..a80891975 --- /dev/null +++ b/source/specifications/schemas/index.rst @@ -0,0 +1,8 @@ +.. _`packaging-schemas`: + +PyPA schemas +############ + +- `direct_url.json `_ +- `build-details.json `_ +- `pylock.toml `_ diff --git a/source/specifications/schemas/pylock.schema.json b/source/specifications/schemas/pylock.schema.json new file mode 100644 index 000000000..5469111ec --- /dev/null +++ b/source/specifications/schemas/pylock.schema.json @@ -0,0 +1,345 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://json.schemastore.org/pylock.json", + "additionalProperties": false, + "definitions": { + "tool": { + "type": "object", + "markdownDescription": "Similar usage as that of the `[tool]` table from the [pyproject.toml specification](https://packaging.python.org/en/latest/specifications/pyproject-toml/#pyproject-toml-spec), but at the package version level instead of at the lock file level (which is also available via `[tool]`).", + "additionalProperties": { + "type": "object", + "additionalProperties": true + } + }, + "url": { + "type": "string", + "markdownDescription": "The URL to the source tree." + }, + "path": { + "type": "string", + "markdownDescription": "The path to the local directory of the source tree." + }, + "upload-time": { + "markdownDescription": "The time the file was uploaded (UTC). Must be specified as a datetime literal." + }, + "size": { + "type": "integer", + "markdownDescription": "The size of the archive file." + }, + "hashes": { + "type": "object", + "description": "Known hash values of the file where the key is the hash algorithm and the value is the hash value.", + "additionalProperties": { + "type": "string" + } + }, + "subdirectory": { + "type": "string", + "markdownDescription": "The subdirectory within the [source tree](https://packaging.python.org/en/latest/specifications/source-distribution-format/#source-distribution-format-source-tree) where the project root of the project is (e.g. the location of the `pyproject.toml` file)." + }, + "vcs": { + "type": "object", + "markdownDescription": "Record the version control system details for the [source tree](https://packaging.python.org/en/latest/specifications/source-distribution-format/#source-distribution-format-source-tree) it contains.", + "additionalProperties": false, + "properties": { + "type": { + "type": "string", + "markdownDescription": "The type of version control system used." + }, + "url": { + "$ref": "#/definitions/url" + }, + "path": { + "$ref": "#/definitions/path" + }, + "requested-revision": { + "type": "string", + "markdownDescription": "The branch/tag/ref/commit/revision/etc. that the user requested." + }, + "commit-id": { + "type": "string", + "markdownDescription": "The exact commit/revision number that is to be installed." + }, + "subdirectory": { + "$ref": "#/definitions/subdirectory" + } + } + }, + "directory": { + "type": "object", + "markdownDescription": "Record the local directory details for the [source tree](https://packaging.python.org/en/latest/specifications/source-distribution-format/#source-distribution-format-source-tree) it contains.", + "additionalProperties": false, + "properties": { + "path": { + "type": "string", + "markdownDescription": "The local directory where the source tree is." + }, + "editable": { + "type": "boolean", + "default": false, + "markdownDescription": "A flag representing whether the source tree was an editable install at lock time." + }, + "subdirectory": { + "$ref": "#/definitions/subdirectory" + } + } + }, + "archive": { + "type": "object", + "additionalProperties": false, + "markdownDescription": "A direct reference to an archive file to install from (this can include wheels and sdists, as well as other archive formats containing a source tree).", + "properties": { + "url": { + "$ref": "#/definitions/url" + }, + "path": { + "$ref": "#/definitions/path" + }, + "size": { + "$ref": "#/definitions/size" + }, + "upload-time": { + "$ref": "#/definitions/upload-time" + }, + "hashes": { + "$ref": "#/definitions/hashes" + }, + "subdirectory": { + "$ref": "#/definitions/subdirectory" + } + } + }, + "sdist": { + "type": "object", + "additionalProperties": false, + "markdownDescription": "Details of a [source distribution file name](https://packaging.python.org/en/latest/specifications/source-distribution-format/#source-distribution-format-sdist) for the package.", + "properties": { + "name": { + "type": "string", + "markdownDescription": "The file name of the [source distribution file name](https://packaging.python.org/en/latest/specifications/source-distribution-format/#source-distribution-format-sdist) file." + }, + "upload-time": { + "$ref": "#/definitions/upload-time" + }, + "url": { + "$ref": "#/definitions/url" + }, + "path": { + "$ref": "#/definitions/path" + }, + "size": { + "$ref": "#/definitions/size" + }, + "hashes": { + "$ref": "#/definitions/hashes" + } + } + }, + "wheels": { + "type": "array", + "markdownDescription": "For recording the wheel files as specified by [Binary distribution format](https://packaging.python.org/en/latest/specifications/binary-distribution-format/#binary-distribution-format) for the package.", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "markdownDescription": "The file name of the [Binary distribution format](https://packaging.python.org/en/latest/specifications/binary-distribution-format/#binary-distribution-format) file." + }, + "upload-time": { + "$ref": "#/definitions/upload-time" + }, + "url": { + "$ref": "#/definitions/url" + }, + "path": { + "$ref": "#/definitions/path" + }, + "size": { + "$ref": "#/definitions/size" + }, + "hashes": { + "$ref": "#/definitions/hashes" + } + } + } + }, + "1.0": { + "required": ["lock-version", "created-by", "packages"], + "properties": { + "lock-version": { + "type": "string", + "enum": ["1.0"], + "description": "Record the file format version that the file adheres to." + }, + "environments": { + "type": "array", + "markdownDescription": "A list of [environment markers](https://packaging.python.org/en/latest/specifications/dependency-specifiers/#dependency-specifiers-environment-markers) for which the lock file is considered compatible with.", + "items": { + "type": "string", + "description": "Environment marker" + } + }, + "requires-python": { + "type": "string", + "markdownDescription": "Specifies the [Requires-Python](https://packaging.python.org/en/latest/specifications/core-metadata/#core-metadata-requires-python) for the minimum Python version compatible for any environment supported by the lock file (i.e. the minimum viable Python version for the lock file)." + }, + "extras": { + "type": "array", + "markdownDescription": "The list of [extras](https://packaging.python.org/en/latest/specifications/core-metadata/#core-metadata-provides-extra) supported by this lock file.", + "default": [], + "items": { + "type": "string", + "description": "Extra name" + } + }, + "dependency-groups": { + "type": "array", + "markdownDescription": "The list of [dependency groups](https://packaging.python.org/en/latest/specifications/dependency-groups/#dependency-groups) publicly supported by this lock file (i.e. dependency groups users are expected to be able to specify via a tool’s UI).", + "default": [], + "items": { + "type": "string", + "description": "Dependency group name" + } + }, + "default-groups": { + "type": "array", + "markdownDescription": "The name of synthetic dependency groups to represent what should be installed by default (e.g. what `project.dependencies` implicitly represents).", + "default": [], + "items": { + "type": "string", + "description": "Dependency group name" + } + }, + "created-by": { + "type": "string", + "markdownDescription": "Records the name of the tool used to create the lock file." + }, + "packages": { + "type": "array", + "markdownDescription": "An array containing all packages that may be installed.", + "items": { + "type": "object", + "additionalProperties": false, + "required": ["name"], + "allOf": [ + { + "if": { + "required": ["vcs"] + }, + "then": { + "not": { + "required": ["directory", "archive", "sdist", "wheels"] + } + } + }, + { + "if": { + "required": ["directory"] + }, + "then": { + "not": { + "required": ["vcs", "archive", "sdist", "wheels"] + } + } + }, + { + "if": { + "required": ["sdist"] + }, + "then": { + "not": { + "required": ["vcs", "directory", "archive"] + } + } + }, + { + "if": { + "required": ["wheels"] + }, + "then": { + "not": { + "required": ["vcs", "directory", "archive"] + } + } + } + ], + "properties": { + "name": { + "type": "string", + "markdownDescription": "The name of the package, [normalized](https://packaging.python.org/en/latest/specifications/name-normalization/#name-normalization)." + }, + "version": { + "type": "string", + "description": "The version of the package." + }, + "marker": { + "type": "string", + "markdownDescription": "The [environment marker](https://packaging.python.org/en/latest/specifications/dependency-specifiers/#dependency-specifiers-environment-markers) which specify when the package should be installed." + }, + "requires-python": { + "type": "string", + "markdownDescription": "Holds the [version specifiers](https://packaging.python.org/en/latest/specifications/version-specifiers/#version-specifiers) for Python version compatibility for the package." + }, + "dependencies": { + "type": "array", + "markdownDescription": "Records the other entries in `[[packages]]` which are direct dependencies of this package.", + "items": { + "type": "object", + "markdownDescription": "A table which contains the minimum information required to tell which other package entry it corresponds to where doing a key-by-key comparison would find the appropriate package with no ambiguity (e.g. if there are two entries for the `spam` package, then you can include the version number like `{name = \"spam\", version = \"1.0.0\"}`, or by source like `{name = \"spam\", vcs = { url = \"...\"}`).", + "additionalProperties": true + } + }, + "vcs": { + "$ref": "#/definitions/vcs" + }, + "directory": { + "$ref": "#/definitions/directory" + }, + "archive": { + "$ref": "#/definitions/archive" + }, + "index": { + "type": "string", + "markdownDescription": "The base URL for the package index from [simple repository API](https://packaging.python.org/en/latest/specifications/simple-repository-api/#simple-repository-api) where the sdist and/or wheels were found (e.g. `https://pypi.org/simple/`)." + }, + "sdist": { + "$ref": "#/definitions/sdist" + }, + "wheels": { + "$ref": "#/definitions/wheels" + }, + "attestation-identities": { + "type": "array", + "markdownDescription": "A recording of the attestations for any file recorded for this package.", + "items": { + "type": "object", + "additionalProperties": false, + "required": ["kind"], + "properties": { + "kind": { + "type": "string", + "markdownDescription": "The unique identity of the Trusted Publisher." + } + } + } + }, + "tool": { + "$ref": "#/definitions/tool" + } + } + } + }, + "tool": { + "$ref": "#/definitions/tool" + } + } + } + }, + "oneOf": [ + { + "$ref": "#/definitions/1.0" + } + ], + "type": "object" +} From afab730d8ebff66e79ec03527d3628544d17eaac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Ram=C3=ADrez=20Mondrag=C3=B3n?= Date: Sun, 3 Aug 2025 19:16:39 -0600 Subject: [PATCH 023/187] Fix broken setuptools-scm link --- source/discussions/setup-py-deprecated.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/discussions/setup-py-deprecated.rst b/source/discussions/setup-py-deprecated.rst index 6bcd15b58..dbea4ed52 100644 --- a/source/discussions/setup-py-deprecated.rst +++ b/source/discussions/setup-py-deprecated.rst @@ -115,7 +115,7 @@ A possible replacement solution (among others) is to rely on setuptools-scm_: * ``python -m setuptools_scm`` -.. _setuptools-scm: https://setuptools-scm.readthedocs.io/en/latest/usage/#as-cli-tool +.. _setuptools-scm: https://setuptools-scm.readthedocs.io/en/latest/usage.html#as-cli-tool Remaining commands From daeac9dcd39f9bc3f7dcf44397b4912cd7d8559d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Ram=C3=ADrez=20Mondrag=C3=B3n?= Date: Wed, 6 Aug 2025 12:56:12 -0600 Subject: [PATCH 024/187] Update source/discussions/setup-py-deprecated.rst Co-authored-by: Alyssa Coghlan --- source/discussions/setup-py-deprecated.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/discussions/setup-py-deprecated.rst b/source/discussions/setup-py-deprecated.rst index dbea4ed52..b13ce190b 100644 --- a/source/discussions/setup-py-deprecated.rst +++ b/source/discussions/setup-py-deprecated.rst @@ -115,7 +115,7 @@ A possible replacement solution (among others) is to rely on setuptools-scm_: * ``python -m setuptools_scm`` -.. _setuptools-scm: https://setuptools-scm.readthedocs.io/en/latest/usage.html#as-cli-tool +.. _setuptools-scm: https://setuptools-scm.readthedocs.io/en/latest/usage#as-cli-tool Remaining commands From e1f29ae1486a5f55bd61359d8bdabf24da1bced3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Ram=C3=ADrez=20Mondrag=C3=B3n?= Date: Wed, 6 Aug 2025 14:04:07 -0600 Subject: [PATCH 025/187] Link to our own copy of the schema Co-authored-by: Alyssa Coghlan --- source/specifications/schemas/pylock.schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/specifications/schemas/pylock.schema.json b/source/specifications/schemas/pylock.schema.json index 5469111ec..90404e33d 100644 --- a/source/specifications/schemas/pylock.schema.json +++ b/source/specifications/schemas/pylock.schema.json @@ -1,6 +1,6 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://json.schemastore.org/pylock.json", + "$id": "https://packaging.python.org/en/latest/specifications/schemas/pylock.schema.json", "additionalProperties": false, "definitions": { "tool": { From 99299e312d93875fb37575732b9968a89ecfe07c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 7 Jul 2025 18:28:30 +0000 Subject: [PATCH 026/187] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/codespell-project/codespell: v2.3.0 → v2.4.1](https://github.com/codespell-project/codespell/compare/v2.3.0...v2.4.1) - [github.com/astral-sh/ruff-pre-commit: v0.7.1 → v0.12.2](https://github.com/astral-sh/ruff-pre-commit/compare/v0.7.1...v0.12.2) --- .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 db8b1131a..e092c419c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,7 +15,7 @@ repos: - id: trailing-whitespace - repo: https://github.com/codespell-project/codespell - rev: v2.3.0 + rev: v2.4.1 hooks: - id: codespell args: ["-L", "ned,ist,oder", "--skip", "*.po"] @@ -37,7 +37,7 @@ repos: - id: rst-inline-touching-normal - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.7.1 + rev: v0.12.2 hooks: - id: ruff - id: ruff-format From 00e971710a09c835a06e1268c174b720fc0aa53a Mon Sep 17 00:00:00 2001 From: Dustin Ingram Date: Thu, 21 Aug 2025 17:40:45 +0000 Subject: [PATCH 027/187] Correct regex for metadata 'name' format The current regex permits strings that end in the newline character, which is counter to what the description for the field states ("ASCII letters and numbers, period, underscore and hyphen"). This updates the rexex to use `\Z` instead of `$` to match at the end of the string and exclude newline characters. --- source/specifications/name-normalization.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/specifications/name-normalization.rst b/source/specifications/name-normalization.rst index ba3246b63..e295a3d11 100644 --- a/source/specifications/name-normalization.rst +++ b/source/specifications/name-normalization.rst @@ -17,7 +17,7 @@ underscore and hyphen. It must start and end with a letter or number. This means that valid project names are limited to those which match the following regex (run with :py:data:`re.IGNORECASE`):: - ^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$ + ^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])\Z .. _name-normalization: From fb63fa51d867197d98888d7978dba10449374b67 Mon Sep 17 00:00:00 2001 From: Dustin Ingram Date: Thu, 21 Aug 2025 17:53:46 +0000 Subject: [PATCH 028/187] Update regex from PEP 508 as well --- source/specifications/dependency-specifiers.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/specifications/dependency-specifiers.rst b/source/specifications/dependency-specifiers.rst index 06897da27..168d966d4 100644 --- a/source/specifications/dependency-specifiers.rst +++ b/source/specifications/dependency-specifiers.rst @@ -142,7 +142,7 @@ document we limit the acceptable values for identifiers to that regex. A full redefinition of name may take place in a future metadata PEP. The regex (run with re.IGNORECASE) is:: - ^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$ + ^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])\Z .. _dependency-specifiers-extras: From f86255b40639f1ed962496a465d67c16d443ce7d Mon Sep 17 00:00:00 2001 From: Dustin Ingram Date: Thu, 21 Aug 2025 18:33:17 +0000 Subject: [PATCH 029/187] Add history blurbs --- source/specifications/dependency-specifiers.rst | 3 +++ source/specifications/name-normalization.rst | 3 +++ 2 files changed, 6 insertions(+) diff --git a/source/specifications/dependency-specifiers.rst b/source/specifications/dependency-specifiers.rst index e1b69ff61..d9466c26e 100644 --- a/source/specifications/dependency-specifiers.rst +++ b/source/specifications/dependency-specifiers.rst @@ -526,6 +526,9 @@ History in use since late 2022. - April 2025: Added ``extras`` and ``dependency_groups`` for :ref:`lock-file-spec` as approved through :pep:`751`. +- 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) References diff --git a/source/specifications/name-normalization.rst b/source/specifications/name-normalization.rst index e295a3d11..560d956b5 100644 --- a/source/specifications/name-normalization.rst +++ b/source/specifications/name-normalization.rst @@ -53,3 +53,6 @@ History :pep:`503 <503#normalized-names>`. - November 2015: The specification of valid names was approved through :pep:`508 <508#names>`. +- 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) From 8290c3face8bf5d6580f07bb9892bcbb9af90b37 Mon Sep 17 00:00:00 2001 From: konstin Date: Mon, 25 Aug 2025 18:20:46 +0200 Subject: [PATCH 030/187] 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 031/187] 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 032/187] 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 033/187] 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 034/187] 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 035/187] 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 036/187] 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 037/187] 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 038/187] 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 039/187] 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 040/187] 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 041/187] 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 042/187] 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 043/187] 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 044/187] 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 045/187] 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 046/187] 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 047/187] 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 048/187] 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 049/187] 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 050/187] 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 051/187] 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 052/187] 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 053/187] 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 054/187] 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 055/187] 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 056/187] 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 057/187] 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 058/187] 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 059/187] 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 060/187] 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 061/187] [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 062/187] 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 063/187] 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 064/187] 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 065/187] 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 066/187] 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 067/187] [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 068/187] 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 069/187] [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 070/187] 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 071/187] 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 072/187] 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 073/187] 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 074/187] 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 075/187] 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 076/187] 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 077/187] 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 078/187] 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 079/187] 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 080/187] 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 081/187] 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 082/187] 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 083/187] 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 084/187] 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 085/187] 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 086/187] 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 087/187] 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 088/187] 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 52bb45f8997fd1b7c401e11e2b187f65d0fd02da Mon Sep 17 00:00:00 2001 From: Mahmoud Aziz <41173335+mahmoudadelaziz@users.noreply.github.com> Date: Sat, 4 Oct 2025 17:11:11 +0300 Subject: [PATCH 089/187] Update glossary.rst for accessibility (just added a hyperlink) Added a hyperlink to the "source tree" definition at its first occurrence in the Glossary, under the definition of a "Build Backend", for accessibility. --- source/glossary.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/glossary.rst b/source/glossary.rst index 6a592125f..91cda3ccd 100644 --- a/source/glossary.rst +++ b/source/glossary.rst @@ -14,7 +14,7 @@ Glossary Build Backend - A library that takes a source tree + A library that takes a :term:`source tree ` and builds a :term:`source distribution ` or :term:`built distribution ` from it. The build is delegated to the backend by a From 22d9ddf8899b615ee51fe46f0cd9dff8c108bcbf Mon Sep 17 00:00:00 2001 From: Benjamin Rodenberg Date: Thu, 6 Nov 2025 13:18:09 +0100 Subject: [PATCH 090/187] 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 091/187] 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 092/187] 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 093/187] [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 094/187] 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 095/187] 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 1301b443b4a95663779b8a2960a87a184da462db Mon Sep 17 00:00:00 2001 From: Dale Mcdiarmid Date: Thu, 6 Jun 2024 16:47:57 +0100 Subject: [PATCH 096/187] add clickpy for visualizing packages --- source/guides/analyzing-pypi-package-downloads.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/source/guides/analyzing-pypi-package-downloads.rst b/source/guides/analyzing-pypi-package-downloads.rst index 2ad02fed5..5da1608d5 100644 --- a/source/guides/analyzing-pypi-package-downloads.rst +++ b/source/guides/analyzing-pypi-package-downloads.rst @@ -333,6 +333,13 @@ Usage: The `pandas-gbq`_ project allows for accessing query results via `Pandas`_. +``ClickPy`` +----------- + +`ClickHouse`_, the popular open source database, provides a publicly available application for visualizing download statistics at `ClickPy `__. + +Users can directly query the underlying `ClickHouse instance `__, which is updated daily, with SQL for free. + References ========== @@ -346,3 +353,5 @@ References .. _google-cloud-bigquery: https://cloud.google.com/bigquery/docs/reference/libraries .. _pandas-gbq: https://pandas-gbq.readthedocs.io/en/latest/ .. _Pandas: https://pandas.pydata.org/ +.. _ClickHouse: https://github.com/ClickHouse/ClickHouse +.. _Clickpy: https://github.com/ClickHouse/ClickPy From 9f221301f6dfff1b1ce7ee6681da0db584e8b008 Mon Sep 17 00:00:00 2001 From: Lionel Palacin Date: Wed, 13 Aug 2025 09:53:23 +0100 Subject: [PATCH 097/187] Reduce ClickPy description to one sentence --- source/guides/analyzing-pypi-package-downloads.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/source/guides/analyzing-pypi-package-downloads.rst b/source/guides/analyzing-pypi-package-downloads.rst index 5da1608d5..ff596ca41 100644 --- a/source/guides/analyzing-pypi-package-downloads.rst +++ b/source/guides/analyzing-pypi-package-downloads.rst @@ -336,9 +336,7 @@ The `pandas-gbq`_ project allows for accessing query results via `Pandas`_. ``ClickPy`` ----------- -`ClickHouse`_, the popular open source database, provides a publicly available application for visualizing download statistics at `ClickPy `__. - -Users can directly query the underlying `ClickHouse instance `__, which is updated daily, with SQL for free. +The `ClickPy ` project provides a public application to visualize download statistics, with free direct SQL access to the underlying open-source `ClickHouse https://sql.clickhouse.com/?query_id=UEZEBJHYKTWDYXQZFMUT39`__ database, updated daily. References ========== From e8a8090a845cfb147ac574e20db088dd71280b9f Mon Sep 17 00:00:00 2001 From: Lionel Palacin Date: Wed, 13 Aug 2025 10:33:18 +0100 Subject: [PATCH 098/187] Fix reference errors + line-wrap --- source/guides/analyzing-pypi-package-downloads.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/source/guides/analyzing-pypi-package-downloads.rst b/source/guides/analyzing-pypi-package-downloads.rst index ff596ca41..2e2fdb583 100644 --- a/source/guides/analyzing-pypi-package-downloads.rst +++ b/source/guides/analyzing-pypi-package-downloads.rst @@ -336,7 +336,10 @@ The `pandas-gbq`_ project allows for accessing query results via `Pandas`_. ``ClickPy`` ----------- -The `ClickPy ` project provides a public application to visualize download statistics, with free direct SQL access to the underlying open-source `ClickHouse https://sql.clickhouse.com/?query_id=UEZEBJHYKTWDYXQZFMUT39`__ database, updated daily. +The `ClickPy`_ project provides a public application to visualize download +statistics, with free direct SQL access to the underlying open-source +`ClickHouse`_ database, updated daily. + References ========== @@ -352,4 +355,4 @@ References .. _pandas-gbq: https://pandas-gbq.readthedocs.io/en/latest/ .. _Pandas: https://pandas.pydata.org/ .. _ClickHouse: https://github.com/ClickHouse/ClickHouse -.. _Clickpy: https://github.com/ClickHouse/ClickPy +.. _Clickpy: https://clickpy.clickhouse.com/ From 9daa2ef1184a805e6634ab16f8bd6560cd1c5d2a Mon Sep 17 00:00:00 2001 From: Damian Shaw Date: Mon, 1 Dec 2025 20:30:45 -0500 Subject: [PATCH 099/187] 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 100/187] 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 101/187] 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 102/187] 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 103/187] 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 104/187] 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 ccf17ed7914851537c409dc6b97f95f2f0774072 Mon Sep 17 00:00:00 2001 From: Pradyun Gedam Date: Fri, 19 Dec 2025 12:07:22 +0000 Subject: [PATCH 105/187] Drop the opening note in pyproject-toml spec The history section covers this more accurately. --- source/specifications/pyproject-toml.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/source/specifications/pyproject-toml.rst b/source/specifications/pyproject-toml.rst index 48f35599e..20e055327 100644 --- a/source/specifications/pyproject-toml.rst +++ b/source/specifications/pyproject-toml.rst @@ -14,8 +14,6 @@ The ``pyproject.toml`` file acts as a configuration file for packaging-related tools (as well as other tools). -.. note:: This specification was originally defined in :pep:`518` and :pep:`621`. - The ``pyproject.toml`` file is written in `TOML `_. Three tables are currently specified, namely :ref:`[build-system] `, From 90034b530d029679155d3c7ce4ba50f8ade19aca Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Mon, 22 Dec 2025 17:33:14 -0500 Subject: [PATCH 106/187] 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 107/187] 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 108/187] [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 From b480162a172d91003ceda051d77edae9ce4d6061 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Tue, 6 Jan 2026 12:38:33 -0500 Subject: [PATCH 109/187] simple-repository-api: fix PEP 792 transcription error Signed-off-by: William Woodruff --- .../specifications/simple-repository-api.rst | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/source/specifications/simple-repository-api.rst b/source/specifications/simple-repository-api.rst index 3b9a2ccac..d317db6f7 100644 --- a/source/specifications/simple-repository-api.rst +++ b/source/specifications/simple-repository-api.rst @@ -477,16 +477,12 @@ The format of this URL is ``//`` where the ```` is replaced by name for that project, so a project named "Silly_Walk" would have a URL like ``/silly-walk/``. -This URL must respond with a JSON encoded dictionary that has four keys: +This URL must respond with a JSON encoded dictionary that has five keys: - ``name``: The normalized name of the project. -- ``files``: A list of dictionaries, each one representing an individual file. -- ``meta``: The general response metadata as `described earlier `__. +- ``project-status``: An optional dictionary, containing the following: - In addition to the general response metadata, the project detail ``meta`` - dictionary **MAY** also include the following: - - - ``project-status``: If present, this **MUST** be a valid project status marker. + - ``status``: If present, this **MUST** be a valid project status marker. .. note:: @@ -495,15 +491,21 @@ This URL must respond with a JSON encoded dictionary that has four keys: .. note:: - The ``project-status`` key was added with API version 1.4. + The ``status`` key was added with API version 1.4. - - ``project-status-reason``: If present, this **MUST** be an arbitrary string - description of the project status. + - ``reason``: If present, this **MUST** be an arbitrary string description + of the project status. .. note:: - The ``project-status-reason`` key was added with API version 1.4. + The ``reason`` key was added with API version 1.4. + + .. note:: + + The ``project-status`` key was added with API version 1.4. +- ``files``: A list of dictionaries, each one representing an individual file. +- ``meta``: The general response metadata as `described earlier `__. - ``versions``: A list of version strings specifying all of the project versions uploaded for this project. The value of ``versions`` is logically a set, and as such may not contain duplicates, and the order of the versions is From 0b95c27e9e3fe5fef324c8743b3cad46bad25910 Mon Sep 17 00:00:00 2001 From: Alyssa Coghlan Date: Sat, 10 Jan 2026 16:33:29 +1000 Subject: [PATCH 110/187] Attempt to clarify environment marker evaluation Preparation for the release of packaging 25.1 revealed multiple deficiencies in the specification of environment marker evaluation. Review of the proposed amendments to resolve those deficiencies highlighted multiple other problems, including some dating from the original PEP 508 specification: * other pages still referencing PEP 508 instead of the living spec * direct reference to PEP 685 instead of the core metadata spec * the "extra" special case not being properly defined * lacking guidance to tool developers regarding what should be considered errors to disallow entirely vs issues to work around Inspired by the initial PR at #1971 --- source/specifications/core-metadata.rst | 2 +- source/specifications/dependency-groups.rst | 4 +- .../specifications/dependency-specifiers.rst | 288 +++++++++++++----- source/specifications/pyproject-toml.rst | 12 +- 4 files changed, 215 insertions(+), 91 deletions(-) diff --git a/source/specifications/core-metadata.rst b/source/specifications/core-metadata.rst index eb9a03ff6..b8df0f068 100644 --- a/source/specifications/core-metadata.rst +++ b/source/specifications/core-metadata.rst @@ -574,7 +574,7 @@ The format of a requirement string contains from one to four parts: * An environment marker after a semicolon. This means that the requirement is only needed in the specified conditions. -See :pep:`508` for full details of the allowed format. +See :ref:`dependency-specifiers` for full details of the allowed format. The project names should correspond to names as found on the `Python Package Index`_. diff --git a/source/specifications/dependency-groups.rst b/source/specifications/dependency-groups.rst index a35afb475..2fa82cd90 100644 --- a/source/specifications/dependency-groups.rst +++ b/source/specifications/dependency-groups.rst @@ -209,8 +209,8 @@ The output is therefore valid ``requirements.txt`` data. realized_group = [] for item in raw_group: if isinstance(item, str): - # packaging.requirements.Requirement parsing ensures that this is a valid - # PEP 508 Dependency Specifier + # packaging.requirements.Requirement parsing ensures that this + # is a valid dependency specifier # raises InvalidRequirement on failure Requirement(item) realized_group.append(item) diff --git a/source/specifications/dependency-specifiers.rst b/source/specifications/dependency-specifiers.rst index 99886563c..5392f3d18 100644 --- a/source/specifications/dependency-specifiers.rst +++ b/source/specifications/dependency-specifiers.rst @@ -6,21 +6,25 @@ Dependency specifiers ===================== -This document describes the dependency specifiers format as originally specified -in :pep:`508`. +This document defines the format used to specify dependencies on other projects. +The language defined is a compact line based format which was adapted from the +format originally used in ``pip`` requirements files. The job of a dependency is to enable tools like pip [#pip]_ to find the right package to install. Sometimes this is very loose - just specifying a name, and sometimes very specific - referring to a specific file to install. Sometimes -dependencies are only relevant in one platform, or only some versions are +dependencies are only relevant on one platform, or only some versions are acceptable, so the language permits describing all these cases. -The language defined is a compact line based format which is already in -widespread use in pip requirements files, though we do not specify the command -line option handling that those files permit. There is one caveat - the -URL reference form, specified in :ref:`Versioning specifier specification ` -is not actually implemented in pip, but we use that format rather -than pip's current native format. +Whether tools should be strict or permissive in their processing of dependency +specifiers is largely dependent on the role of the tool in the wider ecosystem: + +* publishing tools and index servers SHOULD be strict in their processing for + new releases, encouraging the consistency of published specifiers to improve + over time +* locking and installation tools MAY be permissive in their processing, allowing + consumption of older packages which may contain dependency specifiers that are + arguably nonsensical Specification ============= @@ -30,7 +34,7 @@ Examples All features of the language shown with a name based lookup:: - requests [security,tests] >= 2.8.1, == 2.8.* ; python_version < "2.7" + requests [security,tests] >= 2.8.1, == 2.8.* ; python_version < "3.7" A minimal URL based lookup:: @@ -108,8 +112,6 @@ field:: extras_list = identifier (wsp* ',' wsp* identifier)* extras = '[' wsp* extras_list? wsp* ']' -Restrictions on names for extras is defined in :pep:`685`. - Giving us a rule for name based requirements:: name_req = name wsp* extras? wsp* versionspec? wsp* quoted_marker? @@ -126,23 +128,22 @@ Whitespace ---------- Non line-breaking whitespace is mostly optional with no semantic meaning. The -sole exception is detecting the end of a URL requirement. +sole exceptions are detecting the end of a URL requirement and inside user +supplied constants in environment markers. .. _dependency-specifiers-names: Names ----- -Python distribution names are currently defined in :pep:`345`. Names -act as the primary identifier for distributions. They are present in all +Distribution names are defined in the :ref:`Core metadata `. +Names act as the primary identifier for distributions. They are present in all dependency specifications, and are sufficient to be a specification on their -own. However, PyPI places strict restrictions on names - they must match a -case insensitive regex or they won't be accepted. Accordingly, in this -document we limit the acceptable values for identifiers to that regex. A full -redefinition of name may take place in a future metadata PEP. The regex (run -with re.IGNORECASE) is:: +own. + +Valid distribution names are defined in the :ref:`name format specification +`. - ^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])\Z .. _dependency-specifiers-extras: @@ -163,6 +164,12 @@ are listed in the "security" extra of requests. If multiple extras are listed, all the dependencies are unioned together. +Restrictions on names for extras are defined in the +:ref:`Core metadata specification `. Publication +tools SHOULD enforce these restrictions in dependency specifiers, while locking +and installation tools MAY normalize invalid extra names in order to accept +published metadata using core metadata versions prior to 2.3. + .. _dependency-specifiers-versions: Versions @@ -172,7 +179,7 @@ See the :ref:`Version specifier specification ` for more detail on both version numbers and version comparisons. Version specifications limit the versions of a distribution that can be used. They only apply to distributions looked up by name, rather than -via a URL. Version comparison are also used in the markers feature. The +via a URL. Version comparisons are also used in environment markers. The optional brackets around a version are present for compatibility with :pep:`345` but should not be generated, only accepted. @@ -183,63 +190,140 @@ Environment Markers Environment markers allow a dependency specification to provide a rule that describes when the dependency should be used. For instance, consider a package -that needs argparse. In Python 2.7 argparse is always present. On older Python -versions it has to be installed as a dependency. This can be expressed as so:: +that needs ``pywin32`` when running on Windows. This can be expressed as:: - argparse;python_version<"2.7" + pywin32; sys_platform == "win32" -A marker expression evaluates to either True or False. When it evaluates to -False, the dependency specification should be ignored. +A marker expression evaluates to either True or False for a given deployment +environment. When it evaluates to False, the dependency should be ignored. The marker language is inspired by Python itself, chosen for the ability to safely evaluate it without running arbitrary code that could become a security -vulnerability. Markers were first standardised in :pep:`345`. This document -fixes some issues that were observed in the design described in :pep:`426`. - -Comparisons in marker expressions are typed by the comparison operator and the -type of the marker value. The operators that are not in - perform the same as they do for strings or sets in Python based on -whether the marker value is a string or set itself. The operators -use the version comparison rules of the -:ref:`Version specifier specification ` when those are -defined (that is when both sides have a valid version specifier). If there is no -defined behaviour of this specification and the operator exists in Python, then -the operator falls back to the Python behaviour for the types involved. -Otherwise an error should be raised. e.g. the following will result in errors:: - - "dog" ~= "fred" - python_version ~= "surprise" - -User supplied constants are always encoded as strings with either ``'`` or -``"`` quote marks. Note that backslash escapes are not defined, but existing -implementations do support them. They are not included in this -specification because they add complexity and there is no observable need for -them today. Similarly we do not define non-ASCII character support: all the -runtime variables we are referencing are expected to be ASCII-only. - -The variables in the marker grammar such as "os_name" resolve to values looked -up in the Python runtime. With the exception of "extra" all values are defined -on all Python versions today - it is an error in the implementation of markers -if a value is not defined. - -Unknown variables must raise an error rather than resulting in a comparison -that evaluates to True or False. +vulnerability. + +Markers were first defined in :pep:`345`, formally specified in :pep:`508`, +then subsequently amended over time (amendments since :pep:`508` are recorded +:ref:`at the end of this specification `). + +Marker field types +'''''''''''''''''' + +Environment marker fields are each defined as one of the following types: + +* ``String``: the contents of the field are always treated as an opaque string. +* ``Set of strings``: the contents of the field are always treated as a set + containing opaque strings. In comparisons, the user supplied constant MUST + still be a single string (as set literals are not part of the marker syntax). +* ``Version``: the contents of the field are always expected to be a valid + :ref:`version specifier `. Publishing tools SHOULD emit + an error if that is not the case, but installation tools MAY fall back to + treating the field as a string field. +* ``Version | String``: the contents of the field are expected to be a valid + :ref:`version specifier ` on some platforms, but an + opaque string on others. The specifics of this distinction are field dependent + and whether or not tools actually make the distinction will be tool dependent. + +Marker comparisons +'''''''''''''''''' + +All marker comparison expressions are expected to compare a named marker field +against a given user supplied constant. The type of the comparison is determined +by the comparison operator used and the type of the named field as given +in :ref:`the table below `. Tools MAY emit an +error if no marker field is referenced in a comparison (that is, both operands +are given as constants). + +The follow comparison operations are defined in the marker expression grammar: + +* ``==`` (for example, ``sys_platform == "win32"``) +* ``!=`` (for example, ``sys_platform != "win32"``) +* ``>`` (for example, ``python_version > "3.10"``) +* ``>=`` (for example, ``python_version >= "3.10"``) +* ``<`` (for example, ``python_version < "3.10"``) +* ``<=`` (for example, ``python_version <= "3.10"``) +* ``~=`` (for example, ``python_version ~= "3"``) +* ``===`` (for example, ``implementation_version === "not.a.valid.version"``) +* ``in`` (for example, ``"gui" in extras``) +* ``not in`` (for example, ``"dev" not in dependency_groups``) + +For ``String`` fields, ``==``, ``!=``, ``in``, and ``not in`` are defined as +they are for Python strings (case sensitive, with no value normalization of any +kind). The use of ``~=`` or ``===`` with string fields is +explicitly discouraged, and publishing tools SHOULD emit an error, while locking +and installation tools MAY instead interpret them as equivalent to ``==``. The +use of ordered comparisons (``<``, ``<=``, ``>``, ``>=``) with string fields is +explicitly discouraged (as it makes no semantic sense in the packaging context), +and publishing tools SHOULD emit an error, while locking and installation tools +SHOULD implement the following behavior: + +* treat ``>=`` and ``<=`` as equivalent to ``==`` +* treat ``>`` and ``<`` as always being False + +For ``Set of String`` fields, as there is no marker syntax for set literals, +the only valid operations are ``in`` and ``not in`` comparisons with a user +supplied string literal as the left operand. + +For ``Version`` fields, the comparison operations are defined by the +:ref:`Version specifier specification ` when either both +the marker field value and the user supplied constant can be parsed as valid +version specifiers or the ``===`` arbitrary equivalence comparison operator +is used. When an operator other than ``===`` is used, publishing tools SHOULD +emit an error if the user supplied constant cannot be parsed as a valid version +specifier, while locking and installation tools MAY either emit an error or else +fall back to ``String`` field comparison logic if either the marker field value +or the user supplied constant cannot be parsed as a valid version specifier. + +For ``Version | String`` fields, comparison operations are defined as they are +for ``Version`` fields. However, there is no expectation that the parsing of +the marker field value or the user supplied constant as a valid version will +succeed, so tools MUST fall back to processing the field as a ``String`` field. +Alternatively, tools MAY unconditionally treat such fields as ``String`` fields. + +Composing marker expressions +'''''''''''''''''''''''''''' + +More complex marker expressions may be composed using the ``and`` and ``or`` +logical operators. Parentheses may be used as necessary to control operand +precedence (with all comparison operations having a higher precedence). + +Python's comparison chaining (such as ``3.4 < python_version < 3.9``) is NOT +supported in environment markers. + +User supplied constants +''''''''''''''''''''''' + +User supplied constants are always given as strings within either ``'`` or +``"`` quote marks. Triple-quoted multi-line strings are NOT permitted. + +Backslash escapes are not specified, although tools MAY support them. +They are not included in the specification because they add complexity and +there is currently no known need for treating user supplied constants as +anything other than either opaque strings or valid version specifiers. + +Similarly, non-ASCII character support is not specified, but tools MAY accept +them (usually based on the text encoding of the file or stream containing the +dependency specifier). This may be revisited in the future if it becomes more +common for the runtime variables typically referenced in environment markers to +contain non-ASCII text that users wish to perform comparisons against. + +Unknown marker fields +''''''''''''''''''''' + +References to unknown marker fields MUST raise an error rather than resulting +in a comparison that evaluates to True or False. Variables whose value cannot be calculated on a given Python implementation -should evaluate to ``0`` for versions, and an empty string for all other -variables. +should evaluate to ``0`` for ``Version`` fields, and an empty string for all +other variables (including ``Version | String`` fields). + +.. _dependency-specifiers-environment-marker-fields: +.. _environment-marker-fields: -The "extra" variable is special. It is used by wheels to signal which -specifications apply to a given extra in the wheel ``METADATA`` file, but -since the ``METADATA`` file is based on a draft version of :pep:`426`, there is -no current specification for this. Regardless, outside of a context where this -special handling is taking place, the "extra" variable should result in an -error like all other unknown variables. +Defined environment marker fields +''''''''''''''''''''''''''''''''' -The "extras" and "dependency_groups" variables are also special. They are used -to specify any requested extras or dependency groups when installing from a lock -file. Outside of the context of lock files, these two variables should result in -an error like all other unknown variables. +Unless otherwise noted below, marker evaluation environments MUST support all +of the following marker fields: .. list-table:: :header-rows: 1 @@ -267,7 +351,7 @@ an error like all other unknown variables. - ``CPython``, ``Jython`` * - ``platform_release`` - :py:func:`platform.release()` - - String + - Version | String - ``3.14.1-x86_64-linode39``, ``14.5.0``, ``1.8.0_51`` * - ``platform_system`` - :py:func:`platform.system()` @@ -296,21 +380,46 @@ an error like all other unknown variables. - :ref:`Version ` - ``3.4.0``, ``3.5.0b1`` * - ``extra`` - - An error except when defined by the context interpreting the - specification. - - String + - Used to indicate optional dependencies in project dependency metadata. + An error except when defined by the context interpreting the + specifier. Publishing tools SHOULD permit use of this field. + - Special (see below) - ``toml`` * - ``extras`` - - An error except when defined by the context interpreting the - specification. + - Used to indicate optional public dependencies in lock files. An error + except when defined by the context interpreting the specifier. + Publishing tools SHOULD NOT permit use of this field. - Set of strings - ``{"toml"}`` * - ``dependency_groups`` - - An error except when defined by the context interpreting the - specification. + - Used to indicate optional project internal dependencies in lock files. + An error except when defined by the context interpreting the + specifier. Publishing tools SHOULD NOT permit use of this field. - Set of strings - ``{"test"}`` +For backwards compatibility with older locking and installation tools, the +``extras`` and ``dependency_groups`` fields are currently only considered +valid in :ref:`lock files ` (where they allow consumers of the +lock file to selectively install optional parts of the locked dependency tree). +Publishing tools SHOULD emit an error if projects attempt to use them in their +published metadata, and index servers SHOULD NOT accept uploads referencing +these fields. Outside lock file processing, marker evaluation environments +DO NOT need to define these fields. + +The ``extra`` field is also special, as it expects set-like behaviour, but +predates the addition of ``Set of strings`` as a defined marker field type. +Accordingly, for this field only, ``extra == "name"`` is equivalent to +``"name" in extras``, while ``extra != "name"`` is equivalent to +``"name" not in extras``. Other comparison operations on ``extra`` are not +defined and publishing tools SHOULD emit an error, while locking and +installation tools may evaluate them as False. Unlike the newer ``extras`` +field, this field SHOULD be accepted by both publishing tools and index +servers. Marker evaluation environments intended for project dependency +declarations will typically need to handle evaluation of ``extra`` field +comparisons, while other evaluations of environment markers will not generally +need to do so. + The ``implementation_version`` marker variable is derived from :py:data:`sys.implementation.version `: @@ -328,9 +437,6 @@ The ``implementation_version`` marker variable is derived from else: implementation_version = "0" -This environment markers section, initially defined through :pep:`508`, supersedes the environment markers -section in :pep:`345`. - .. _dependency-specifiers-grammar: Complete Grammar @@ -512,6 +618,8 @@ A test program - if the grammar is in a string ``grammar``: print("%s -> %s" % (test, parsed)) +.. _dependency-specifier-history: + History ======= @@ -521,16 +629,27 @@ History ``'.'.join(platform.python_version_tuple()[:2])``, to accommodate potential future versions of Python with 2-digit major and minor versions (e.g. 3.10). [#future_versions]_ +- March 2022: Standardised the normalization of extra names at publication time + (for core metadata 2.3 and later) through :pep:`685` - June 2024: The definition of ``version_many`` was changed to allow trailing commas, matching with the behavior of the Python implementation that has been in use since late 2022. -- April 2025: Added ``extras`` and ``dependency_groups`` for +- April 2025: Added ``extras`` and ``dependency_groups`` marker field for :ref:`lock-file-spec` as approved through :pep:`751`. - 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 +- December 2025: Ensure ``===`` is before ``==`` in grammar, to allow arbitrary equality comparisons to be parsed. +- January 2026: Amend the definition of environment marker comparison operations + to restrict version comparison semantics to fields where they make sense, + make extra name restrictions more explicit, adjust the way ordered comparisons + are defined for strings, and make the fallback from version comparisons to + string comparisons when version parsing fails optional. Also provide different + tool behaviour recommendations for publishing tools vs installation tools. + This brought the nominal specification into line with the way tools actually + work. [#marker_comparison_logic]_ +- January 2026: fix outdated references inadvertently retained from :pep:`508` References @@ -546,6 +665,9 @@ References definition of Environment Marker Variable ``python_version`` (https://github.com/python/peps/issues/560) +.. [#marker_comparison_logic] Resolving inconsistencies between actual tool + behavior and the nominal definitions of environment marker field comparisons + (https://discuss.python.org/t/spec-change-bugfix-dependency-specifiers-simplification-pep-508/105203) .. _python-version-change: https://mail.python.org/pipermail/distutils-sig/2018-January/031920.html diff --git a/source/specifications/pyproject-toml.rst b/source/specifications/pyproject-toml.rst index 48f35599e..4f35bdd81 100644 --- a/source/specifications/pyproject-toml.rst +++ b/source/specifications/pyproject-toml.rst @@ -454,8 +454,8 @@ be ambiguous in the face of ``[project.scripts]`` and ``dependencies``/``optional-dependencies`` ------------------------------------------ -- TOML_ type: Array of :pep:`508` strings (``dependencies``), and a - table with values of arrays of :pep:`508` strings +- TOML_ type: Array of :ref:`dependency-specifiers` strings (``dependencies``), + and a table with values of arrays of :ref:`dependency-specifiers` strings (``optional-dependencies``) - Corresponding :ref:`core metadata ` field: :ref:`Requires-Dist ` and @@ -465,12 +465,14 @@ The (optional) dependencies of the project. For ``dependencies``, it is a key whose value is an array of strings. Each string represents a dependency of the project and MUST be -formatted as a valid :pep:`508` string. Each string maps directly to -a :ref:`Requires-Dist ` entry. +formatted as a valid :ref:`dependency-specifiers` string. +Each string maps directly to a +:ref:`Requires-Dist ` entry. For ``optional-dependencies``, it is a table where each key specifies an extra and whose value is an array of strings. The strings of the -arrays must be valid :pep:`508` strings. The keys MUST be valid values +arrays must be valid :ref:`dependency-specifiers` strings. +The keys MUST be valid values for :ref:`Provides-Extra `. Each value in the array thus becomes a corresponding :ref:`Requires-Dist ` entry for the From 28d4b58655e43f55028e5ca2b70a7327ced4d7d1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 10 Jan 2026 06:38:07 +0000 Subject: [PATCH 111/187] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- source/specifications/dependency-specifiers.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/specifications/dependency-specifiers.rst b/source/specifications/dependency-specifiers.rst index 5392f3d18..c86b2e047 100644 --- a/source/specifications/dependency-specifiers.rst +++ b/source/specifications/dependency-specifiers.rst @@ -218,7 +218,7 @@ Environment marker fields are each defined as one of the following types: :ref:`version specifier `. Publishing tools SHOULD emit an error if that is not the case, but installation tools MAY fall back to treating the field as a string field. -* ``Version | String``: the contents of the field are expected to be a valid +* ``Version | String``: the contents of the field are expected to be a valid :ref:`version specifier ` on some platforms, but an opaque string on others. The specifics of this distinction are field dependent and whether or not tools actually make the distinction will be tool dependent. From 472320a71b654a010eca52359bf3daa159814473 Mon Sep 17 00:00:00 2001 From: github-merge-queue <118344674+github-merge-queue@users.noreply.github.com> Date: Mon, 19 Jan 2026 06:14:20 +0000 Subject: [PATCH 112/187] Update uv_build version to 0.9.26 --- 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 64ef0bf2f..d49d41108 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.21, <0.10.0"] + requires = ["uv_build >= 0.9.26, <0.10.0"] build-backend = "uv_build" From fd2c2e2752ff9255ce5ee6cb8181627281cf9248 Mon Sep 17 00:00:00 2001 From: Alyssa Coghlan Date: Sat, 24 Jan 2026 21:10:00 +1000 Subject: [PATCH 113/187] Updates from my own PR review --- source/specifications/core-metadata.rst | 4 +- .../specifications/dependency-specifiers.rst | 16 +++++- source/specifications/entry-points.rst | 3 +- source/specifications/pyproject-toml.rst | 49 +++++++++++++------ 4 files changed, 52 insertions(+), 20 deletions(-) diff --git a/source/specifications/core-metadata.rst b/source/specifications/core-metadata.rst index b8df0f068..50b0660aa 100644 --- a/source/specifications/core-metadata.rst +++ b/source/specifications/core-metadata.rst @@ -574,14 +574,14 @@ The format of a requirement string contains from one to four parts: * An environment marker after a semicolon. This means that the requirement is only needed in the specified conditions. -See :ref:`dependency-specifiers` for full details of the allowed format. - The project names should correspond to names as found on the `Python Package Index`_. Version specifiers must follow the rules described in :doc:`version-specifiers`. +See :ref:`dependency-specifiers` for full details of the allowed format. + Examples:: Requires-Dist: pkginfo diff --git a/source/specifications/dependency-specifiers.rst b/source/specifications/dependency-specifiers.rst index c86b2e047..226f004c9 100644 --- a/source/specifications/dependency-specifiers.rst +++ b/source/specifications/dependency-specifiers.rst @@ -243,7 +243,7 @@ The follow comparison operations are defined in the marker expression grammar: * ``<=`` (for example, ``python_version <= "3.10"``) * ``~=`` (for example, ``python_version ~= "3"``) * ``===`` (for example, ``implementation_version === "not.a.valid.version"``) -* ``in`` (for example, ``"gui" in extras``) +* ``in`` (for example, ``"gui" in extras``, ``"SMP" in platform_version``) * ``not in`` (for example, ``"dev" not in dependency_groups``) For ``String`` fields, ``==``, ``!=``, ``in``, and ``not in`` are defined as @@ -272,12 +272,17 @@ emit an error if the user supplied constant cannot be parsed as a valid version specifier, while locking and installation tools MAY either emit an error or else fall back to ``String`` field comparison logic if either the marker field value or the user supplied constant cannot be parsed as a valid version specifier. +Note that ``in`` and ``not in`` containment checks are NOT valid for ``Version`` +fields. For ``Version | String`` fields, comparison operations are defined as they are for ``Version`` fields. However, there is no expectation that the parsing of the marker field value or the user supplied constant as a valid version will succeed, so tools MUST fall back to processing the field as a ``String`` field. Alternatively, tools MAY unconditionally treat such fields as ``String`` fields. +Accordingly, comparisons that rely on these fields being processed as +``Version`` field SHOULD NOT be used in environment markers published to public +index servers, but they may be appropriate in more constrained environments. Composing marker expressions '''''''''''''''''''''''''''' @@ -286,8 +291,15 @@ More complex marker expressions may be composed using the ``and`` and ``or`` logical operators. Parentheses may be used as necessary to control operand precedence (with all comparison operations having a higher precedence). +For example:: + + sys_platform == "ios" or sys_platform == "darwin" + sys_platform == "linux" and "SMP" in platform_version + sys_platform == "darwin" and platform_version >= "12" + Python's comparison chaining (such as ``3.4 < python_version < 3.9``) is NOT -supported in environment markers. +supported in environment markers (such expressions must instead be written out +as two separate comparisons joined by ``and``). User supplied constants ''''''''''''''''''''''' diff --git a/source/specifications/entry-points.rst b/source/specifications/entry-points.rst index dea039492..102d694f1 100644 --- a/source/specifications/entry-points.rst +++ b/source/specifications/entry-points.rst @@ -106,8 +106,7 @@ Within a value, readers must accept and ignore spaces (including multiple consecutive spaces) before or after the colon, between the object reference and the left square bracket, between the extra names and the square brackets and colons delimiting them, and after the right square bracket. The syntax for -extras is formally specified as part of :pep:`508` (as ``extras``) and -restrictions on values specified in :pep:`685`. +extras is formally specified in :ref:`dependency-specifiers`. For tools writing the file, it is recommended only to insert a space between the object reference and the left square bracket. diff --git a/source/specifications/pyproject-toml.rst b/source/specifications/pyproject-toml.rst index 4f35bdd81..67cbb71c5 100644 --- a/source/specifications/pyproject-toml.rst +++ b/source/specifications/pyproject-toml.rst @@ -449,29 +449,45 @@ be ambiguous in the face of ``[project.scripts]`` and .. _pyproject-toml-dependencies: -.. _pyproject-toml-optional-dependencies: -``dependencies``/``optional-dependencies`` ------------------------------------------- +``dependencies`` +---------------- -- TOML_ type: Array of :ref:`dependency-specifiers` strings (``dependencies``), - and a table with values of arrays of :ref:`dependency-specifiers` strings - (``optional-dependencies``) +- TOML_ type: Array of :ref:`dependency specifier ` + strings (``dependencies``) - Corresponding :ref:`core metadata ` field: - :ref:`Requires-Dist ` and - :ref:`Provides-Extra ` + :ref:`Requires-Dist ` -The (optional) dependencies of the project. +``dependencies`` lists the expected dependencies of the project as an +array of strings. -For ``dependencies``, it is a key whose value is an array of strings. Each string represents a dependency of the project and MUST be -formatted as a valid :ref:`dependency-specifiers` string. +formatted as a valid :ref:`dependency specifier `. + Each string maps directly to a :ref:`Requires-Dist ` entry. -For ``optional-dependencies``, it is a table where each key specifies -an extra and whose value is an array of strings. The strings of the -arrays must be valid :ref:`dependency-specifiers` strings. +Dependencies listed in this array are always considered +for installation, but may still contain environment markers that cause them +to be skipped in some environments. + + +.. _pyproject-toml-optional-dependencies: + +``optional-dependencies`` +------------------------- + +- TOML_ type: table with string keys mapping to arrays of + :ref:`dependency specifier ` strings (``optional-dependencies``) +- Corresponding :ref:`core metadata ` fields: + :ref:`Requires-Dist ` and + :ref:`Provides-Extra ` + +``optional-dependencies`` is a table where each key specifies +an extra and whose value is an array of strings using the same format as the +``dependencies`` array (the strings in the +arrays must be valid :ref:`dependency specifiers `). + The keys MUST be valid values for :ref:`Provides-Extra `. Each value in the array thus becomes a corresponding @@ -479,6 +495,11 @@ in the array thus becomes a corresponding matching :ref:`Provides-Extra ` metadata. +The optionality of these dependencies is recorded by modifying the environment +marker clause on the related ``Requires-Dist`` entries to check the extra name. +Optional dependencies are thus only considered for installation if installation +if the associated extra name is requested. + .. _pyproject-toml-import-names: From a50bb27da10b84d8c364138b4dd990b9741b098b Mon Sep 17 00:00:00 2001 From: Alyssa Coghlan Date: Sat, 24 Jan 2026 21:23:49 +1000 Subject: [PATCH 114/187] Use string containment on version-or-string fields --- .../specifications/dependency-specifiers.rst | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/source/specifications/dependency-specifiers.rst b/source/specifications/dependency-specifiers.rst index 226f004c9..dbc441f99 100644 --- a/source/specifications/dependency-specifiers.rst +++ b/source/specifications/dependency-specifiers.rst @@ -273,16 +273,18 @@ specifier, while locking and installation tools MAY either emit an error or else fall back to ``String`` field comparison logic if either the marker field value or the user supplied constant cannot be parsed as a valid version specifier. Note that ``in`` and ``not in`` containment checks are NOT valid for ``Version`` -fields. +fields and publishing tools SHOULD emit an error, while locking and installation +tools MAY treat them as always being False. For ``Version | String`` fields, comparison operations are defined as they are -for ``Version`` fields. However, there is no expectation that the parsing of -the marker field value or the user supplied constant as a valid version will -succeed, so tools MUST fall back to processing the field as a ``String`` field. -Alternatively, tools MAY unconditionally treat such fields as ``String`` fields. -Accordingly, comparisons that rely on these fields being processed as -``Version`` field SHOULD NOT be used in environment markers published to public -index servers, but they may be appropriate in more constrained environments. +for ``Version`` fields, while ``in`` and ``not in`` containment checks are +defined as they are for ``String`` fields. However, there is no expectation +that the parsing of the marker field value or the user supplied constant as a +valid version will succeed, so tools MUST fall back to processing the field as +a ``String`` field. Alternatively, tools MAY unconditionally treat such fields +as ``String`` fields. Due to this potential for variation across clients, +comparisons that rely on these fields being processed as ``Version`` fields +SHOULD NOT be used in environment markers published to public index servers. Composing marker expressions '''''''''''''''''''''''''''' From 2cc070165f3219f915a1ff3cb50be7f36ac11ec3 Mon Sep 17 00:00:00 2001 From: Alyssa Coghlan Date: Sat, 24 Jan 2026 21:30:41 +1000 Subject: [PATCH 115/187] Fix marker field in macOS release check --- source/specifications/dependency-specifiers.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/specifications/dependency-specifiers.rst b/source/specifications/dependency-specifiers.rst index dbc441f99..a424cdc39 100644 --- a/source/specifications/dependency-specifiers.rst +++ b/source/specifications/dependency-specifiers.rst @@ -297,7 +297,7 @@ For example:: sys_platform == "ios" or sys_platform == "darwin" sys_platform == "linux" and "SMP" in platform_version - sys_platform == "darwin" and platform_version >= "12" + sys_platform == "darwin" and platform_release >= "12" Python's comparison chaining (such as ``3.4 < python_version < 3.9``) is NOT supported in environment markers (such expressions must instead be written out From bc46f2d79bea6b556d8bfd09ce5ffddb78fa022f Mon Sep 17 00:00:00 2001 From: Alyssa Coghlan Date: Sat, 24 Jan 2026 21:43:43 +1000 Subject: [PATCH 116/187] Add history entries to pages with updated links --- source/specifications/core-metadata.rst | 3 +++ source/specifications/dependency-specifiers.rst | 3 ++- source/specifications/entry-points.rst | 2 ++ source/specifications/pyproject-toml.rst | 3 +++ 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/source/specifications/core-metadata.rst b/source/specifications/core-metadata.rst index 50b0660aa..0cd05f9fa 100644 --- a/source/specifications/core-metadata.rst +++ b/source/specifications/core-metadata.rst @@ -1071,6 +1071,9 @@ History - October 2025: Clarified that ``License-Expression`` applies to the containing distribution file and not the project itself. +- January 2026: Replaced outdated direct reference to :pep:`508` with a + reference to :ref:`dependency-specifiers`. + ---- .. [1] reStructuredText markup: diff --git a/source/specifications/dependency-specifiers.rst b/source/specifications/dependency-specifiers.rst index a424cdc39..9824815e5 100644 --- a/source/specifications/dependency-specifiers.rst +++ b/source/specifications/dependency-specifiers.rst @@ -663,7 +663,8 @@ History tool behaviour recommendations for publishing tools vs installation tools. This brought the nominal specification into line with the way tools actually work. [#marker_comparison_logic]_ -- January 2026: fix outdated references inadvertently retained from :pep:`508` +- January 2026: fix outdated references to other documents that were + inadvertently retained from :pep:`508` References diff --git a/source/specifications/entry-points.rst b/source/specifications/entry-points.rst index 102d694f1..9e59862aa 100644 --- a/source/specifications/entry-points.rst +++ b/source/specifications/entry-points.rst @@ -165,6 +165,8 @@ History - October 2017: This specification was written to formalize the existing entry points feature of setuptools (discussion_). +- January 2026: Replaced outdated direct references to :pep:`508` and + :pep:`685` with a reference to :ref:`dependency-specifiers`. .. _discussion: https://mail.python.org/pipermail/distutils-sig/2017-October/031585.html diff --git a/source/specifications/pyproject-toml.rst b/source/specifications/pyproject-toml.rst index 67cbb71c5..3b1954ce0 100644 --- a/source/specifications/pyproject-toml.rst +++ b/source/specifications/pyproject-toml.rst @@ -672,4 +672,7 @@ History - October 2025: The ``import-names`` and ``import-namespaces`` keys were added through :pep:`794`. +- January 2026: Replaced outdated direct reference to :pep:`508` with a + reference to :ref:`dependency-specifiers`. + .. _TOML: https://toml.io From 7babaa7f994ff75948a3426ef9e0f4f50cd3fe38 Mon Sep 17 00:00:00 2001 From: konstin Date: Tue, 27 Jan 2026 22:37:05 +0100 Subject: [PATCH 117/187] PEP 815: Deprecate `RECORD.jws` and `RECORD.p7s` Implement PEP 815: Deprecate `RECORD.jws` and `RECORD.p7s` The changes retain the information about signature files to the extend that a post-PEP 815 installer needs to be aware of them (not mentioned in `RECORD`), and informs build backend authors that these files must not be created anymore. The remaining information on signature files, now irrelevant, is removed. --- .../binary-distribution-format.rst | 94 ++----------------- 1 file changed, 10 insertions(+), 84 deletions(-) diff --git a/source/specifications/binary-distribution-format.rst b/source/specifications/binary-distribution-format.rst index 8bb41ab40..17e7bd062 100644 --- a/source/specifications/binary-distribution-format.rst +++ b/source/specifications/binary-distribution-format.rst @@ -240,18 +240,17 @@ The .dist-info directory secure hashes. Unlike PEP 376, every file except RECORD, which cannot contain a hash of itself, must include its hash. The hash algorithm must be sha256 or better; specifically, md5 and sha1 are - not permitted, as signed wheel files rely on the strong hashes in - RECORD to validate the integrity of the archive. + not permitted. #. PEP 376's INSTALLER and REQUESTED are not included in the archive. -#. RECORD.jws is used for digital signatures. It is not mentioned in - RECORD. -#. RECORD.p7s is allowed as a courtesy to anyone who would prefer to - use S/MIME signatures to secure their wheel files. It is not - mentioned in RECORD. +#. RECORD.jws and RECORD.p7s are deprecated. Where they are still + used, neither RECORD.jws nor RECORD.p7s are mentioned in RECORD. + Build backends and other tools must not add them to wheels anymore, + installers should be aware that these files may still be part of + some wheels. #. During extraction, wheel installers verify all the hashes in RECORD - against the file contents. Apart from RECORD and its signatures, - installation will fail if any file in the archive is not both - mentioned and correctly hashed in RECORD. + against the file contents. Apart from RECORD, RECORD.jws and + RECORD.p7s, installation will fail if any file in the archive is not + both mentioned and correctly hashed in RECORD. Subdirectories in :file:`.dist-info/` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -300,52 +299,6 @@ documentation and so forth from the distribution. During installation the contents of these subdirectories are moved onto their destination paths. -Signed wheel files ------------------- - -Wheel files include an extended RECORD that enables digital -signatures. PEP 376's RECORD is altered to include a secure hash -``digestname=urlsafe_b64encode_nopad(digest)`` (urlsafe base64 -encoding with no trailing = characters) as the second column instead -of an md5sum. All possible entries are hashed, including any -generated files such as .pyc files, but not RECORD which cannot contain its -own hash. For example:: - - file.py,sha256=AVTFPZpEKzuHr7OvQZmhaU3LvwKz06AJw8mT\_pNh2yI,3144 - distribution-1.0.dist-info/RECORD,, - -The signature file(s) RECORD.jws and RECORD.p7s are not mentioned in -RECORD at all since they can only be added after RECORD is generated. -Every other file in the archive must have a correct hash in RECORD -or the installation will fail. - -If JSON web signatures are used, one or more JSON Web Signature JSON -Serialization (JWS-JS) signatures is stored in a file RECORD.jws adjacent -to RECORD. JWS is used to sign RECORD by including the SHA-256 hash of -RECORD as the signature's JSON payload: - -.. code-block:: json - - { "hash": "sha256=ADD-r2urObZHcxBW3Cr-vDCu5RJwT4CaRTHiFmbcIYY" } - -(The hash value is the same format used in RECORD.) - -If RECORD.p7s is used, it must contain a detached S/MIME format signature -of RECORD. - -A wheel installer is not required to understand digital signatures but -MUST verify the hashes in RECORD against the extracted file contents. -When the installer checks file hashes against RECORD, a separate signature -checker only needs to establish that RECORD matches the signature. - -See - -- https://datatracker.ietf.org/doc/html/rfc7515 -- https://datatracker.ietf.org/doc/html/draft-jones-json-web-signature-json-serialization-01 -- https://datatracker.ietf.org/doc/html/rfc7517 -- https://datatracker.ietf.org/doc/html/draft-jones-jose-json-private-key-01 - - FAQ === @@ -361,34 +314,6 @@ Wheel defines a .data directory. Should I put all my data there? in *wheel's* ``.data`` directory. -Why does wheel include attached signatures? -------------------------------------------- - - Attached signatures are more convenient than detached signatures - because they travel with the archive. Since only the individual files - are signed, the archive can be recompressed without invalidating - the signature or individual files can be verified without having - to download the whole archive. - - -Why does wheel allow JWS signatures? ------------------------------------- - - The JOSE specifications of which JWS is a part are designed to be easy - to implement, a feature that is also one of wheel's primary design - goals. JWS yields a useful, concise pure-Python implementation. - - -Why does wheel also allow S/MIME signatures? --------------------------------------------- - - S/MIME signatures are allowed for users who need or want to use - existing public key infrastructure with wheel. - - Signed packages are only a basic building block in a secure package - update system. Wheel only provides the building block. - - What's the deal with "purelib" vs. "platlib"? --------------------------------------------- @@ -465,6 +390,7 @@ History :pep:`639`. - January 2025: Clarified that name and version needs to be normalized for ``.dist-info`` and ``.data`` directories. +- January 2026: Deprecate RECORD.jws and RECORD.p7s (PEP 815) Appendix From 19be0aacccea0189b13cafe7442161ef508818d8 Mon Sep 17 00:00:00 2001 From: konstin Date: Thu, 29 Jan 2026 11:47:27 +0100 Subject: [PATCH 118/187] PEP reference --- source/specifications/binary-distribution-format.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/specifications/binary-distribution-format.rst b/source/specifications/binary-distribution-format.rst index 17e7bd062..e9cbcb53d 100644 --- a/source/specifications/binary-distribution-format.rst +++ b/source/specifications/binary-distribution-format.rst @@ -390,7 +390,7 @@ History :pep:`639`. - January 2025: Clarified that name and version needs to be normalized for ``.dist-info`` and ``.data`` directories. -- January 2026: Deprecate RECORD.jws and RECORD.p7s (PEP 815) +- January 2026: Deprecate RECORD.jws and RECORD.p7s :pep:`815`. Appendix From 1246fbe0b7763214370e011a8ba4658f43d693e2 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Fri, 30 Jan 2026 03:09:54 +0100 Subject: [PATCH 119/187] Ignore linkcheck 403s from docutils.sourceforge.io Signed-off-by: William Woodruff --- source/conf.py | 1 + 1 file changed, 1 insertion(+) diff --git a/source/conf.py b/source/conf.py index ccb828b6e..cd52473ac 100644 --- a/source/conf.py +++ b/source/conf.py @@ -156,6 +156,7 @@ r"https://click\.palletsprojects\.com/.*", r"https://typer\.tiangolo\.com/.*", r"https://www.npmjs.com/.*", + r"https://docutils\.sourceforge\.io/.*", ] linkcheck_retries = 5 # Ignore anchors for common targets when we know they likely won't be found From 1b9e6330c33f954f8e5cd9c732e0a4ba428b4a0e Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Fri, 30 Jan 2026 19:09:07 +0100 Subject: [PATCH 120/187] Add another ignore Signed-off-by: William Woodruff --- source/conf.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/conf.py b/source/conf.py index cd52473ac..37d00dd55 100644 --- a/source/conf.py +++ b/source/conf.py @@ -157,6 +157,9 @@ r"https://typer\.tiangolo\.com/.*", r"https://www.npmjs.com/.*", r"https://docutils\.sourceforge\.io/.*", + # Temporarily ignored due to expired TLS cert. + # Ref: https://github.com/pypa/packaging.python.org/issues/1998 + r"https://blog\.ganssle\.io/.*", ] linkcheck_retries = 5 # Ignore anchors for common targets when we know they likely won't be found From f98314acf3f2bf1d977a0030b96aaf5ce53253bd Mon Sep 17 00:00:00 2001 From: Laurie O Date: Mon, 2 Feb 2026 10:47:24 +1000 Subject: [PATCH 121/187] Remove setuptools/wheel upgrade instruction in tutorial --- source/tutorials/installing-packages.rst | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/source/tutorials/installing-packages.rst b/source/tutorials/installing-packages.rst index 3a9aa23bb..4c9b95030 100644 --- a/source/tutorials/installing-packages.rst +++ b/source/tutorials/installing-packages.rst @@ -137,7 +137,7 @@ If that still doesn't allow you to run ``python -m pip``: `_ [1]_ * Run ``python get-pip.py``. [2]_ This will install or upgrade pip. - Additionally, it will install :ref:`setuptools` and :ref:`wheel` if they're + Additionally, it may install :ref:`setuptools` and :ref:`wheel` if they're not installed already. .. warning:: @@ -150,24 +150,23 @@ If that still doesn't allow you to run ``python -m pip``: software. -Ensure pip, setuptools, and wheel are up to date ------------------------------------------------- +Ensure pip is up to date +------------------------ -While ``pip`` alone is sufficient to install from pre-built binary archives, -up to date copies of the ``setuptools`` and ``wheel`` projects are useful -to ensure you can also install from source archives: +Make sure you have the latest features and fixes, and support for the latest +Python packaging specifications. .. tab:: Unix/macOS .. code-block:: bash - python3 -m pip install --upgrade pip setuptools wheel + python3 -m pip install --upgrade pip .. tab:: Windows .. code-block:: bat - py -m pip install --upgrade pip setuptools wheel + py -m pip install --upgrade pip Optionally, create a virtual environment ---------------------------------------- From 3f10d6ea08fb37a4e4bbe5746dda80f03652e981 Mon Sep 17 00:00:00 2001 From: github-merge-queue <118344674+github-merge-queue@users.noreply.github.com> Date: Mon, 2 Feb 2026 06:30:05 +0000 Subject: [PATCH 122/187] Update uv_build version to 0.9.28 --- 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 d49d41108..f135a2c24 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.26, <0.10.0"] + requires = ["uv_build >= 0.9.28, <0.10.0"] build-backend = "uv_build" From 45cf412baff57c222623f631c363fd455894363d Mon Sep 17 00:00:00 2001 From: woodruffw <3059210+woodruffw@users.noreply.github.com> Date: Sat, 7 Feb 2026 02:02:07 +0000 Subject: [PATCH 123/187] Update uv_build version to 0.10.0 --- 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 f135a2c24..615724616 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.28, <0.10.0"] + requires = ["uv_build >= 0.10.0, <0.11.0"] build-backend = "uv_build" From a0d16b1a88e27ee4a5e88cd2d75a1af98af6b6b3 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Wed, 24 Dec 2025 23:31:01 -0500 Subject: [PATCH 124/187] pypirc: stipulate UTF-8 encoding Signed-off-by: William Woodruff --- source/specifications/pypirc.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/source/specifications/pypirc.rst b/source/specifications/pypirc.rst index aeba72b0d..e2711614d 100644 --- a/source/specifications/pypirc.rst +++ b/source/specifications/pypirc.rst @@ -5,6 +5,13 @@ The :file:`.pypirc` file ======================== +.. important:: + + The :file:`.pypirc` file **SHOULD** be UTF-8 encoded. + + Tools that read or write :file:`.pypirc` files may not function correctly + if another character encoding is used. + A :file:`.pypirc` file allows you to define the configuration for :term:`package indexes ` (referred to here as "repositories"), so that you don't have to enter the URL, username, or password whenever you upload a package with From 78b4061aaca53a01ac26b07032ea2e962b506c4f Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Tue, 10 Feb 2026 12:24:39 -0500 Subject: [PATCH 125/187] Feedback Signed-off-by: William Woodruff --- source/specifications/pypirc.rst | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/source/specifications/pypirc.rst b/source/specifications/pypirc.rst index e2711614d..b937a1d62 100644 --- a/source/specifications/pypirc.rst +++ b/source/specifications/pypirc.rst @@ -5,18 +5,16 @@ The :file:`.pypirc` file ======================== -.. important:: - - The :file:`.pypirc` file **SHOULD** be UTF-8 encoded. - - Tools that read or write :file:`.pypirc` files may not function correctly - if another character encoding is used. - A :file:`.pypirc` file allows you to define the configuration for :term:`package indexes ` (referred to here as "repositories"), so that you don't have to enter the URL, username, or password whenever you upload a package with :ref:`twine` or :ref:`flit`. +The :file:`.pypirc` file **SHOULD** be UTF-8 encoded. + +Tools that read or write :file:`.pypirc` files may not function correctly +if another character encoding is used. + The format (originally defined by the :ref:`distutils` package) is: .. code-block:: ini From 307f8b15e0166a184418c6c5b0b1443a3138b3d4 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Tue, 10 Feb 2026 12:29:08 -0500 Subject: [PATCH 126/187] Remove dead link to pkg_resources Signed-off-by: William Woodruff --- source/guides/packaging-namespace-packages.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/guides/packaging-namespace-packages.rst b/source/guides/packaging-namespace-packages.rst index 3d929d527..1fa3ea64d 100644 --- a/source/guides/packaging-namespace-packages.rst +++ b/source/guides/packaging-namespace-packages.rst @@ -159,8 +159,8 @@ Legacy namespace packages These two methods, that were used to create namespace packages prior to :pep:`420`, are now considered to be obsolete and should not be used unless you need compatibility -with packages already using this method. Also, :doc:`pkg_resources ` -has been deprecated. +with packages already using this method. Also, ``pkg_resources`` has been deprecated +(and is fully removed in setuptools 82.0.0). To migrate an existing package, all packages sharing the namespace must be migrated simultaneously. From b26e2c4fa6700f9a3d1386176cf53c4ebe1fe6a9 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Tue, 10 Feb 2026 16:35:09 -0500 Subject: [PATCH 127/187] Remove more dead references Signed-off-by: William Woodruff --- source/guides/multi-version-installs.rst | 4 ---- source/guides/packaging-namespace-packages.rst | 14 +++++++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/source/guides/multi-version-installs.rst b/source/guides/multi-version-installs.rst index a09bc900a..456ee22e2 100644 --- a/source/guides/multi-version-installs.rst +++ b/source/guides/multi-version-installs.rst @@ -37,7 +37,3 @@ time, but that approach does mean that standard command line invocations of the affected tools can't be used - it's necessary to write a custom wrapper script or use ``python3 -c ''`` to invoke the application's main entry point directly. - -Refer to the `pkg_resources documentation -`__ -for more details. diff --git a/source/guides/packaging-namespace-packages.rst b/source/guides/packaging-namespace-packages.rst index 1fa3ea64d..a3940b715 100644 --- a/source/guides/packaging-namespace-packages.rst +++ b/source/guides/packaging-namespace-packages.rst @@ -157,10 +157,16 @@ the `native namespace package example project`_. Legacy namespace packages ------------------------- +.. warning:: + + The information in this section is obsolete and is no longer functional + (as of Setuptools 82.0.0). It is only retained for historical reference. + + ``pkg_resources`` has been deprecated and was fully removed in Setuptools 82.0.0. + These two methods, that were used to create namespace packages prior to :pep:`420`, are now considered to be obsolete and should not be used unless you need compatibility -with packages already using this method. Also, ``pkg_resources`` has been deprecated -(and is fully removed in setuptools 82.0.0). +with packages already using this method. To migrate an existing package, all packages sharing the namespace must be migrated simultaneously. @@ -216,7 +222,7 @@ in the `pkgutil namespace example project`_. pkg_resources-style namespace packages ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -:doc:`Setuptools ` provides the `pkg_resources.declare_namespace`_ function and +:doc:`Setuptools ` previously provided the ``pkg_resources.declare_namespace`` function and the ``namespace_packages`` argument to :func:`~setuptools.setup`. Together these can be used to declare namespace packages. While this approach is no longer recommended, it is widely present in most existing namespace packages. @@ -285,7 +291,5 @@ to :func:`~setuptools.setup` in :file:`setup.py`. For example: A complete working example of two pkg_resources-style namespace packages can be found in the `pkg_resources namespace example project`_. -.. _pkg_resources.declare_namespace: - https://setuptools.readthedocs.io/en/latest/pkg_resources.html#namespace-package-support .. _pkg_resources namespace example project: https://github.com/pypa/sample-namespace-packages/tree/master/pkg_resources From 5ac5ac1e1edc9da8446b5b3f99f87063c8f2d664 Mon Sep 17 00:00:00 2001 From: Valentin Nechayev Date: Sun, 15 Feb 2026 08:55:25 +0200 Subject: [PATCH 128/187] Fix version example typo The descriptive part defines `rc` but not `c` as possible value of this suffix. --- source/specifications/version-specifiers.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/specifications/version-specifiers.rst b/source/specifications/version-specifiers.rst index 13015794f..5c2d66609 100644 --- a/source/specifications/version-specifiers.rst +++ b/source/specifications/version-specifiers.rst @@ -590,8 +590,8 @@ and post-releases for minor corrections:: 1.0.dev2 1.0.dev3 1.0.dev4 - 1.0c1 - 1.0c2 + 1.0rc1 + 1.0rc2 1.0 1.0.post1 1.1.dev1 From f808aaa5445d9fba7fdae0bdd588bc99b4883e73 Mon Sep 17 00:00:00 2001 From: Raffaele Mancuso Date: Mon, 16 Feb 2026 11:16:21 +0100 Subject: [PATCH 129/187] Add project table to classifier example Like in the other examples --- source/guides/writing-pyproject-toml.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/source/guides/writing-pyproject-toml.rst b/source/guides/writing-pyproject-toml.rst index a1a595a13..92a7f25bf 100644 --- a/source/guides/writing-pyproject-toml.rst +++ b/source/guides/writing-pyproject-toml.rst @@ -413,6 +413,7 @@ A list of PyPI classifiers that apply to your project. Check the .. code-block:: toml + [project] classifiers = [ # How mature is this project? Common values are # 3 - Alpha From 8213504db80b61886cf21e2faeb9a0aa72746597 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Mon, 26 Jan 2026 16:23:37 +0100 Subject: [PATCH 130/187] Discourage use of version epochs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a note discouraging use of epochs in version specifiers, and update the versioning discussion accordingly. While at it, suggest using two-digit years for CalVer, as mentioned in the discussion thread. Discussion: https://discuss.python.org/t/discouraging-use-of-epoch-segments-in-versions/105811/1 Signed-off-by: Michał Górny --- source/discussions/versioning.rst | 17 +++++++++-------- source/specifications/version-specifiers.rst | 16 ++++++++++++++++ 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/source/discussions/versioning.rst b/source/discussions/versioning.rst index eeea3578c..aee3d25ea 100644 --- a/source/discussions/versioning.rst +++ b/source/discussions/versioning.rst @@ -27,7 +27,7 @@ examples of version numbers [#version-examples]_: - A post-release of an alpha release (possible, but discouraged): ``1.2.0a1.post1`` - A simple version with only two components: ``23.12`` - A simple version with just one component: ``42`` -- A version with an epoch: ``1!1.0`` +- A version with an epoch (discouraged): ``1!1.0`` Projects can use a cycle of pre-releases to support testing by their users before a final release. In order, the steps are: alpha releases, beta releases, @@ -46,13 +46,14 @@ notes. They should not be used for bug fixes; these should be done with a new final release (e.g., incrementing the third component when using semantic versioning). -Finally, epochs, a rarely used feature, serve to fix the sorting order when -changing the versioning scheme. For example, if a project is using calendar -versioning, with versions like 23.12, and switches to semantic versioning, with -versions like 1.0, the comparison between 1.0 and 23.12 will go the wrong way. -To correct this, the new version numbers should have an explicit epoch, as in -"1!1.0", in order to be treated as more recent than the old version numbers. - +Finally, epochs were intended to fix the sorting order when changing the +versioning scheme. For example, if a project was using calendar versioning, with +versions like ``23.12``, and switched to semantic versioning, with versions like +``1.0``, the comparison between ``1.0`` and ``23.12`` would go the wrong way. To +correct this, the new version numbers would have an explicit epoch, as in +``1!1.0``, in order to be treated as more recent than the old version numbers. +However, this is discouraged, and it is preferable to use a higher version +number that is unlikely to cause user confusion, such as ``100.0``. Semantic versioning vs. calendar versioning diff --git a/source/specifications/version-specifiers.rst b/source/specifications/version-specifiers.rst index 13015794f..0be631993 100644 --- a/source/specifications/version-specifiers.rst +++ b/source/specifications/version-specifiers.rst @@ -394,6 +394,21 @@ from an earlier epoch:: 1!1.1 1!2.0 +.. note:: + + Use of nonzero epochs is discouraged. They are often not supported or + discouraged by downstream packaging where Python packages may need to be + consumed, and due to their scarce use they may also not be well supported by + Python packaging tools. + + When version scheme needs to be changed, it is preferable to continue with + monotonically increasing numbers in epoch zero. For example, the version + 2026.x could be unambiguously followed by 3000.x. + + See `Discouraging use of epoch segments in versions + `__ + for the relevant discussion. + .. _version-specifiers-normalization: @@ -1273,3 +1288,4 @@ History - May 2025: Clarify that development releases are a form of pre-release when they are handled. - Nov 2025: Make arbitrary equality case insensitivity explicit. +- Jan 2026: The use of epochs was discouraged. From eb953dea1779c5bc8dcb70c660071fd0437c636b Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Thu, 26 Feb 2026 22:14:39 -0500 Subject: [PATCH 131/187] Move warning Signed-off-by: William Woodruff --- source/guides/packaging-namespace-packages.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/source/guides/packaging-namespace-packages.rst b/source/guides/packaging-namespace-packages.rst index a3940b715..219eded90 100644 --- a/source/guides/packaging-namespace-packages.rst +++ b/source/guides/packaging-namespace-packages.rst @@ -157,13 +157,6 @@ the `native namespace package example project`_. Legacy namespace packages ------------------------- -.. warning:: - - The information in this section is obsolete and is no longer functional - (as of Setuptools 82.0.0). It is only retained for historical reference. - - ``pkg_resources`` has been deprecated and was fully removed in Setuptools 82.0.0. - These two methods, that were used to create namespace packages prior to :pep:`420`, are now considered to be obsolete and should not be used unless you need compatibility with packages already using this method. @@ -222,6 +215,13 @@ in the `pkgutil namespace example project`_. pkg_resources-style namespace packages ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. warning:: + + The information in this section is obsolete and is no longer functional + (as of Setuptools 82.0.0). It is only retained for historical reference. + + ``pkg_resources`` has been deprecated and was fully removed in Setuptools 82.0.0. + :doc:`Setuptools ` previously provided the ``pkg_resources.declare_namespace`` function and the ``namespace_packages`` argument to :func:`~setuptools.setup`. Together these can be used to declare namespace packages. While this approach is no From 69adfc583333b02237a5e566c9ec9751745b36a6 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Thu, 26 Feb 2026 22:18:22 -0500 Subject: [PATCH 132/187] Feedback Signed-off-by: William Woodruff --- source/guides/packaging-namespace-packages.rst | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/source/guides/packaging-namespace-packages.rst b/source/guides/packaging-namespace-packages.rst index 219eded90..e7e5d4019 100644 --- a/source/guides/packaging-namespace-packages.rst +++ b/source/guides/packaging-namespace-packages.rst @@ -159,7 +159,7 @@ Legacy namespace packages These two methods, that were used to create namespace packages prior to :pep:`420`, are now considered to be obsolete and should not be used unless you need compatibility -with packages already using this method. +with packages already using one of these methods. To migrate an existing package, all packages sharing the namespace must be migrated simultaneously. @@ -175,7 +175,7 @@ pkgutil-style namespace packages Python 2.3 introduced the :doc:`pkgutil ` module and the :py:func:`python:pkgutil.extend_path` function. This can be used to declare namespace packages that need to be compatible with both Python 2.3+ and Python 3. This -is the recommended approach for the highest level of compatibility. +was the recommended approach for the highest level of compatibility. To create a pkgutil-style namespace package, you need to provide an :file:`__init__.py` file for the namespace package: @@ -224,8 +224,8 @@ pkg_resources-style namespace packages :doc:`Setuptools ` previously provided the ``pkg_resources.declare_namespace`` function and the ``namespace_packages`` argument to :func:`~setuptools.setup`. Together -these can be used to declare namespace packages. While this approach is no -longer recommended, it is widely present in most existing namespace packages. +these could be used to declare namespace packages. While this approach is no +supported, it may still be encountered in environments using older ``setuptools`` versions. If you are creating a new distribution within an existing namespace package that uses this method then it's recommended to continue using this as the different methods are not cross-compatible and it's not advisable to try to migrate an @@ -287,9 +287,3 @@ to :func:`~setuptools.setup` in :file:`setup.py`. For example: packages=find_packages() namespace_packages=['mynamespace'] ) - -A complete working example of two pkg_resources-style namespace packages can be found -in the `pkg_resources namespace example project`_. - -.. _pkg_resources namespace example project: - https://github.com/pypa/sample-namespace-packages/tree/master/pkg_resources From 1212a110f480a6cf0b5991df4b7eeb82b2d83720 Mon Sep 17 00:00:00 2001 From: github-merge-queue <118344674+github-merge-queue@users.noreply.github.com> Date: Mon, 2 Mar 2026 06:25:57 +0000 Subject: [PATCH 133/187] Update uv_build version to 0.10.7 --- 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 615724616..578241ce6 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.10.0, <0.11.0"] + requires = ["uv_build >= 0.10.7, <0.11.0"] build-backend = "uv_build" From 5911ea3ce7e8e1ae51b5387722c0a50ea2154130 Mon Sep 17 00:00:00 2001 From: Alyssa Coghlan Date: Mon, 2 Mar 2026 21:57:23 +1000 Subject: [PATCH 134/187] Add missing word, reflow paragraph --- source/guides/packaging-namespace-packages.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/guides/packaging-namespace-packages.rst b/source/guides/packaging-namespace-packages.rst index e7e5d4019..6ff93c4c9 100644 --- a/source/guides/packaging-namespace-packages.rst +++ b/source/guides/packaging-namespace-packages.rst @@ -225,7 +225,8 @@ pkg_resources-style namespace packages :doc:`Setuptools ` previously provided the ``pkg_resources.declare_namespace`` function and the ``namespace_packages`` argument to :func:`~setuptools.setup`. Together these could be used to declare namespace packages. While this approach is no -supported, it may still be encountered in environments using older ``setuptools`` versions. +longer supported, it may still be encountered in environments using older +``setuptools`` versions. If you are creating a new distribution within an existing namespace package that uses this method then it's recommended to continue using this as the different methods are not cross-compatible and it's not advisable to try to migrate an From 6d887c3e6a99b8631055648f2a946e17398b254f Mon Sep 17 00:00:00 2001 From: Alyssa Coghlan Date: Mon, 2 Mar 2026 22:14:00 +1000 Subject: [PATCH 135/187] Address review comments --- .../specifications/dependency-specifiers.rst | 104 +++++++++++------- 1 file changed, 66 insertions(+), 38 deletions(-) diff --git a/source/specifications/dependency-specifiers.rst b/source/specifications/dependency-specifiers.rst index 9824815e5..57a201e73 100644 --- a/source/specifications/dependency-specifiers.rst +++ b/source/specifications/dependency-specifiers.rst @@ -248,12 +248,14 @@ The follow comparison operations are defined in the marker expression grammar: For ``String`` fields, ``==``, ``!=``, ``in``, and ``not in`` are defined as they are for Python strings (case sensitive, with no value normalization of any -kind). The use of ``~=`` or ``===`` with string fields is -explicitly discouraged, and publishing tools SHOULD emit an error, while locking -and installation tools MAY instead interpret them as equivalent to ``==``. The -use of ordered comparisons (``<``, ``<=``, ``>``, ``>=``) with string fields is -explicitly discouraged (as it makes no semantic sense in the packaging context), -and publishing tools SHOULD emit an error, while locking and installation tools +kind). The use of ``~=`` or ``===`` with string fields is explicitly +discouraged and publishing tools SHOULD emit an error, index servers MAY +disallow uploads containing such environment markers, while locking and +installation tools MAY instead interpret them as equivalent to ``==``. The use +of ordered comparisons (``<``, ``<=``, ``>``, ``>=``) with string fields is +explicitly discouraged (as it makes no semantic sense in the packaging context) +and publishing tools SHOULD emit an error, index servers MAY disallow uploads +containing such environment markers, while locking and installation tools SHOULD implement the following behavior: * treat ``>=`` and ``<=`` as equivalent to ``==`` @@ -261,7 +263,11 @@ SHOULD implement the following behavior: For ``Set of String`` fields, as there is no marker syntax for set literals, the only valid operations are ``in`` and ``not in`` comparisons with a user -supplied string literal as the left operand. +supplied string literal as the left operand. Publishing tools SHOULD emit an +error if environment markers attempt to use any other comparison operations on +these fields and index servers MAY disallow uploads containing such environment +markers, while locking and installation tools SHOULD treat such operations as +always being False. For ``Version`` fields, the comparison operations are defined by the :ref:`Version specifier specification ` when either both @@ -269,22 +275,27 @@ the marker field value and the user supplied constant can be parsed as valid version specifiers or the ``===`` arbitrary equivalence comparison operator is used. When an operator other than ``===`` is used, publishing tools SHOULD emit an error if the user supplied constant cannot be parsed as a valid version -specifier, while locking and installation tools MAY either emit an error or else +specifier, index servers MAY disallow uploads containing such environment +markers, while locking and installation tools MAY either emit an error or else fall back to ``String`` field comparison logic if either the marker field value or the user supplied constant cannot be parsed as a valid version specifier. Note that ``in`` and ``not in`` containment checks are NOT valid for ``Version`` -fields and publishing tools SHOULD emit an error, while locking and installation +fields and publishing tools SHOULD emit an error, index servers MAY disallow +uploads containing such environment markers, while locking and installation tools MAY treat them as always being False. For ``Version | String`` fields, comparison operations are defined as they are for ``Version`` fields, while ``in`` and ``not in`` containment checks are -defined as they are for ``String`` fields. However, there is no expectation -that the parsing of the marker field value or the user supplied constant as a -valid version will succeed, so tools MUST fall back to processing the field as -a ``String`` field. Alternatively, tools MAY unconditionally treat such fields -as ``String`` fields. Due to this potential for variation across clients, -comparisons that rely on these fields being processed as ``Version`` fields -SHOULD NOT be used in environment markers published to public index servers. +defined as they are for ``String`` fields. However, there is no consistent +cross-platform expectation that the parsing of the marker field value or the +user supplied constant as a valid version will succeed, so tools SHOULD fall +back to processing the field as a ``String`` field if parsing either value as a +version fails. Tools MAY emit a warning if the field is expected to contain a +valid version on a given platform but does not in fact do so. Tools SHOULD NOT +unconditionally treat such fields as ``String`` fields, as doing so may give +incorrect answers for environment markers that are appropriately scoped +to the relevant platforms before performing a version based comparison. + Composing marker expressions '''''''''''''''''''''''''''' @@ -323,8 +334,13 @@ contain non-ASCII text that users wish to perform comparisons against. Unknown marker fields ''''''''''''''''''''' -References to unknown marker fields MUST raise an error rather than resulting -in a comparison that evaluates to True or False. +References to unknown marker fields SHOULD raise an error rather than resulting +in a comparison that evaluates to True or False. This is so that attempted +installations involving unknown marker fields result in a clear installation +failure, rather than an apparently successful installation that then fails at +runtime due to missing dependencies (if the unknown marker is treated as +False) or a potentially cryptic installation failure of a dependency that is +not valid for the current platform (if the unknown marker is treated as True) Variables whose value cannot be calculated on a given Python implementation should evaluate to ``0`` for ``Version`` fields, and an empty string for all @@ -345,7 +361,7 @@ of the following marker fields: * - Marker - Python equivalent - Type - - Sample values + - Sample values & notes * - ``os_name`` - :py:data:`os.name` - String @@ -353,64 +369,75 @@ of the following marker fields: * - ``sys_platform`` - :py:data:`sys.platform` - String - - ``linux``, ``linux2``, ``darwin``, ``java1.8.0_51`` (note that "linux" - is from Python3 and "linux2" from Python2) + - ``linux``, ``win32``, ``darwin``, ``java1.8.0_51`` + (note that this is the most well defined field for use when declaring + platform specific dependencies) * - ``platform_machine`` - :py:func:`platform.machine()` - String - - ``x86_64`` + - ``x86_64``, ``aarch64``, ``AMD64``, ``arm64`` + (note that this value is provided by the operating system, so the same + CPU architecture may use different strings on different platforms) * - ``platform_python_implementation`` - :py:func:`platform.python_implementation()` - String - - ``CPython``, ``Jython`` + - ``CPython``, ``PyPy``, ``Jython`` * - ``platform_release`` - :py:func:`platform.release()` - Version | String - ``3.14.1-x86_64-linode39``, ``14.5.0``, ``1.8.0_51`` + (may be a valid version field, for example on macOS/darwin) * - ``platform_system`` - :py:func:`platform.system()` - String - ``Linux``, ``Windows``, ``Java`` * - ``platform_version`` - :py:func:`platform.version()` - - String + - Version | String - ``#1 SMP Fri Apr 25 13:07:35 EDT 2014`` ``Java HotSpot(TM) 64-Bit Server VM, 25.51-b03, Oracle Corporation`` ``Darwin Kernel Version 14.5.0: Wed Jul 29 02:18:53 PDT 2015; root:xnu-2782.40.9~2/RELEASE_X86_64`` + ``13`` + (may be a valid version field, for example on iOS or Android) * - ``python_version`` - ``'.'.join(platform.python_version_tuple()[:2])`` - :ref:`Version ` - - ``3.4``, ``2.7`` + - ``3.9``, ``3.15`` * - ``python_full_version`` - :py:func:`platform.python_version()` - :ref:`Version ` - - ``3.4.0``, ``3.5.0b1`` + - ``3.10.12``, ``3.15.0a1`` * - ``implementation_name`` - :py:data:`sys.implementation.name ` - String - - ``cpython`` + - ``cpython``, ``pypy`` * - ``implementation_version`` - see definition below - :ref:`Version ` - - ``3.4.0``, ``3.5.0b1`` + - ``3.10.12``, ``7.3.17`` + (examples are for CPython and PyPy respectively) * - ``extra`` - Used to indicate optional dependencies in project dependency metadata. An error except when defined by the context interpreting the - specifier. Publishing tools SHOULD permit use of this field. + specifier. - Special (see below) - ``toml`` + (publishing tools SHOULD permit use of this field) * - ``extras`` - Used to indicate optional public dependencies in lock files. An error except when defined by the context interpreting the specifier. - Publishing tools SHOULD NOT permit use of this field. - Set of strings - ``{"toml"}`` + (publishing tools SHOULD NOT permit use of this field and index servers + SHOULD NOT accept uploads containing such environment markers) * - ``dependency_groups`` - Used to indicate optional project internal dependencies in lock files. An error except when defined by the context interpreting the - specifier. Publishing tools SHOULD NOT permit use of this field. + specifier. - Set of strings - ``{"test"}`` + (publishing tools SHOULD NOT permit use of this field and index servers + SHOULD NOT accept uploads containing such environment markers) For backwards compatibility with older locking and installation tools, the ``extras`` and ``dependency_groups`` fields are currently only considered @@ -426,13 +453,14 @@ predates the addition of ``Set of strings`` as a defined marker field type. Accordingly, for this field only, ``extra == "name"`` is equivalent to ``"name" in extras``, while ``extra != "name"`` is equivalent to ``"name" not in extras``. Other comparison operations on ``extra`` are not -defined and publishing tools SHOULD emit an error, while locking and -installation tools may evaluate them as False. Unlike the newer ``extras`` -field, this field SHOULD be accepted by both publishing tools and index -servers. Marker evaluation environments intended for project dependency -declarations will typically need to handle evaluation of ``extra`` field -comparisons, while other evaluations of environment markers will not generally -need to do so. +defined and publishing tools SHOULD emit an error, index servers MAY disallow +uploads containing such environment markers, while locking and +installation tools SHOULD evaluate them as False. Unlike the newer ``extras`` +field, environment markers using this field SHOULD be accepted by both +publishing tools and index servers. Marker evaluation environments intended +for project dependency declarations will typically need to handle evaluation +of ``extra`` field comparisons, while other evaluations of environment markers +will not generally need to do so. The ``implementation_version`` marker variable is derived from :py:data:`sys.implementation.version `: From f65fa6d933eef1d002f3700d5f72dc620923e81b Mon Sep 17 00:00:00 2001 From: Alyssa Coghlan Date: Mon, 2 Mar 2026 22:19:49 +1000 Subject: [PATCH 136/187] Update source/glossary.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Éric --- source/glossary.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/glossary.rst b/source/glossary.rst index 91cda3ccd..cd4e23f61 100644 --- a/source/glossary.rst +++ b/source/glossary.rst @@ -14,7 +14,7 @@ Glossary Build Backend - A library that takes a :term:`source tree ` + A library that takes a :term:`source tree ` and builds a :term:`source distribution ` or :term:`built distribution ` from it. The build is delegated to the backend by a From 0a74a29a71b82540b5189041e9104e8d1d3425ff Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Sun, 8 Mar 2026 14:17:49 +0800 Subject: [PATCH 137/187] Update devguide link Signed-off-by: William Woodruff --- source/discussions/deploying-python-applications.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/discussions/deploying-python-applications.rst b/source/discussions/deploying-python-applications.rst index e10f36f9c..59856c4a4 100644 --- a/source/discussions/deploying-python-applications.rst +++ b/source/discussions/deploying-python-applications.rst @@ -97,7 +97,7 @@ services, and DLL/EXE COM servers might work but it is not actively supported. The distutils extension is released under the MIT-licence and Mozilla Public License 2.0. -.. __: https://devguide.python.org/#status-of-python-branches +.. __: https://devguide.python.org/versions/ macOS ----- From 6922c352aaaf78094f073bc40970665650c4a345 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Wed, 11 Mar 2026 15:26:06 -0700 Subject: [PATCH 138/187] Allow spaces in valid glob patterns Discussion at https://discuss.python.org/t/spaces-not-considered-a-valid-verbatim-character-for-glob-patterns/106463 . --- source/specifications/glob-patterns.rst | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/source/specifications/glob-patterns.rst b/source/specifications/glob-patterns.rst index abdb15b0f..8ff3f09fb 100644 --- a/source/specifications/glob-patterns.rst +++ b/source/specifications/glob-patterns.rst @@ -15,8 +15,8 @@ Valid glob patterns For PyPA purposes, a *valid glob pattern* MUST be a string matched against filesystem entries as specified below: -- Alphanumeric characters, underscores (``_``), hyphens (``-``) and dots (``.``) - MUST be matched verbatim. +- Alphanumeric characters, spaces (`` ``), underscores (``_``), hyphens (``-``), + and dots (``.``) MUST be matched verbatim. - Special glob characters: ``*``, ``?``, ``**`` and character ranges: ``[]`` containing only the verbatim matched characters MUST be supported. @@ -107,9 +107,15 @@ The code below is as a simple reference implementation: raise ValueError( f"Pattern {pattern!r} should be relative and must not start with '/'" ) - if re.match(r'^[\w\-\.\/\*\?\[\]]+$', pattern) is None: + if re.match(r'^[\w \-\.\/\*\?\[\]]+$', pattern) is None: raise ValueError(f"Pattern '{pattern}' contains invalid characters.") found = glob(pattern, recursive=True) if not found: raise ValueError(f"Pattern '{pattern}' did not match any files.") return found + +History +======= + +- January 2025: Initial version +- March 2026: Treat spaces as a verbatim character From 59b9f2687283ebe65054368650fdc44352700c94 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Wed, 11 Mar 2026 15:37:58 -0700 Subject: [PATCH 139/187] Update link for Python version status --- source/discussions/deploying-python-applications.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/discussions/deploying-python-applications.rst b/source/discussions/deploying-python-applications.rst index e10f36f9c..59856c4a4 100644 --- a/source/discussions/deploying-python-applications.rst +++ b/source/discussions/deploying-python-applications.rst @@ -97,7 +97,7 @@ services, and DLL/EXE COM servers might work but it is not actively supported. The distutils extension is released under the MIT-licence and Mozilla Public License 2.0. -.. __: https://devguide.python.org/#status-of-python-branches +.. __: https://devguide.python.org/versions/ macOS ----- From c326e307483f5bc3270e480055cf34707849ad35 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Fri, 13 Mar 2026 16:11:39 -0700 Subject: [PATCH 140/187] Clarify file name precedence for archive, sdist, and wheel specifications in pylock.toml --- source/specifications/pylock-toml.rst | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/source/specifications/pylock-toml.rst b/source/specifications/pylock-toml.rst index 342e608c5..6b4976b5d 100644 --- a/source/specifications/pylock-toml.rst +++ b/source/specifications/pylock-toml.rst @@ -449,7 +449,12 @@ See :ref:`pylock-packages-vcs-subdirectory`. ``packages.archive.url`` '''''''''''''''''''''''' -See :ref:`pylock-packages-vcs-url`. +- **Type**: string +- **Required?**: if :ref:`pylock-packages-archive-path` is not specified +- **Inspiration**: :ref:`direct-url-data-structure-archive` +- The URL_ to the archive. +- If :ref:`pylock-packages-archive-path` is also specified, the filename as + specified by this key takes precedence. .. _pylock-packages-archive-path: @@ -457,7 +462,13 @@ See :ref:`pylock-packages-vcs-url`. ``packages.archive.path`` ''''''''''''''''''''''''' -See :ref:`pylock-packages-vcs-path`. +- **Type**: string +- **Required?**: if :ref:`pylock-packages-archive-url` is not specified +- **Inspiration**: :ref:`direct-url-data-structure-archive` +- The path to the archive. +- If a relative path is used it MUST be relative to the location of this file. +- If the path is relative it MAY use POSIX-style path separators explicitly + for portability. .. _pylock-packages-archive-size: @@ -554,6 +565,8 @@ See :ref:`pylock-packages-vcs-subdirectory`. the same value - **Inspiration**: PDM_, Poetry_, uv_ - The file name of the :ref:`source-distribution-format-sdist` file. +- If specified, this key's value takes precedence over the file name found in + either :ref:`pylock-packages-sdist-url` or :ref:`pylock-packages-sdist-path`. .. _pylock-packages-sdist-upload-time: @@ -623,6 +636,8 @@ See :ref:`pylock-packages-archive-hashes`. the same value - **Inspiration**: PDM_, Poetry_, uv_ - The file name of the :ref:`binary-distribution-format` file. +- If specified, this key's value takes precedence over the file name found in + either :ref:`pylock-packages-sdist-url` or :ref:`pylock-packages-sdist-path`. .. _pylock-packages-wheels-upload-time: @@ -826,6 +841,7 @@ History ------- - April 2025: Initial version, approved via :pep:`751`. +- March 2026: Clarify file name precedence for archives, sdists, and wheels. .. _Content-Length: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Length From 3d347d70dbe66bcd0578db6a969f77a007f3012e Mon Sep 17 00:00:00 2001 From: github-merge-queue <118344674+github-merge-queue@users.noreply.github.com> Date: Mon, 16 Mar 2026 06:39:50 +0000 Subject: [PATCH 141/187] Update uv_build version to 0.10.10 --- 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 578241ce6..ac39f33c1 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.10.7, <0.11.0"] + requires = ["uv_build >= 0.10.10, <0.11.0"] build-backend = "uv_build" From 5271c1f1c435f0e64bb4bf71dfeda167cad96ebf Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Wed, 18 Mar 2026 10:00:08 -0700 Subject: [PATCH 142/187] Clarify precedence of archive path and URL --- source/specifications/pylock-toml.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/specifications/pylock-toml.rst b/source/specifications/pylock-toml.rst index 6b4976b5d..bc5cb5413 100644 --- a/source/specifications/pylock-toml.rst +++ b/source/specifications/pylock-toml.rst @@ -453,8 +453,6 @@ See :ref:`pylock-packages-vcs-subdirectory`. - **Required?**: if :ref:`pylock-packages-archive-path` is not specified - **Inspiration**: :ref:`direct-url-data-structure-archive` - The URL_ to the archive. -- If :ref:`pylock-packages-archive-path` is also specified, the filename as - specified by this key takes precedence. .. _pylock-packages-archive-path: @@ -469,6 +467,8 @@ See :ref:`pylock-packages-vcs-subdirectory`. - If a relative path is used it MUST be relative to the location of this file. - If the path is relative it MAY use POSIX-style path separators explicitly for portability. +- If :ref:`pylock-packages-archive-url` is also specified, the filename as + specified by this key takes precedence. .. _pylock-packages-archive-size: From 18ca3fc7f31d834689dd276d88ea094fc4dc63e8 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Wed, 18 Mar 2026 10:03:20 -0700 Subject: [PATCH 143/187] Fix reference to wheels URL and path in pylock-toml Corrected reference to wheels URL and path in documentation. --- source/specifications/pylock-toml.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/specifications/pylock-toml.rst b/source/specifications/pylock-toml.rst index bc5cb5413..394f9a206 100644 --- a/source/specifications/pylock-toml.rst +++ b/source/specifications/pylock-toml.rst @@ -637,7 +637,7 @@ See :ref:`pylock-packages-archive-hashes`. - **Inspiration**: PDM_, Poetry_, uv_ - The file name of the :ref:`binary-distribution-format` file. - If specified, this key's value takes precedence over the file name found in - either :ref:`pylock-packages-sdist-url` or :ref:`pylock-packages-sdist-path`. + either :ref:`pylock-packages-wheels-url` or :ref:`pylock-packages-wheels-path`. .. _pylock-packages-wheels-upload-time: From 88f97dedab6cfe0fc39cf98711139499a1e81418 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=A9=EC=84=B1=EB=B2=94=20=28Bang=20Seongbeom=29?= Date: Mon, 23 Mar 2026 01:45:41 +0900 Subject: [PATCH 144/187] Add uv --- source/key_projects.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/source/key_projects.rst b/source/key_projects.rst index e4501fe0e..d372b4b69 100644 --- a/source/key_projects.rst +++ b/source/key_projects.rst @@ -827,6 +827,19 @@ scientific applications on clusters and supercomputers. Spack is not in PyPI (yet), but it requires no installation and can be used immediately after cloning from GitHub. +.. _uv: + +uv +== + +`Docs `__ | +`GitHub `__ | +`PyPI `__ + +An extremely fast Python package and project manager, written in Rust. It +supports creating and managing virtual environments, installing packages, +locking dependencies, and managing Python versions and projects. + .. _zestreleaser: zest.releaser From 26355d64de8379467e656340a2cd9f5dfc816679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=A9=EC=84=B1=EB=B2=94=20=28Bang=20Seongbeom=29?= Date: Mon, 23 Mar 2026 23:57:00 +0900 Subject: [PATCH 145/187] Update uv description to highlight Rust-based performance --- source/key_projects.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/key_projects.rst b/source/key_projects.rst index d372b4b69..dc7544a0b 100644 --- a/source/key_projects.rst +++ b/source/key_projects.rst @@ -836,7 +836,7 @@ uv `GitHub `__ | `PyPI `__ -An extremely fast Python package and project manager, written in Rust. It +A Python package and project manager, written in Rust for high performance. It supports creating and managing virtual environments, installing packages, locking dependencies, and managing Python versions and projects. From 91de779518df2a926b099e865820ba08e4597a4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Bidoul?= Date: Tue, 24 Mar 2026 10:46:32 +0100 Subject: [PATCH 146/187] Improve pylock requires-python exemple Since `requires-python` is a version specifier, `==3.12` actually means `==3.12.0` which is not how one would intuitively interpret it. --- source/specifications/pylock-toml/pylock.example.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/specifications/pylock-toml/pylock.example.toml b/source/specifications/pylock-toml/pylock.example.toml index 45e8731b2..8a439cd7a 100644 --- a/source/specifications/pylock-toml/pylock.example.toml +++ b/source/specifications/pylock-toml/pylock.example.toml @@ -1,6 +1,6 @@ lock-version = '1.0' environments = ["sys_platform == 'win32'", "sys_platform == 'linux'"] -requires-python = '== 3.12' +requires-python = '== 3.12.*' created-by = 'mousebender' [[packages]] From e689dc1826db1300e12d1f1c6cd6d8896d45e5a6 Mon Sep 17 00:00:00 2001 From: github-merge-queue <118344674+github-merge-queue@users.noreply.github.com> Date: Mon, 13 Apr 2026 06:53:50 +0000 Subject: [PATCH 147/187] Update uv_build version to 0.11.6 --- 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 ac39f33c1..4f1894414 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.10.10, <0.11.0"] + requires = ["uv_build >= 0.11.6, <0.12.0"] build-backend = "uv_build" From bb1458080af00b6d109f81acf247e0336aeff311 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Mon, 13 Apr 2026 14:29:56 -0400 Subject: [PATCH 148/187] Fix linkcheck timeouts Signed-off-by: William Woodruff --- .github/workflows/test.yml | 4 ++++ source/conf.py | 10 +++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1f67bad8e..8d230d6ba 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,6 +24,7 @@ jobs: name: ${{ matrix.noxenv }} if: ${{ github.repository_owner == 'pypa' || github.event_name != 'schedule' }} runs-on: ubuntu-latest + timeout-minutes: 20 strategy: matrix: noxenv: @@ -47,6 +48,9 @@ jobs: python -m pip install --upgrade nox virtualenv - name: Nox ${{ matrix.noxenv }} + env: + # Authenticate github.com requests during linkcheck to avoid rate limits. + GITHUB_TOKEN: ${{ github.token }} run: | python -m nox -s ${{ matrix.noxenv }} diff --git a/source/conf.py b/source/conf.py index 37d00dd55..fb0669bb5 100644 --- a/source/conf.py +++ b/source/conf.py @@ -161,7 +161,8 @@ # Ref: https://github.com/pypa/packaging.python.org/issues/1998 r"https://blog\.ganssle\.io/.*", ] -linkcheck_retries = 5 +linkcheck_retries = 2 +linkcheck_timeout = 30 # Ignore anchors for common targets when we know they likely won't be found linkcheck_anchors_ignore_for_url = [ # GitHub synthesises anchors in JavaScript, so Sphinx can't find them in the HTML @@ -171,6 +172,13 @@ # https://github.com/pypa/packaging.python.org/issues/1744 r"https://pypi\.org/", ] +# Authenticate requests to github.com (when a token is available) to avoid +# unauthenticated rate limits that can stall linkcheck for hours on CI. +if _gh_token := os.getenv("GITHUB_TOKEN"): + linkcheck_request_headers = { + "https://github.com/": {"Authorization": f"Bearer {_gh_token}"}, + "https://api.github.com/": {"Authorization": f"Bearer {_gh_token}"}, + } # -- Options for extlinks ---------------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/extensions/extlinks.html#configuration From aee19731528537df6d13e0cc0cb9a0c9eee4f760 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Wed, 15 Apr 2026 14:53:55 -0700 Subject: [PATCH 149/187] Update references from Travis to GitHub Actions --- source/guides/supporting-windows-using-appveyor.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/guides/supporting-windows-using-appveyor.rst b/source/guides/supporting-windows-using-appveyor.rst index e884dd976..b1394d606 100644 --- a/source/guides/supporting-windows-using-appveyor.rst +++ b/source/guides/supporting-windows-using-appveyor.rst @@ -21,7 +21,7 @@ can be a challenge, because setting up a suitable Windows test environment is non-trivial, and may require buying software licenses. The Appveyor service is a continuous integration service, much like the -better-known `Travis`_ service that is commonly used for testing by projects +better-known `GitHub Actions`_ service that is commonly used for testing by projects hosted on `GitHub`_. However, unlike Travis, the build workers on Appveyor are Windows hosts and have the necessary compilers installed to build Python extensions. @@ -237,6 +237,6 @@ For reference, the SDK setup support script is listed here: :linenos: .. _Appveyor: https://www.appveyor.com/ -.. _Travis: https://travis-ci.com/ .. _GitHub: https://github.com +.. _GitHub Actions: https://docs.github.com/en/actions .. _Bitbucket: https://bitbucket.org/ From debe3e1200561c97aab9b1f3efd397e34c6336e2 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Wed, 15 Apr 2026 14:56:19 -0700 Subject: [PATCH 150/187] Replace Travis CI with GitHub Actions in documentation --- source/guides/supporting-multiple-python-versions.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/source/guides/supporting-multiple-python-versions.rst b/source/guides/supporting-multiple-python-versions.rst index 7e945aa53..2e6d87f12 100644 --- a/source/guides/supporting-multiple-python-versions.rst +++ b/source/guides/supporting-multiple-python-versions.rst @@ -62,9 +62,8 @@ 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 - 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. + - `GitHub Actions `_ provides Windows, + Linux and a macOS environments. - `Appveyor `_ provides a Windows environment (Windows Server 2012). @@ -76,7 +75,7 @@ Windows: TODO How do we keep the Travis Linux and macOS versions up-to-date in this document? -Both `Travis CI`_ and Appveyor_ require a `YAML +Both `GitHub Actions`_ and Appveyor_ require a `YAML `_-formatted file as specification for the instructions for testing. If any tests fail, the output log for that specific configuration can be inspected. From 6616a37d747f7dd18487aa30e2b40ed7ffd07245 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Wed, 15 Apr 2026 15:01:03 -0700 Subject: [PATCH 151/187] Remove Travis mentions --- source/guides/supporting-windows-using-appveyor.rst | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/source/guides/supporting-windows-using-appveyor.rst b/source/guides/supporting-windows-using-appveyor.rst index b1394d606..b661024f7 100644 --- a/source/guides/supporting-windows-using-appveyor.rst +++ b/source/guides/supporting-windows-using-appveyor.rst @@ -20,12 +20,6 @@ Many projects are developed on Unix by default, and providing Windows support can be a challenge, because setting up a suitable Windows test environment is non-trivial, and may require buying software licenses. -The Appveyor service is a continuous integration service, much like the -better-known `GitHub Actions`_ service that is commonly used for testing by projects -hosted on `GitHub`_. However, unlike Travis, the build workers on Appveyor are -Windows hosts and have the necessary compilers installed to build Python -extensions. - Windows users typically do not have access to a C compiler, and therefore are reliant on projects that use C extensions distributing binary wheels on PyPI in order for the distribution to be installable via ``python -m pip install ``. By @@ -46,8 +40,7 @@ your project is hosted on one of those two services, setting up Appveyor integration is straightforward. Once you have set up your Appveyor account and added your project, Appveyor will -automatically build your project each time a commit occurs. This behaviour will -be familiar to users of Travis. +automatically build your project each time a commit occurs. Adding Appveyor support to your project ======================================= @@ -179,7 +172,7 @@ other CI systems). 2. When used interactively, ``tox`` allows you to run your tests against multiple environments (often, this means multiple Python versions). This feature is not as - useful in a CI environment like Travis or Appveyor, where all tests are run in + useful in a CI environment like Appveyor, where all tests are run in isolated environments for each configuration. As a result, projects often supply an argument ``-e ENVNAME`` to ``tox`` to specify which environment to use (there are default environments for most versions of Python). From c628d80cd0fd9387392abdb7c0325e34201b9242 Mon Sep 17 00:00:00 2001 From: github-merge-queue <118344674+github-merge-queue@users.noreply.github.com> Date: Mon, 20 Apr 2026 06:55:20 +0000 Subject: [PATCH 152/187] Update uv_build version to 0.11.7 --- 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 4f1894414..8b5c9e91f 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.11.6, <0.12.0"] + requires = ["uv_build >= 0.11.7, <0.12.0"] build-backend = "uv_build" From 242b6b487725c239ebff0a40b8a0dd3e0be668d9 Mon Sep 17 00:00:00 2001 From: konstin Date: Mon, 20 Apr 2026 15:07:00 -0400 Subject: [PATCH 153/187] Remove kivy.org from linkcheck The cert for kivy.org is expired, failing the mandatory linkcheck. --- source/conf.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/conf.py b/source/conf.py index fb0669bb5..22b0e5e36 100644 --- a/source/conf.py +++ b/source/conf.py @@ -160,6 +160,8 @@ # Temporarily ignored due to expired TLS cert. # Ref: https://github.com/pypa/packaging.python.org/issues/1998 r"https://blog\.ganssle\.io/.*", + # Temporarily ignored due to expired TLS cert. + r"https://kivy.org/.*", ] linkcheck_retries = 2 linkcheck_timeout = 30 From 3bfdecb3d96ba7201c0ef9f96a0ef8133387d1c7 Mon Sep 17 00:00:00 2001 From: konstin Date: Mon, 20 Apr 2026 15:34:42 -0400 Subject: [PATCH 154/187] Don't block PRs on linkcheck Fixes https://github.com/pypa/packaging.python.org/issues/1998 Currently, linkcheck is blocking PRs if any link in the project isn't accessible. Due to the high number of links, this regularly blocks unrelated PRs (see https://github.com/pypa/packaging.python.org/pull/2018 for a recent example). This PR moves linkcheck to a separate, non-blocking check. It will still run on PRs and report a failure if a newly added link 404s (https://github.com/pypa/packaging.python.org/issues/1998#issuecomment-4002461573), but an unrelated failure won't block PRs anymore. We also run the check on a daily cron, so that links going away is surfaced separately from PRs. --- .github/workflows/linkcheck.yml | 51 +++++++++++++++++++++++++++++++++ .github/workflows/test.yml | 1 - 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/linkcheck.yml diff --git a/.github/workflows/linkcheck.yml b/.github/workflows/linkcheck.yml new file mode 100644 index 000000000..363aa5331 --- /dev/null +++ b/.github/workflows/linkcheck.yml @@ -0,0 +1,51 @@ +name: Test + +on: + push: + 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 + schedule: + - cron: '0 0 * * *' # Run daily at midnight UTC + workflow_call: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} + cancel-in-progress: true + +permissions: {} + +jobs: + build: + name: linkcheck + if: ${{ github.repository_owner == 'pypa' }} + runs-on: ubuntu-latest + timeout-minutes: 20 + + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + persist-credentials: false + + - name: Set up Python + uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 + with: + python-version: "3.11" + cache: 'pip' + cache-dependency-path: 'requirements.txt' + + - name: Install dependencies + run: | + python -m pip install --upgrade nox virtualenv + + - name: Nox linkcheck + env: + # Authenticate github.com requests during linkcheck to avoid rate limits. + GITHUB_TOKEN: ${{ github.token }} + run: | + python -m nox -s linkcheck diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8d230d6ba..60de1cb52 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -29,7 +29,6 @@ jobs: matrix: noxenv: - build - - linkcheck steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 From 3dcce6830e8a523dd6316d8c35d3438042d9e565 Mon Sep 17 00:00:00 2001 From: konstin Date: Mon, 20 Apr 2026 15:42:51 -0400 Subject: [PATCH 155/187] Separate cancel group --- .github/workflows/linkcheck.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/linkcheck.yml b/.github/workflows/linkcheck.yml index 363aa5331..9d14b3938 100644 --- a/.github/workflows/linkcheck.yml +++ b/.github/workflows/linkcheck.yml @@ -15,7 +15,7 @@ on: workflow_call: concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}-linkcheck cancel-in-progress: true permissions: {} From efca0b63dfd2ee95786bc68b4c6f80a6324f32a3 Mon Sep 17 00:00:00 2001 From: konstin Date: Tue, 21 Apr 2026 09:54:10 -0400 Subject: [PATCH 156/187] Remove unused github token from test.yml --- .github/workflows/test.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 60de1cb52..5f018615e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -47,9 +47,6 @@ jobs: python -m pip install --upgrade nox virtualenv - name: Nox ${{ matrix.noxenv }} - env: - # Authenticate github.com requests during linkcheck to avoid rate limits. - GITHUB_TOKEN: ${{ github.token }} run: | python -m nox -s ${{ matrix.noxenv }} From 0f9103fec8611f0271cde379ee838ff673330dde Mon Sep 17 00:00:00 2001 From: konstin Date: Sun, 3 May 2026 22:09:06 +0200 Subject: [PATCH 157/187] Review --- .github/workflows/linkcheck.yml | 51 --------------------------------- .github/workflows/test.yml | 12 ++++++++ 2 files changed, 12 insertions(+), 51 deletions(-) delete mode 100644 .github/workflows/linkcheck.yml diff --git a/.github/workflows/linkcheck.yml b/.github/workflows/linkcheck.yml deleted file mode 100644 index 9d14b3938..000000000 --- a/.github/workflows/linkcheck.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: Test - -on: - push: - 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 - schedule: - - cron: '0 0 * * *' # Run daily at midnight UTC - workflow_call: - -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}-linkcheck - cancel-in-progress: true - -permissions: {} - -jobs: - build: - name: linkcheck - if: ${{ github.repository_owner == 'pypa' }} - runs-on: ubuntu-latest - timeout-minutes: 20 - - steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - with: - persist-credentials: false - - - name: Set up Python - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 - with: - python-version: "3.11" - cache: 'pip' - cache-dependency-path: 'requirements.txt' - - - name: Install dependencies - run: | - python -m pip install --upgrade nox virtualenv - - - name: Nox linkcheck - env: - # Authenticate github.com requests during linkcheck to avoid rate limits. - GITHUB_TOKEN: ${{ github.token }} - run: | - python -m nox -s linkcheck diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5f018615e..4ce8a7b73 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,6 +11,8 @@ on: - synchronize # default - reopened # default - ready_for_review # used in PRs created from GitHub Actions workflows + schedule: + - cron: '0 0 * * *' # Run the linkcheck daily to surface failures independent of PRs workflow_call: concurrency: @@ -25,10 +27,17 @@ jobs: if: ${{ github.repository_owner == 'pypa' || github.event_name != 'schedule' }} runs-on: ubuntu-latest timeout-minutes: 20 + # Don't block PRs on linkcheck unrelated failures. + continue-on-error: ${{ matrix.ignore-errors || false }} strategy: + fail-fast: false matrix: noxenv: - build + - linkcheck + include: + - noxenv: linkcheck + ignore-errors: true steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 @@ -47,6 +56,9 @@ jobs: python -m pip install --upgrade nox virtualenv - name: Nox ${{ matrix.noxenv }} + env: + # Authenticate github.com requests during linkcheck to avoid rate limits. + GITHUB_TOKEN: ${{ matrix.noxenv == 'linkcheck' && github.token || '' }} run: | python -m nox -s ${{ matrix.noxenv }} From de82dfd66683f7cc7d03096eb3996890e021fd3f Mon Sep 17 00:00:00 2001 From: konstin Date: Sun, 3 May 2026 22:09:32 +0200 Subject: [PATCH 158/187] typo --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4ce8a7b73..1c98ddefc 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,7 +27,7 @@ jobs: if: ${{ github.repository_owner == 'pypa' || github.event_name != 'schedule' }} runs-on: ubuntu-latest timeout-minutes: 20 - # Don't block PRs on linkcheck unrelated failures. + # Don't block PRs on linkcheck unrelated failures continue-on-error: ${{ matrix.ignore-errors || false }} strategy: fail-fast: false From b5c65a863088d26f9e0e259b7a26aca8fe746ac1 Mon Sep 17 00:00:00 2001 From: konsti Date: Sun, 3 May 2026 22:36:15 +0200 Subject: [PATCH 159/187] Update .github/workflows/test.yml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 🇺🇦 Sviatoslav Sydorenko (Святослав Сидоренко) --- .github/workflows/test.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1c98ddefc..973d46a93 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,8 +11,6 @@ on: - synchronize # default - reopened # default - ready_for_review # used in PRs created from GitHub Actions workflows - schedule: - - cron: '0 0 * * *' # Run the linkcheck daily to surface failures independent of PRs workflow_call: concurrency: From 0cb306149e1453c1bb8d407475ae87f9a6fab93d Mon Sep 17 00:00:00 2001 From: konstin Date: Sun, 3 May 2026 22:38:58 +0200 Subject: [PATCH 160/187] Restructure linkcheck matrix per review --- .github/workflows/test.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 973d46a93..81ea4f054 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,17 +25,18 @@ jobs: if: ${{ github.repository_owner == 'pypa' || github.event_name != 'schedule' }} runs-on: ubuntu-latest timeout-minutes: 20 - # Don't block PRs on linkcheck unrelated failures - continue-on-error: ${{ matrix.ignore-errors || false }} + continue-on-error: >- + ${{ fromJSON(matrix.continue-on-error) }} strategy: - fail-fast: false matrix: noxenv: - build - - linkcheck + continue-on-error: + - false include: - noxenv: linkcheck - ignore-errors: true + continue-on-error: >- # Don't block PRs on linkcheck unrelated failures + ${{ toJSON(github.event_name == 'pull_request') }} steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 From c161b7baadf6b633954c1e2107ddbb4a59cf17f1 Mon Sep 17 00:00:00 2001 From: Herrtian <70463940+Herrtian@users.noreply.github.com> Date: Mon, 4 May 2026 20:08:24 +0200 Subject: [PATCH 161/187] Warn about artifact action behavior for wheel matrices --- ...-releases-using-github-actions-ci-cd-workflows.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) 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 a3d893c9f..de7aedf49 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 @@ -107,6 +107,15 @@ build the distribution packages. First, we'll define the job for building the dist packages of your project and storing them for later use: +.. warning:: + + This artifact configuration is intended for a single build job that uploads + one source distribution and one wheel. If you adapt it for several + platform-specific wheel jobs, use separate artifact names for each job and + adjust the download step accordingly. The v4+ artifact actions do not support + multiple jobs uploading to the same artifact; see + `actions/upload-artifact#472`_. + .. literalinclude:: github-actions-ci-cd-sample/publish-to-pypi.yml :language: yaml :start-at: jobs: @@ -228,6 +237,8 @@ sure that your release pipeline remains healthy! https://github.com/actions/download-artifact .. _`upload-artifact`: https://github.com/actions/upload-artifact +.. _`actions/upload-artifact#472`: + https://github.com/actions/upload-artifact/issues/472 .. _Secrets: https://docs.github.com/en/actions/reference/encrypted-secrets .. _Trusted Publishing: https://docs.pypi.org/trusted-publishers/ From c2b117966ee647240e3f69217103f92f3b61f901 Mon Sep 17 00:00:00 2001 From: Herrtian <70463940+Herrtian@users.noreply.github.com> Date: Tue, 5 May 2026 10:23:53 +0200 Subject: [PATCH 162/187] Shorten artifact note --- ...eleases-using-github-actions-ci-cd-workflows.rst | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) 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 de7aedf49..8af6f8c08 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 @@ -107,14 +107,11 @@ build the distribution packages. First, we'll define the job for building the dist packages of your project and storing them for later use: -.. warning:: +.. tip:: - This artifact configuration is intended for a single build job that uploads - one source distribution and one wheel. If you adapt it for several - platform-specific wheel jobs, use separate artifact names for each job and - adjust the download step accordingly. The v4+ artifact actions do not support - multiple jobs uploading to the same artifact; see - `actions/upload-artifact#472`_. + If you adapt this workflow to build multiple platform-specific wheels, use + uniquely named artifacts for each build job and adjust the download step + accordingly. .. literalinclude:: github-actions-ci-cd-sample/publish-to-pypi.yml :language: yaml @@ -237,8 +234,6 @@ sure that your release pipeline remains healthy! https://github.com/actions/download-artifact .. _`upload-artifact`: https://github.com/actions/upload-artifact -.. _`actions/upload-artifact#472`: - https://github.com/actions/upload-artifact/issues/472 .. _Secrets: https://docs.github.com/en/actions/reference/encrypted-secrets .. _Trusted Publishing: https://docs.pypi.org/trusted-publishers/ From abde967845ae11152687afa05bde062269fb8a03 Mon Sep 17 00:00:00 2001 From: TT <70463940+Herrtian@users.noreply.github.com> Date: Tue, 5 May 2026 16:57:45 +0200 Subject: [PATCH 163/187] Link cibuildwheel examples from artifact tip --- ...ibution-releases-using-github-actions-ci-cd-workflows.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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 8af6f8c08..3b5e6ed28 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 @@ -111,7 +111,8 @@ your project and storing them for later use: If you adapt this workflow to build multiple platform-specific wheels, use uniquely named artifacts for each build job and adjust the download step - accordingly. + accordingly. The `cibuildwheel GitHub Actions examples`_ show a fuller + wheel matrix layout. .. literalinclude:: github-actions-ci-cd-sample/publish-to-pypi.yml :language: yaml @@ -237,3 +238,5 @@ sure that your release pipeline remains healthy! .. _Secrets: https://docs.github.com/en/actions/reference/encrypted-secrets .. _Trusted Publishing: https://docs.pypi.org/trusted-publishers/ +.. _`cibuildwheel GitHub Actions examples`: + https://cibuildwheel.pypa.io/en/latest/ci-services/#github-actions From c1caf2e4270a7420efb788e4957c7e3a5667c9b7 Mon Sep 17 00:00:00 2001 From: Evgenii Prusov Date: Fri, 8 May 2026 12:45:56 +0200 Subject: [PATCH 164/187] The document is now maintained as a PyPA specification. --- 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 20e055327..f4da9ad99 100644 --- a/source/specifications/pyproject-toml.rst +++ b/source/specifications/pyproject-toml.rst @@ -215,7 +215,7 @@ If the file path ends in a case-insensitive ``.md`` suffix, then tools MUST assume the content-type is ``text/markdown``. If the file path ends in a case-insensitive ``.rst``, then tools MUST assume the content-type is ``text/x-rst``. If a tool recognizes more extensions -than this PEP, they MAY infer the content-type for the user without +than this specification, they MAY infer the content-type for the user without specifying this key as ``dynamic``. For all unrecognized suffixes when a content-type is not provided, tools MUST raise an error. From 840fea9f5d4fd246b5d2bfda74d113dca8899e54 Mon Sep 17 00:00:00 2001 From: Evgenii Prusov Date: Fri, 8 May 2026 13:08:43 +0200 Subject: [PATCH 165/187] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- 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 f4da9ad99..01cef9686 100644 --- a/source/specifications/pyproject-toml.rst +++ b/source/specifications/pyproject-toml.rst @@ -215,7 +215,7 @@ If the file path ends in a case-insensitive ``.md`` suffix, then tools MUST assume the content-type is ``text/markdown``. If the file path ends in a case-insensitive ``.rst``, then tools MUST assume the content-type is ``text/x-rst``. If a tool recognizes more extensions -than this specification, they MAY infer the content-type for the user without +than this specification, it MAY infer the content-type for the user without specifying this key as ``dynamic``. For all unrecognized suffixes when a content-type is not provided, tools MUST raise an error. From 32bc5cbf5507c62b0412200eb6fecb6f85e8a80e Mon Sep 17 00:00:00 2001 From: Alyssa Coghlan Date: Mon, 18 May 2026 00:02:02 +1000 Subject: [PATCH 166/187] Allow ignoring packages with unknown markers --- source/specifications/dependency-specifiers.rst | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/source/specifications/dependency-specifiers.rst b/source/specifications/dependency-specifiers.rst index 57a201e73..521fee18c 100644 --- a/source/specifications/dependency-specifiers.rst +++ b/source/specifications/dependency-specifiers.rst @@ -334,13 +334,15 @@ contain non-ASCII text that users wish to perform comparisons against. Unknown marker fields ''''''''''''''''''''' -References to unknown marker fields SHOULD raise an error rather than resulting -in a comparison that evaluates to True or False. This is so that attempted -installations involving unknown marker fields result in a clear installation -failure, rather than an apparently successful installation that then fails at -runtime due to missing dependencies (if the unknown marker is treated as -False) or a potentially cryptic installation failure of a dependency that is -not valid for the current platform (if the unknown marker is treated as True) +References to unknown marker fields SHOULD render a package version ineligible +for installation or inclusion in a locked dependency tree rather than resulting +in a comparison that evaluates to True or False. This is so that published +package versions with unknown marker fields are either ignored when resolving +dependencies or emit a descriptive installation failure, rather than producing +an apparently successful installation that then fails at runtime due to missing +dependencies (if the unknown marker is treated as False) or a potentially +cryptic installation failure of a dependency that is not valid for the +current platform (if the unknown marker is treated as True). Variables whose value cannot be calculated on a given Python implementation should evaluate to ``0`` for ``Version`` fields, and an empty string for all From 14f2097a75c2acb5d97ecdcf5f51a5aeb20c4686 Mon Sep 17 00:00:00 2001 From: Alyssa Coghlan Date: Mon, 18 May 2026 00:02:33 +1000 Subject: [PATCH 167/187] Attempt to clarify legacy extra syntax definition --- .../specifications/dependency-specifiers.rst | 44 ++++++++++++------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/source/specifications/dependency-specifiers.rst b/source/specifications/dependency-specifiers.rst index 521fee18c..56620834d 100644 --- a/source/specifications/dependency-specifiers.rst +++ b/source/specifications/dependency-specifiers.rst @@ -442,27 +442,39 @@ of the following marker fields: SHOULD NOT accept uploads containing such environment markers) For backwards compatibility with older locking and installation tools, the -``extras`` and ``dependency_groups`` fields are currently only considered -valid in :ref:`lock files ` (where they allow consumers of the -lock file to selectively install optional parts of the locked dependency tree). -Publishing tools SHOULD emit an error if projects attempt to use them in their -published metadata, and index servers SHOULD NOT accept uploads referencing +``extras`` and ``dependency_groups`` fields are currently only valid for use in +``packages.marker`` fields in :ref:`lock files `. For these +comparisons, the ``extras`` and ``dependency_groups`` sets used for the marker +evaluation refer to the *currently selected* extras and dependency groups when +installing from the lock file, not the full set of defined extras and dependency +groups listed in the corresponding top level lock file fields. The interface +for selecting which extras and dependency groups to install is tool dependent. +Publishing tools SHOULD emit an error if projects attempt to reference the +``extras`` or ``dependency_groups`` fields in their published dependency +declaration metadata, and index servers SHOULD NOT accept uploads referencing these fields. Outside lock file processing, marker evaluation environments DO NOT need to define these fields. The ``extra`` field is also special, as it expects set-like behaviour, but predates the addition of ``Set of strings`` as a defined marker field type. -Accordingly, for this field only, ``extra == "name"`` is equivalent to -``"name" in extras``, while ``extra != "name"`` is equivalent to -``"name" not in extras``. Other comparison operations on ``extra`` are not -defined and publishing tools SHOULD emit an error, index servers MAY disallow -uploads containing such environment markers, while locking and -installation tools SHOULD evaluate them as False. Unlike the newer ``extras`` -field, environment markers using this field SHOULD be accepted by both -publishing tools and index servers. Marker evaluation environments intended -for project dependency declarations will typically need to handle evaluation -of ``extra`` field comparisons, while other evaluations of environment markers -will not generally need to do so. +Accordingly, ``extra == "name"`` in a dependency declaration is similar to +``"name" in extras``, while ``extra != "name"`` is similar to +``"name" not in extras``. For dependency marker evaluations, the set of extra +names used for these comparisons is the full set of requested extras for *that +particular package*, whether requested directly in a top level dependency +declaration, or indirectly in a transitive dependency declaration. Other +comparison operations on ``extra`` are not defined and publishing tools SHOULD +emit an error, index servers MAY disallow uploads containing such environment +markers, while locking and installation tools SHOULD evaluate them as False. + +Unlike the newer ``extras`` field, environment markers using this field SHOULD +be accepted by both publishing tools and index servers. Marker evaluation +environments intended for project dependency declarations will typically need +to handle evaluation of ``extra`` field comparisons, while other evaluations +of environment markers will not generally need to do so. The legacy ``extra`` +comparison syntax is NOT permitted in lock file ``packages.marker`` fields, +and installation tools SHOULD reject lock files containing such comparisons as +invalid. The ``implementation_version`` marker variable is derived from :py:data:`sys.implementation.version `: From 7f5f080346641748ae416ef96ca62f012d9401e3 Mon Sep 17 00:00:00 2001 From: Alyssa Coghlan Date: Mon, 18 May 2026 00:10:36 +1000 Subject: [PATCH 168/187] Omit Jython from implementation examples --- source/specifications/dependency-specifiers.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/specifications/dependency-specifiers.rst b/source/specifications/dependency-specifiers.rst index 56620834d..d66f77503 100644 --- a/source/specifications/dependency-specifiers.rst +++ b/source/specifications/dependency-specifiers.rst @@ -383,7 +383,7 @@ of the following marker fields: * - ``platform_python_implementation`` - :py:func:`platform.python_implementation()` - String - - ``CPython``, ``PyPy``, ``Jython`` + - ``CPython``, ``PyPy`` * - ``platform_release`` - :py:func:`platform.release()` - Version | String From aadd402f6eac903b776dfbed87f81494493af2bc Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Thu, 21 May 2026 15:25:45 -0400 Subject: [PATCH 169/187] sdist: fix normative language around pax Signed-off-by: William Woodruff --- source/specifications/source-distribution-format.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/specifications/source-distribution-format.rst b/source/specifications/source-distribution-format.rst index 9ac93be7b..b877e87d5 100644 --- a/source/specifications/source-distribution-format.rst +++ b/source/specifications/source-distribution-format.rst @@ -74,7 +74,7 @@ at their respective paths relative to the root directory of the sdist No other content of a sdist is required or defined. Build systems can store whatever information they need in the sdist to build the project. -The tarball should use the modern POSIX.1-2001 pax tar format, which specifies +The tarball must use the modern POSIX.1-2001 pax tar format, which specifies UTF-8 based file names. In particular, source distribution files must be readable using the standard library tarfile module with the open flag 'r:gz'. From 6bc3430fa6c48683e49e0481acacb6d0477587de Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Tue, 2 Jun 2026 16:06:01 -0400 Subject: [PATCH 170/187] Add a PEP 833 callout to the simple API spec Signed-off-by: William Woodruff --- source/specifications/simple-repository-api.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/source/specifications/simple-repository-api.rst b/source/specifications/simple-repository-api.rst index d317db6f7..f07cc8e5b 100644 --- a/source/specifications/simple-repository-api.rst +++ b/source/specifications/simple-repository-api.rst @@ -122,6 +122,15 @@ HTML Serialization .. _simple-repository-html-project-list: +.. important:: + + The HTML representation is considered "frozen" and is not expected + to be updated. Producers and consumers of the simple API + should prefer the :ref:`JSON representation `. + + See :pep:`833` for additional information about the HTML representation's + status. + The following constraints apply to all HTML serialized responses described in this spec: @@ -989,3 +998,4 @@ History * November 2024: provenance metadata in the HTML and JSON formats, in :pep:`740` * July 2025: project status markers in the HTML and JSON formats, in :pep:`792` * July 2025: layout changes (dedicated page for file yanking, introduce concepts before API details) +* June 2026: :pep:`833` formally "freezes" the HTML representation of the simple API \ No newline at end of file From 9a9aca9dc04ce7ecb782b7c07722598e03d979dd Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Tue, 2 Jun 2026 16:11:16 -0400 Subject: [PATCH 171/187] Fix EOF Signed-off-by: William Woodruff --- source/specifications/simple-repository-api.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/specifications/simple-repository-api.rst b/source/specifications/simple-repository-api.rst index f07cc8e5b..d7e14a4d3 100644 --- a/source/specifications/simple-repository-api.rst +++ b/source/specifications/simple-repository-api.rst @@ -998,4 +998,4 @@ History * November 2024: provenance metadata in the HTML and JSON formats, in :pep:`740` * July 2025: project status markers in the HTML and JSON formats, in :pep:`792` * July 2025: layout changes (dedicated page for file yanking, introduce concepts before API details) -* June 2026: :pep:`833` formally "freezes" the HTML representation of the simple API \ No newline at end of file +* June 2026: :pep:`833` formally "freezes" the HTML representation of the simple API From 580a764d19c22a065cdfc1c2246e4509e48faa8b Mon Sep 17 00:00:00 2001 From: github-merge-queue <118344674+github-merge-queue@users.noreply.github.com> Date: Mon, 15 Jun 2026 08:14:37 +0000 Subject: [PATCH 172/187] Update uv_build version to 0.11.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 8b5c9e91f..ad9a65959 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.11.7, <0.12.0"] + requires = ["uv_build >= 0.11.21, <0.12.0"] build-backend = "uv_build" From e9ceddf1f4c1f2cfc0a1cadf4fdbe388bf98906f Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Tue, 16 Jun 2026 06:21:46 -0400 Subject: [PATCH 173/187] Add a Sphinx label for the `.dist-info/sboms/` sections --- source/specifications/binary-distribution-format.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/specifications/binary-distribution-format.rst b/source/specifications/binary-distribution-format.rst index e9cbcb53d..a6f141851 100644 --- a/source/specifications/binary-distribution-format.rst +++ b/source/specifications/binary-distribution-format.rst @@ -276,6 +276,8 @@ fields is specified, the :file:`.dist-info/` directory MUST contain a ``License-File`` fields in the :file:`METADATA` file at their respective paths relative to the :file:`licenses/` directory. +.. _dist-info-sbom-directory: + The :file:`.dist-info/sboms/` directory ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 4ab278a0e0fd01648a4fc0385af1ae22deb1fd3b Mon Sep 17 00:00:00 2001 From: github-merge-queue <118344674+github-merge-queue@users.noreply.github.com> Date: Mon, 22 Jun 2026 08:15:01 +0000 Subject: [PATCH 174/187] Update uv_build version to 0.11.23 --- 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 ad9a65959..6ff17eed2 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.11.21, <0.12.0"] + requires = ["uv_build >= 0.11.23, <0.12.0"] build-backend = "uv_build" From e0afd28b79a427c0cfdd224f9cbcd6a48bb3a09e Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Thu, 2 Jul 2026 14:46:09 -0400 Subject: [PATCH 175/187] docs: fix link to activestate python As far as I can tell, this is roughly the equivalent link now. Signed-off-by: Henry Schreiner --- source/overview.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/overview.rst b/source/overview.rst index 70ef2d058..d7b3efdaf 100644 --- a/source/overview.rst +++ b/source/overview.rst @@ -279,7 +279,7 @@ A similar model involves installing an alternative Python distribution, but does not support arbitrary operating system-level packages: -* `ActiveState ActivePython `_ +* `ActiveState ActivePython `_ * `WinPython `_ .. _bringing-your-own-python: From 053f40e9b42ee5d0b0bd4d146b9866ba5a372173 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Sun, 12 Jul 2026 12:14:44 +0100 Subject: [PATCH 176/187] Clarify handling of script metadata --- source/specifications/inline-script-metadata.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/source/specifications/inline-script-metadata.rst b/source/specifications/inline-script-metadata.rst index 6fa832a3e..0f0285307 100644 --- a/source/specifications/inline-script-metadata.rst +++ b/source/specifications/inline-script-metadata.rst @@ -70,6 +70,17 @@ and the regular expression, the text specification takes precedence. Tools MUST NOT read from metadata blocks with types that have not been standardized by this specification. +Note that the specification only requires that *top-level* comment blocks are +recognised as containing metadata. However, parsing Python code is non-trivial, +and therefore: + +* Tools MAY choose to do a simple textual scan, rather than a full Python parse. + For example, the canonical regular expression provided above does a textual + scan. +* As a result of the previous point, the behaviour of scripts that contain data + that looks like metadata within another Python construct such as a multi-line + string is tool-dependent and should not be relied on. + script type ----------- From 9dd85f27266c88c4eca58828c918c337b665d331 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Mon, 13 Jul 2026 16:49:48 +0100 Subject: [PATCH 177/187] Reorganise bullet points --- source/specifications/inline-script-metadata.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/specifications/inline-script-metadata.rst b/source/specifications/inline-script-metadata.rst index 0f0285307..f9df2f0f5 100644 --- a/source/specifications/inline-script-metadata.rst +++ b/source/specifications/inline-script-metadata.rst @@ -75,11 +75,11 @@ recognised as containing metadata. However, parsing Python code is non-trivial, and therefore: * Tools MAY choose to do a simple textual scan, rather than a full Python parse. - For example, the canonical regular expression provided above does a textual - scan. * As a result of the previous point, the behaviour of scripts that contain data that looks like metadata within another Python construct such as a multi-line string is tool-dependent and should not be relied on. +* The canonical regular expression provided above is an example of an + implementation that does a simple textual scan. script type ----------- From 71fd79232efb88eeb5795914f422b464795e08f1 Mon Sep 17 00:00:00 2001 From: LaRoyBot <104553600+LaRoyBot@users.noreply.github.com> Date: Wed, 22 Jul 2026 22:21:42 +0530 Subject: [PATCH 178/187] docs: fix typo e. g. to e.g. in dropping older python versions guide --- source/guides/dropping-older-python-versions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/guides/dropping-older-python-versions.rst b/source/guides/dropping-older-python-versions.rst index 267d7b923..223b65cd0 100644 --- a/source/guides/dropping-older-python-versions.rst +++ b/source/guides/dropping-older-python-versions.rst @@ -89,7 +89,7 @@ such as at least Python 3.9. Or, at least Python 3.7 and beyond, skipping the 3. If using the :ref:`setuptools` build backend, consult the `dependency-management`_ documentation for more options. .. caution:: - Avoid adding upper bounds to the version ranges, e. g. ``">= 3.8, < 3.10"``. Doing so can cause different errors + Avoid adding upper bounds to the version ranges, e.g. ``">= 3.8, < 3.10"``. Doing so can cause different errors and version conflicts. See the `discourse-discussion`_ for more information. 3. Validating the Metadata before publishing From cc74d9756b4a402d3458978eddfe084e8ac18926 Mon Sep 17 00:00:00 2001 From: Ee Durbin Date: Wed, 22 Jul 2026 16:47:23 -0400 Subject: [PATCH 179/187] ignore clickpy.clickhouse.com -- cloudflare challenge --- source/conf.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/conf.py b/source/conf.py index 22b0e5e36..4516880ec 100644 --- a/source/conf.py +++ b/source/conf.py @@ -148,6 +148,8 @@ # Ignore while StackOverflow is blocking GitHub CI. Ref: # https://github.com/pypa/packaging.python.org/pull/1474 r"https://stackoverflow\.com/.*", + # Cloudflare challenge blocks automated link checking. + r"https://clickpy\.clickhouse\.com/$", r"https://pyscaffold\.org/.*", r"https://anaconda\.org", r"https://www\.cisa\.gov/sbom", From 85f5b43f5c94b6deedc61d494c6b8b0c3aad7094 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Mon, 29 Jun 2026 16:00:17 -0400 Subject: [PATCH 180/187] chore: use non-legacy hook name for ruff-check Signed-off-by: Henry Schreiner --- .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 47b864808..6d8d4e78b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -39,5 +39,5 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.14.10 hooks: - - id: ruff + - id: ruff-check - id: ruff-format From 428e3129132721c0fa88e97af918e88ab416dcc7 Mon Sep 17 00:00:00 2001 From: github-merge-queue <118344674+github-merge-queue@users.noreply.github.com> Date: Mon, 27 Jul 2026 07:17:21 +0000 Subject: [PATCH 181/187] Update uv_build version to 0.11.32 --- 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 6ff17eed2..27fda9666 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.11.23, <0.12.0"] + requires = ["uv_build >= 0.11.32, <0.12.0"] build-backend = "uv_build" From bf702d2d3d88fa88a6f48db0049f99b9c170c5a3 Mon Sep 17 00:00:00 2001 From: woodruffw <3059210+woodruffw@users.noreply.github.com> Date: Wed, 29 Jul 2026 19:57:19 +0000 Subject: [PATCH 182/187] Update uv_build version to 0.12.0 --- 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 27fda9666..70029a72c 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.11.32, <0.12.0"] + requires = ["uv_build >= 0.12.0, <0.13.0"] build-backend = "uv_build" From 460400dc5899e6b3b9f7604e567f942af077495b Mon Sep 17 00:00:00 2001 From: Jonathan Dung Date: Fri, 31 Jul 2026 18:56:03 +0800 Subject: [PATCH 183/187] Fix dependency group resolution snippet --- source/specifications/dependency-groups.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/specifications/dependency-groups.rst b/source/specifications/dependency-groups.rst index 2fa82cd90..a8f5b8bca 100644 --- a/source/specifications/dependency-groups.rst +++ b/source/specifications/dependency-groups.rst @@ -209,8 +209,8 @@ The output is therefore valid ``requirements.txt`` data. realized_group = [] for item in raw_group: if isinstance(item, str): - # packaging.requirements.Requirement parsing ensures that this - # is a valid dependency specifier + # packaging.requirements.Requirement parsing ensures that this is a valid + # PEP 508 Dependency Specifier # raises InvalidRequirement on failure Requirement(item) realized_group.append(item) @@ -232,7 +232,7 @@ The output is therefore valid ``requirements.txt`` data. def resolve(dependency_groups: dict, group: str) -> list[str]: if not isinstance(dependency_groups, dict): - raise TypeError("Dependency Groups table is not a dict") + raise TypeError("Dependency groups table is not a dict") if not isinstance(group, str): raise TypeError("Dependency group name is not a str") return _resolve_dependency_group(dependency_groups, group) @@ -244,7 +244,7 @@ The output is therefore valid ``requirements.txt`` data. dependency_groups_raw = pyproject["dependency-groups"] dependency_groups = _normalize_group_names(dependency_groups_raw) - print("\n".join(resolve(pyproject["dependency-groups"], sys.argv[1]))) + print("\n".join(resolve(dependency_groups, sys.argv[1]))) History ======= From f5a23789b496ff2ff49ba1ecebb3aa792ddafe2c Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Mon, 29 Jun 2026 15:59:07 -0400 Subject: [PATCH 184/187] feat: add METADATA 2.6 (PEP 808) This selects the 'append only' choice from the acceptence of PEP 808. I started this by hand, then tried Claude Opus 4.8, feeding PEP 808 into the context, and it did a better job of finding places that needed updating than I did, so I ended up using that as the base, editing it to the current form. Assisted-by: ClaudeCode:claude-opus-4.8 Signed-off-by: Henry Schreiner --- source/specifications/core-metadata.rst | 22 +++++++++--- source/specifications/pyproject-toml.rst | 45 ++++++++++++++++++++++-- 2 files changed, 61 insertions(+), 6 deletions(-) diff --git a/source/specifications/core-metadata.rst b/source/specifications/core-metadata.rst index 0cd05f9fa..b6fd009e2 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.5, approved in September 2025. +This page describes version 2.6, approved in May 2026. 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", "2.4", and "2.5". +"2.2", "2.3", "2.4", "2.5", and "2.6". Automated tools consuming metadata SHOULD warn if ``metadata-version`` is greater than the highest version they support, and MUST fail if @@ -109,6 +109,10 @@ Dynamic (multiple use) ====================== .. versionadded:: 2.2 +.. versionchanged:: 2.6 + A multiple use field that is present in the sdist and also marked + ``Dynamic`` may only be appended to in a wheel built from the sdist. + Previously any field listed in Dynamic was ignored in an sdist. A string containing the name of another core metadata field. The field names ``Name``, ``Version``, and ``Metadata-Version`` may not be specified @@ -121,8 +125,12 @@ rules apply: in any wheel built from the sdist MUST match the value in the sdist. If the field is not in the sdist, and not marked as ``Dynamic``, then it MUST NOT be present in the wheel. -2. If a field is marked as ``Dynamic``, it may contain any valid value in - a wheel built from the sdist (including not being present at all). +2. If a single-use field is marked as ``Dynamic``, it may contain any valid + value in a wheel built from the sdist (including not being present at all). +3. If a multiple use field is present in the sdist and also marked ``Dynamic``, + then a wheel built from the sdist MUST include the value(s) present in the + sdist. The wheel MAY add further values, but it MUST NOT remove, reorder, or + modify the values present in the sdist. If the sdist metadata version is older than version 2.2, then all fields should be treated as if they were specified with ``Dynamic`` (i.e. there are no special @@ -1074,6 +1082,12 @@ History - January 2026: Replaced outdated direct reference to :pep:`508` with a reference to :ref:`dependency-specifiers`. +- May 2026: Core metadata 2.6 was approved through :pep:`808`. + + - Allowed a multiple use field marked ``Dynamic`` to be appended to in a + wheel built from a sdist, requiring the wheel to preserve the value(s) + present in the sdist. + ---- .. [1] reStructuredText markup: diff --git a/source/specifications/pyproject-toml.rst b/source/specifications/pyproject-toml.rst index b4625bbb2..695b6e7f7 100644 --- a/source/specifications/pyproject-toml.rst +++ b/source/specifications/pyproject-toml.rst @@ -114,6 +114,13 @@ by the metadata). Dynamic metadata is listed via the ``dynamic`` key (defined later in this specification) and represents metadata that a tool will later provide. +A key whose value is a list or a table of arbitrary entries MAY be +specified statically *and* listed in ``dynamic`` at the same time. In +that case the entries given statically are fixed and a build back-end +MAY only *append* further entries to them; the back-end MUST NOT +remove, reorder, or modify any statically-specified entries. See the +:ref:`dynamic ` key for details. + The lack of a ``[project]`` table implicitly means the :term:`build backend ` will dynamically provide all keys. @@ -619,8 +626,9 @@ provided via tooling later on. field as "Optional", the metadata MAY list it in ``dynamic`` if the expectation is a build back-end will provide the data for the key later. -- Build back-ends MUST raise an error if the metadata specifies a - key statically as well as being listed in ``dynamic``. +- Build back-ends MUST raise an error if the metadata specifies a key + statically as well as being listed in ``dynamic``, *unless* the key + represents a list or arbitrary table that can be extended, listed below. - If the metadata does not list a key in ``dynamic``, then a build back-end CANNOT fill in the requisite metadata on behalf of the user (i.e. ``dynamic`` is the only way to allow a tool to fill in @@ -630,6 +638,35 @@ provided via tooling later on. the data for it (omitting the data, if determined to be the accurate value, is acceptable). +A key whose value is a list or a table of arbitrary entries MAY be +specified statically and listed in ``dynamic`` simultaneously. The +keys fitting that description are: + +- ``authors`` +- ``classifiers`` +- ``dependencies`` +- ``entry-points`` +- ``gui-scripts`` +- ``import-names`` +- ``import-namespaces`` +- ``keywords`` +- ``license-files`` +- ``maintainers`` +- ``optional-dependencies`` +- ``scripts`` +- ``urls`` + +When such a key is specified both statically and listed in +``dynamic``: + +- A build back-end MAY only *append* entries to the value; it MUST NOT + remove, reorder, or modify any statically-specified entries. For + tables (such as ``optional-dependencies`` or ``entry-points``) this + means a back-end MAY add new keys and MAY append to the values of + existing keys (in the case of a list), but MUST NOT change or remove the + entries given statically. +- A build back-end SHOULD raise an error if a key is listed in + ``dynamic`` and it does not support extending that key. .. _pyproject-tool-table: @@ -673,4 +710,8 @@ History - January 2026: Replaced outdated direct reference to :pep:`508` with a reference to :ref:`dependency-specifiers`. +- May 2026: Allowed list and table keys to be specified statically as well + as listed in ``dynamic``, with build back-ends only able to append + entries, through :pep:`808`. + .. _TOML: https://toml.io From cdb4bf7ce8de9263fc3ec9e4c46117f49c4f72c5 Mon Sep 17 00:00:00 2001 From: Jonathan Dung Date: Sun, 2 Aug 2026 17:08:06 +0800 Subject: [PATCH 185/187] Update comment --- source/specifications/dependency-groups.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/specifications/dependency-groups.rst b/source/specifications/dependency-groups.rst index a8f5b8bca..2fa758f7e 100644 --- a/source/specifications/dependency-groups.rst +++ b/source/specifications/dependency-groups.rst @@ -209,8 +209,8 @@ The output is therefore valid ``requirements.txt`` data. realized_group = [] for item in raw_group: if isinstance(item, str): - # packaging.requirements.Requirement parsing ensures that this is a valid - # PEP 508 Dependency Specifier + # packaging.requirements.Requirement parsing ensures that this + # is a valid dependency specifier # raises InvalidRequirement on failure Requirement(item) realized_group.append(item) From a69a69f638781c522a42b6eaf061ef3b045f1220 Mon Sep 17 00:00:00 2001 From: github-merge-queue <118344674+github-merge-queue@users.noreply.github.com> Date: Mon, 3 Aug 2026 07:16:47 +0000 Subject: [PATCH 186/187] Update uv_build version to 0.12.1 --- 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 70029a72c..f71f25112 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.12.0, <0.13.0"] + requires = ["uv_build >= 0.12.1, <0.13.0"] build-backend = "uv_build" From 90174bb0614df3780ce0a921793aa6feece87231 Mon Sep 17 00:00:00 2001 From: Eisuke Kawashima Date: Fri, 7 Aug 2026 17:29:11 +0900 Subject: [PATCH 187/187] docs: bump flit upper bound fix #2077 --- 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 f71f25112..5f3e0bf4c 100644 --- a/source/shared/build-backend-tabs.rst +++ b/source/shared/build-backend-tabs.rst @@ -22,7 +22,7 @@ .. code-block:: toml [build-system] - requires = ["flit_core >= 3.12.0, <4"] + requires = ["flit_core >= 3.12.0, <5"] build-backend = "flit_core.buildapi" .. tab:: PDM