From 0b95c27e9e3fe5fef324c8743b3cad46bad25910 Mon Sep 17 00:00:00 2001 From: Alyssa Coghlan Date: Sat, 10 Jan 2026 16:33:29 +1000 Subject: [PATCH 01/42] 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 02/42] [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 fd2c2e2752ff9255ce5ee6cb8181627281cf9248 Mon Sep 17 00:00:00 2001 From: Alyssa Coghlan Date: Sat, 24 Jan 2026 21:10:00 +1000 Subject: [PATCH 03/42] 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 04/42] 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 05/42] 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 06/42] 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 6d887c3e6a99b8631055648f2a946e17398b254f Mon Sep 17 00:00:00 2001 From: Alyssa Coghlan Date: Mon, 2 Mar 2026 22:14:00 +1000 Subject: [PATCH 07/42] 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 aed069454738f638cf9fa8b39010549aba05262f Mon Sep 17 00:00:00 2001 From: Herrtian <70463940+Herrtian@users.noreply.github.com> Date: Fri, 8 May 2026 10:24:03 +0200 Subject: [PATCH 08/42] Document separate build and publish jobs --- ...bution-releases-using-github-actions-ci-cd-workflows.rst | 6 ++++++ 1 file changed, 6 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 3b5e6ed28..035a8af8a 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 @@ -104,6 +104,12 @@ We will have to define two jobs to publish to PyPI and TestPyPI respectively, and an additional job to build the distribution packages. +.. important:: + + Keep the build job separate from the publishing jobs. Building + distributions in a publishing job is unsupported; publishing jobs should + only download the already-built artifacts and upload them. + First, we'll define the job for building the dist packages of your project and storing them for later use: From c1caf2e4270a7420efb788e4957c7e3a5667c9b7 Mon Sep 17 00:00:00 2001 From: Evgenii Prusov Date: Fri, 8 May 2026 12:45:56 +0200 Subject: [PATCH 09/42] 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 10/42] 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 11/42] 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 12/42] 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 13/42] 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 14/42] 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 95fd4ab22a0a00a9f4f105aab76ec6071d74729c Mon Sep 17 00:00:00 2001 From: Zander Milroy Date: Mon, 1 Jun 2026 12:18:30 -0400 Subject: [PATCH 15/42] Removes reference to withdrawn PEP 459 Removes recommendation for local version identifier metadata. Resolves #1503 --- source/specifications/version-specifiers.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/source/specifications/version-specifiers.rst b/source/specifications/version-specifiers.rst index e05422ce2..75093c2e2 100644 --- a/source/specifications/version-specifiers.rst +++ b/source/specifications/version-specifiers.rst @@ -172,9 +172,6 @@ identified by the public version identifier, but contains additional changes indexing and hosting upstream projects, it MUST NOT allow the use of local version identifiers. -Source distributions using a local version identifier SHOULD provide the -``python.integrator`` extension metadata (as defined in :pep:`459`). - Final releases -------------- From 6bc3430fa6c48683e49e0481acacb6d0477587de Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Tue, 2 Jun 2026 16:06:01 -0400 Subject: [PATCH 16/42] 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 17/42] 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 18/42] 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 19/42] 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 20/42] 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 21/42] 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 ab07e44e92d471f4b8156946d5e091eedeabb5b5 Mon Sep 17 00:00:00 2001 From: Hugo Date: Fri, 10 Jul 2026 10:21:48 +0100 Subject: [PATCH 22/42] Document self-referential extras now that pip officially supports it Relevant PR: https://github.com/pypa/pip/pull/14157 Relevant Issue: https://github.com/pypa/pip/issues/11296 --- source/guides/writing-pyproject-toml.rst | 17 +++++++++++++++++ source/specifications/pyproject-toml.rst | 7 +++++++ 2 files changed, 24 insertions(+) diff --git a/source/guides/writing-pyproject-toml.rst b/source/guides/writing-pyproject-toml.rst index 92a7f25bf..6ce28553e 100644 --- a/source/guides/writing-pyproject-toml.rst +++ b/source/guides/writing-pyproject-toml.rst @@ -175,6 +175,22 @@ Each of the keys defines a "packaging extra". In the example above, one could use, e.g., ``pip install your-project-name[gui]`` to install your project with GUI support, adding the PyQt5 dependency. +.. _self-referential-extras: + +You can also define an extra that refers back to the same project with +other extras. This is useful for convenience extras that combine several +optional features without duplicating their dependency lists: + +.. code-block:: toml + + all = ["your-project-name[gui, cli]"] + +Installing ``your-project-name[all]`` then installs both the ``gui`` and +``cli`` dependencies. You can also list extras separately, for example +``["your-project-name[gui]", "your-project-name[cli]"]``. The name in the +requirement must match the project's ``name`` field. Installers such as +:ref:`pip` and :ref:`uv` support this pattern already (pip since v21.2). + .. _requires-python: .. _python_requires: @@ -555,6 +571,7 @@ A full example "rich", "click", ] + all = ["spam-eggs[gui, cli]"] [project.urls] Homepage = "https://example.com" diff --git a/source/specifications/pyproject-toml.rst b/source/specifications/pyproject-toml.rst index b4625bbb2..4b5a4a780 100644 --- a/source/specifications/pyproject-toml.rst +++ b/source/specifications/pyproject-toml.rst @@ -498,6 +498,13 @@ 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. +A dependency specifier in an extra MAY name the project itself with other extras +(for example, ``all = ["spam[gui, cli]"]``). That way a combined extra does not +need its own manually maintained copy of each referenced extra's dependencies, +which can otherwise fall out of sync. Installers that support self-referential +extras will be able to install the union of these extras' dependencies. See +:ref:`self-referential extras ` for examples. + .. _pyproject-toml-import-names: From d72cd8b978e469b562fc3390c25f9641c9688b00 Mon Sep 17 00:00:00 2001 From: Hugo Date: Fri, 10 Jul 2026 10:36:58 +0100 Subject: [PATCH 23/42] Update to include pip docs link --- source/guides/writing-pyproject-toml.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/guides/writing-pyproject-toml.rst b/source/guides/writing-pyproject-toml.rst index 6ce28553e..90fb7591c 100644 --- a/source/guides/writing-pyproject-toml.rst +++ b/source/guides/writing-pyproject-toml.rst @@ -189,7 +189,8 @@ Installing ``your-project-name[all]`` then installs both the ``gui`` and ``cli`` dependencies. You can also list extras separately, for example ``["your-project-name[gui]", "your-project-name[cli]"]``. The name in the requirement must match the project's ``name`` field. Installers such as -:ref:`pip` and :ref:`uv` support this pattern already (pip since v21.2). +:ref:`pip` and :ref:`uv` support this pattern already (pip since +`version 21.2 `_). .. _requires-python: From 68c3a77baafa24e65ce1bde8ea657001ccb03090 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 10 Jul 2026 09:37:18 +0000 Subject: [PATCH 24/42] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- source/guides/writing-pyproject-toml.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/guides/writing-pyproject-toml.rst b/source/guides/writing-pyproject-toml.rst index 90fb7591c..fa2760bab 100644 --- a/source/guides/writing-pyproject-toml.rst +++ b/source/guides/writing-pyproject-toml.rst @@ -189,7 +189,7 @@ Installing ``your-project-name[all]`` then installs both the ``gui`` and ``cli`` dependencies. You can also list extras separately, for example ``["your-project-name[gui]", "your-project-name[cli]"]``. The name in the requirement must match the project's ``name`` field. Installers such as -:ref:`pip` and :ref:`uv` support this pattern already (pip since +:ref:`pip` and :ref:`uv` support this pattern already (pip since `version 21.2 `_). From d45adcf5f81677fde743cffc2ee0c0d9f54c0221 Mon Sep 17 00:00:00 2001 From: Hugo Date: Sat, 11 Jul 2026 19:52:13 +0100 Subject: [PATCH 25/42] Rework the writing --- source/guides/writing-pyproject-toml.rst | 26 ++++++++++++++++-------- source/specifications/pyproject-toml.rst | 11 ++++------ 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/source/guides/writing-pyproject-toml.rst b/source/guides/writing-pyproject-toml.rst index fa2760bab..665c1277b 100644 --- a/source/guides/writing-pyproject-toml.rst +++ b/source/guides/writing-pyproject-toml.rst @@ -177,20 +177,28 @@ project with GUI support, adding the PyQt5 dependency. .. _self-referential-extras: -You can also define an extra that refers back to the same project with +You can also define an extra that refers back to the current project with other extras. This is useful for convenience extras that combine several -optional features without duplicating their dependency lists: +optional features (such as an ``all`` extra hosting dependencies from both +``gui`` and ``cli``): .. code-block:: toml - all = ["your-project-name[gui, cli]"] + all = ["your-project-name[gui, cli]"] -Installing ``your-project-name[all]`` then installs both the ``gui`` and -``cli`` dependencies. You can also list extras separately, for example -``["your-project-name[gui]", "your-project-name[cli]"]``. The name in the -requirement must match the project's ``name`` field. Installers such as -:ref:`pip` and :ref:`uv` support this pattern already (pip since -`version 21.2 `_). +The combined extra does not need its own manually maintained copy of each +referenced extra's dependencies, which can otherwise fall out of sync after +a few years of maintenance and bug fixes: + +.. code-block:: toml + + gui = ["PyQt5"] + cli = [ + "rich>=14.2", # version range is added after last "all" extra update + "textual", # dependency newly added since last "all" extra update + "click", + ] + all = ["PyQt5", "rich", "click"] .. _requires-python: diff --git a/source/specifications/pyproject-toml.rst b/source/specifications/pyproject-toml.rst index 4b5a4a780..7bc6ffbe1 100644 --- a/source/specifications/pyproject-toml.rst +++ b/source/specifications/pyproject-toml.rst @@ -498,13 +498,10 @@ 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. -A dependency specifier in an extra MAY name the project itself with other extras -(for example, ``all = ["spam[gui, cli]"]``). That way a combined extra does not -need its own manually maintained copy of each referenced extra's dependencies, -which can otherwise fall out of sync. Installers that support self-referential -extras will be able to install the union of these extras' dependencies. See -:ref:`self-referential extras ` for examples. - +Dependency specifiers in an extra may self-reference other extras from the +current project (e.g. ``all = ["your-project-name[gui, cli]"]``). See +:ref:`self-referential extras ` for an example. +Several installers including :ref:`pip` and :ref:`uv` support this pattern. .. _pyproject-toml-import-names: From 053f40e9b42ee5d0b0bd4d146b9866ba5a372173 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Sun, 12 Jul 2026 12:14:44 +0100 Subject: [PATCH 26/42] 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 27/42] 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 28/42] 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 29/42] 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 30/42] 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 31/42] 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 32/42] 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 33/42] 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 34/42] 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 35/42] 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 36/42] 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 c2eff8d9d436b25642cae6540922b51b7355f2cd Mon Sep 17 00:00:00 2001 From: Hugo Date: Wed, 5 Aug 2026 22:00:19 +0100 Subject: [PATCH 37/42] Update list of supported installer based on test results Tests are hosted in https://github.com/Trenza1ore/Self-Referential-Extras --- source/guides/writing-pyproject-toml.rst | 2 ++ source/specifications/pyproject-toml.rst | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/source/guides/writing-pyproject-toml.rst b/source/guides/writing-pyproject-toml.rst index 665c1277b..98601da8d 100644 --- a/source/guides/writing-pyproject-toml.rst +++ b/source/guides/writing-pyproject-toml.rst @@ -200,6 +200,8 @@ a few years of maintenance and bug fixes: ] all = ["PyQt5", "rich", "click"] +Most installers and dependency managers now support this kind of extra, including +:ref:`pip`, :ref:`uv`, :ref:`poetry`, :ref:`hatch`, :ref:`pdm` and :ref:`pipenv`. .. _requires-python: .. _python_requires: diff --git a/source/specifications/pyproject-toml.rst b/source/specifications/pyproject-toml.rst index 7bc6ffbe1..c65e5494f 100644 --- a/source/specifications/pyproject-toml.rst +++ b/source/specifications/pyproject-toml.rst @@ -501,7 +501,8 @@ if the associated extra name is requested. Dependency specifiers in an extra may self-reference other extras from the current project (e.g. ``all = ["your-project-name[gui, cli]"]``). See :ref:`self-referential extras ` for an example. -Several installers including :ref:`pip` and :ref:`uv` support this pattern. +Most installers and dependency managers now support this kind of extra, including +:ref:`pip`, :ref:`uv`, :ref:`poetry`, :ref:`hatch`, :ref:`pdm` and :ref:`pipenv`. .. _pyproject-toml-import-names: From cd8e36378c3b959a17dec24486e84bb662c0a85e Mon Sep 17 00:00:00 2001 From: Hugo Date: Wed, 5 Aug 2026 23:46:19 +0100 Subject: [PATCH 38/42] Use the term "package managers" as it's most commonly used - "package installer" is only used to describe pip - "dependency manager" is only used to describe pipenv --- source/guides/writing-pyproject-toml.rst | 2 +- source/specifications/pyproject-toml.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/guides/writing-pyproject-toml.rst b/source/guides/writing-pyproject-toml.rst index 98601da8d..a0ff484f1 100644 --- a/source/guides/writing-pyproject-toml.rst +++ b/source/guides/writing-pyproject-toml.rst @@ -200,7 +200,7 @@ a few years of maintenance and bug fixes: ] all = ["PyQt5", "rich", "click"] -Most installers and dependency managers now support this kind of extra, including +Most package managers now support this kind of extra, including :ref:`pip`, :ref:`uv`, :ref:`poetry`, :ref:`hatch`, :ref:`pdm` and :ref:`pipenv`. .. _requires-python: diff --git a/source/specifications/pyproject-toml.rst b/source/specifications/pyproject-toml.rst index c65e5494f..d4e504317 100644 --- a/source/specifications/pyproject-toml.rst +++ b/source/specifications/pyproject-toml.rst @@ -501,7 +501,7 @@ if the associated extra name is requested. Dependency specifiers in an extra may self-reference other extras from the current project (e.g. ``all = ["your-project-name[gui, cli]"]``). See :ref:`self-referential extras ` for an example. -Most installers and dependency managers now support this kind of extra, including +Most package managers now support this kind of extra, including :ref:`pip`, :ref:`uv`, :ref:`poetry`, :ref:`hatch`, :ref:`pdm` and :ref:`pipenv`. .. _pyproject-toml-import-names: From 84ea0ced2c41efa884801ab873d00f3f3b73bf1d Mon Sep 17 00:00:00 2001 From: Hugo Date: Thu, 6 Aug 2026 14:18:56 +0100 Subject: [PATCH 39/42] Add history entry for this edit --- 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 d4e504317..3fca99c9f 100644 --- a/source/specifications/pyproject-toml.rst +++ b/source/specifications/pyproject-toml.rst @@ -678,4 +678,7 @@ History - January 2026: Replaced outdated direct reference to :pep:`508` with a reference to :ref:`dependency-specifiers`. +- August 2026: Document self-referential extra as a supported feature by many + modern package managers of Python. + .. _TOML: https://toml.io From 90174bb0614df3780ce0a921793aa6feece87231 Mon Sep 17 00:00:00 2001 From: Eisuke Kawashima Date: Fri, 7 Aug 2026 17:29:11 +0900 Subject: [PATCH 40/42] 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 From e4ff704bae3400493912367381f7edb2f6b2a401 Mon Sep 17 00:00:00 2001 From: github-merge-queue <118344674+github-merge-queue@users.noreply.github.com> Date: Mon, 17 Aug 2026 06:15:53 +0000 Subject: [PATCH 41/42] Update uv_build version to 0.12.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 5f3e0bf4c..4f2a982c6 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.1, <0.13.0"] + requires = ["uv_build >= 0.12.5, <0.13.0"] build-backend = "uv_build" From 1e8fe5eca1e4b4235a7ea79424ab0b727b338b7d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 6 Jul 2026 18:51:01 +0000 Subject: [PATCH 42/42] [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.4.1 → v2.4.2](https://github.com/codespell-project/codespell/compare/v2.4.1...v2.4.2) - [github.com/astral-sh/ruff-pre-commit: v0.14.10 → v0.15.20](https://github.com/astral-sh/ruff-pre-commit/compare/v0.14.10...v0.15.20) --- .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 6d8d4e78b..4f9e5df7f 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.4.1 + rev: v2.4.2 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.14.10 + rev: v0.15.20 hooks: - id: ruff-check - id: ruff-format