Skip to content

Create complementary dependencies for extra-only sources#18272

Open
charliermarsh wants to merge 3 commits intomainfrom
charlie/extra
Open

Create complementary dependencies for extra-only sources#18272
charliermarsh wants to merge 3 commits intomainfrom
charlie/extra

Conversation

@charliermarsh
Copy link
Member

@charliermarsh charliermarsh commented Mar 3, 2026

Summary

When a [tool.uv.sources] entry uses extra = "foo", the source should only apply when that extra is active. We now create a complementary dependency for extra != "foo" with the source un-applied.

For example, given:

[project]
dependencies = ["iniconfig>=2"]

[project.optional-dependencies]
foo = ["iniconfig"]

[tool.uv.sources]
iniconfig = [
  { url = "https://example.com/iniconfig-2.0.0.whl", extra = "foo" },
]

We now install from example.com when foo is activated, but PyPI otherwise.

Closes #17967.

Closes #18229.

@charliermarsh charliermarsh marked this pull request as ready for review March 6, 2026 15:58
@charliermarsh charliermarsh marked this pull request as draft March 6, 2026 15:58
@charliermarsh charliermarsh force-pushed the charlie/extra branch 2 times, most recently from c4bdcb8 to ea4ea71 Compare March 6, 2026 18:38
@charliermarsh
Copy link
Member Author

The net effects here seem quite good, though I don't fully understand the change yet.

@charliermarsh charliermarsh added the bug Something isn't working label Mar 8, 2026
@charliermarsh charliermarsh marked this pull request as ready for review March 8, 2026 16:16
@charliermarsh charliermarsh requested review from konstin and zanieb March 8, 2026 16:17
@konstin
Copy link
Member

konstin commented Mar 9, 2026

Before I go further on the inline comments, should this apply only to sources, or to more kinds of conditional dependencies? If the former, should we apply this in LoweredRequirement instead of PubGrubPackage, in hopes that it's easier code in there?

@charliermarsh
Copy link
Member Author

I can give that a try.

@charliermarsh charliermarsh marked this pull request as draft March 9, 2026 19:19
@charliermarsh charliermarsh marked this pull request as ready for review March 9, 2026 21:26
@charliermarsh
Copy link
Member Author

I wasn't able to get that to work... Part of the problem is that this has to look across dependencies and optional dependencies to figure out whether to include the complement.

Copy link
Member

@konstin konstin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I gotta admit I have trouble following along with the logic, so this isn't a review, but instead some questions for my understanding.

.collect();

if extra.is_none() && group.is_none() {
self.add_complementary_source_dependencies(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we return an iterator here and chain that? iirc this is a hot path

deps: &mut Vec<PubGrubDependency>,
) {
let python_marker = python_requirement.to_marker_tree();
for requirement in self.overrides.apply(requirements.iter()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a comment and a test why we need to apply overrides here? I removed it and the tests still pass.

.collect()
.collect();

if extra.is_none() && group.is_none() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is that our condition, naively, I'd have expected the inverse condition for inverting

python_marker: MarkerTree,
) -> bool {
// Already included via `flatten_requirements`.
if requirement.evaluate_markers(env.marker_environment(), &[]) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's an example for this?

}

// A base dep (without a URL) must already exist; otherwise this is
// an extra-only dependency and should remain as-is.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could the base dep be added to the dependency graph after the URL dep?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

2 participants