Fix extra marker evaluation for requested extras - #14141
Conversation
|
Heads up, I am also taking a look at this and may at some point raise my own PR. It's fine to keep working on, but be aware that this may not be accepted in favor of other work. It seems like this PR is still in a very experimental state, but some quick feedback, I do not like the idea of have to do a post resolution rewalk or rerunning the resolver more than once. I am even willing to push back at the concept of the spec if it requires some kind of iterative reresolve that we have to hope converges. |
|
Update after rework: agreed with this concern. The PR no longer uses a post-resolution rewalk or reruns the resolver. Extras are now modeled inside resolvelib's normal project criterion flow; see the updated PR body and the follow-up implementation note below. |
|
Current implementation update: this now avoids the post-resolution rewalk/rerun approach and keeps extras in resolvelib's normal criteria flow. The current shape is:
I also opened pypa/packaging#1312 to ask whether packaging wants a public helper for selected-extras marker evaluation. This PR does not depend on that. |
|
@notatallshaw can you retrigger CI? looks like a transient issue. |
|
I generally don't think this is possible, see discussion to ban this: https://discuss.python.org/t/ban-negative-extras-for-extras-marker/108022 A case where this PR silently installs the wrong packages.
It installs |
|
Chose this fix because the reported case has no stable valid resolution under the current The change is conservative: it does not try to make negative extras globally solvable, but prevents pip from accepting a final result whose provenance depends on a package that resolvelib later dropped. This preserves the existing valid additive/backtracking cases while turning the self-invalidating case into an explicit error. |
Fixes #14139.
This updates pip's handling of marker clauses involving
extraso they are evaluated against the selected extras set for the requirement/package, instead of evaluating each selected extra independently in a way that made negated markers too broad.The intended set-wide behavior is:
extraas the empty stringextra == "name"andextra in ...match if any selected extra matchesextra != "name"andextra not in ...match only if all selected extras matchextracomparisons continue to use packaging's marker comparison semantics, aggregated across the selected extras setImplementation notes:
pip._internal.utils.markersBaseDistribution.iter_dependencies()instead of duplicating it across metadata backendsThis deliberately avoids a post-resolution graph repair pass or rerunning the resolver. The resolver continues to converge through resolvelib's existing criterion invalidation/backtracking behavior.
I also opened pypa/packaging#1312 to ask whether packaging wants a public helper for this kind of selected-extras marker evaluation. This PR does not depend on packaging changes.
Tests run: