From 105ab9614ec8d131de08f7bfe879f30cea282e54 Mon Sep 17 00:00:00 2001 From: konstin Date: Sat, 4 Jul 2026 09:50:14 +0200 Subject: [PATCH 1/3] Ban negative extras Negative extras (`extra !=`) are currently technically allowed in the grammar, but they behave strangely: `extra !=` means that package could transitively remove a package from selection through activating an extra. This turns incremental resolution into a global problem: We can't exit a resolution with a conflict when we've exhausted all versions in range including backtracking, we also have to exhaustively search for any package version that may activate the extra which deactivates the `extra !=` requirement which is part of the conflict. This would be fatal to resolver complexity and performance, preventing most of the short-circuiting that makes resolving tractable. Much weirder, with negative extras, adding a new dependency can make a previously impossible resolution solvable: ``` [project] name = "foo" version = "0.1.0" dependencies = [ "numpy >2", "numpy <2; extra != 'old-science'", ] ``` Only by adding a package with `Requires-Dist: foo[old-science]`, this resolves. Using PEP 621, users only get positive extras: `project.optional-dependencies.foo` gets translated into a conjunction of `extra == "foo"` with each requirement's marker. While this may look like a breaking change, it only clarifies the current state of support in tools. From [pip not supporting it](https://github.com/pypa/pip/issues/14139) and [uv not supporting it](https://github.com/astral-sh/uv/issues/20107), we know it is not currently used and safe to remove. This solves the [confusion for users who want to use negative extras for conflicting packages](https://github.com/astral-sh/uv/issues/20107). --- source/specifications/dependency-specifiers.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/source/specifications/dependency-specifiers.rst b/source/specifications/dependency-specifiers.rst index d66f77503..d9054bec8 100644 --- a/source/specifications/dependency-specifiers.rst +++ b/source/specifications/dependency-specifiers.rst @@ -457,9 +457,8 @@ 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, ``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 +It only supports one operation, ``extra == "name"``, which is similar to +``"name" 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 From fcd61723148a823a548b6b8e53f0808de23effd3 Mon Sep 17 00:00:00 2001 From: konstin Date: Sun, 19 Jul 2026 22:05:10 +0200 Subject: [PATCH 2/3] Talk about `extra != "name"` too --- 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 d9054bec8..ea17f9c72 100644 --- a/source/specifications/dependency-specifiers.rst +++ b/source/specifications/dependency-specifiers.rst @@ -458,13 +458,15 @@ 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. It only supports one operation, ``extra == "name"``, which is similar to -``"name" 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. +``"name" in extras``. ``extra != "name"`` SHOULD NOT be used anymore and MAY +be rejected or evaluated to false. 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 From 36a541f7175296ac1aa291db313a124f13741df7 Mon Sep 17 00:00:00 2001 From: konstin Date: Tue, 21 Jul 2026 16:02:35 +0200 Subject: [PATCH 3/3] History entry --- source/specifications/dependency-specifiers.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/specifications/dependency-specifiers.rst b/source/specifications/dependency-specifiers.rst index ea17f9c72..c330a0e17 100644 --- a/source/specifications/dependency-specifiers.rst +++ b/source/specifications/dependency-specifiers.rst @@ -708,6 +708,8 @@ History work. [#marker_comparison_logic]_ - January 2026: fix outdated references to other documents that were inadvertently retained from :pep:`508` +- July 2026: Explain that ``extra != "name"`` is not (properly) supported + (https://discuss.python.org/t/ban-negative-extras-for-extras-marker/108022/24) References