Given a wheel that has something like this in its metadata:
Requires-Dist: requests; extra != "h"
Provides-Extra: h
Requires-Dist: httpx; extra == "h"
pip will always install requests, whether or not you ask for the [h] extra.
This was mentioned in a 2020 DPO thread from @uranusjr:
The current implementation (InstallRequirement.match_markers(), which calls into packaging.markers) is to evaluate each extra against the marker separately and then combine them. So the dependencies of package[extra1,extra2] would return the union of three marker evaluations:
marker.evaluate({'extra': ''})
marker.evaluate({'extra': 'extra1'})
marker.evaluate({'extra': 'extra2'})
The != operator breaks this logic (all inequity operators do) since dependency; extra != 'extra1' would evaluate to true for evaluate({'extra': ''}) and evalute({'extra': 'extra2'}) and apprear as a dependency, even though extra1 is specified.
I am not aware how pip implemented this prior to PEP 508, and it might as well be that pip’s current implementation is wrong and should be fixed. I find it unlikely, however, since packaging.markers does not offer a reasonable interface to compare multiple extra values to a marker all at once.
This still seems to be the case with current pip (version 26.1.2, tested on Ubuntu 24.04).
There was some recent tightening up of the spec language in pypa/packaging.python.org#1988 which now explicitly mentions bothextra == '...' and extra != '...' as intended to work, although the purpose of the edit was to deprecate nonsensical things like extra > '...' and not so much to fix !=.
My motivation here is that onnxruntime and onnxruntime-gpu are alternatives; they both provide the same files, and whichever one is installed last wins. I want to be able to write a pyproject.toml file with
[project]
...
dependencies = [
"onnxruntime; extra != 'gpu'",
]
[project.optional-dependencies]
gpu = [
"onnxruntime-gpu",
]
so that installing the project with no extras gets you onnxruntime, and installing the [gpu] extra gets you only onnxruntime-gpu. However, the environment marker on onnxruntime has no effect and that package always gets installed.
(Curiously, uv has the opposite bug: extra != '...' markers always evaluate to false. I filed astral-sh/uv#20107 about that.)
Given a wheel that has something like this in its metadata:
pip will always install
requests, whether or not you ask for the[h]extra.This was mentioned in a 2020 DPO thread from @uranusjr:
This still seems to be the case with current pip (version 26.1.2, tested on Ubuntu 24.04).
There was some recent tightening up of the spec language in pypa/packaging.python.org#1988 which now explicitly mentions both
extra == '...'andextra != '...'as intended to work, although the purpose of the edit was to deprecate nonsensical things likeextra > '...'and not so much to fix!=.My motivation here is that
onnxruntimeandonnxruntime-gpuare alternatives; they both provide the same files, and whichever one is installed last wins. I want to be able to write a pyproject.toml file withso that installing the project with no extras gets you
onnxruntime, and installing the[gpu]extra gets you onlyonnxruntime-gpu. However, the environment marker ononnxruntimehas no effect and that package always gets installed.(Curiously, uv has the opposite bug:
extra != '...'markers always evaluate to false. I filed astral-sh/uv#20107 about that.)