-
Notifications
You must be signed in to change notification settings - Fork 760
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Consider installed packages during resolution #2596
Conversation
4bd3f16
to
dbe5cf9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this generally looks good!
This is driving me a little crazy and is becoming a larger problem in #2596 where I need to move more types (like `Upgrade` and `Reinstall`) into this crate. Anything that's shared across our core resolver, install, and build crates needs to be defined in this crate to avoid cyclic dependencies. We've outgrown it being a single file with some shared traits. There are no behavioral changes here.
48e4bf0
to
18f36d6
Compare
@@ -613,26 +634,23 @@ impl<'a, Provider: ResolverProvider> Resolver<'a, Provider> { | |||
.ok_or(ResolveError::Unregistered)?; | |||
self.visited.insert(package_name.clone()); | |||
|
|||
let empty_version_map = VersionMap::default(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to initialize this for lifetimes since version_map
is a reference.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alternatively we could have CandidateSelector.select
take an Option<&VersionMap>
but I opted for an empty iterable to avoid nesting in select
instead. I'd consider revisiting this in the future as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can do let empty_version_map;
here and then empty_version_map = VersionMap::default()
in each branch if you want.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh that could be nicer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually idk if that makes sense we're trying to return &VersionMap::default()
in the match which is the problem?
e53df4c
to
d9cf413
Compare
<!-- Thank you for contributing to uv! To help us out with reviewing, please consider the following: - Does this pull request include a summary of the change? (See below.) - Does this pull request include a descriptive title? - Does this pull request include references to any relevant issues? --> ## Summary <!-- What's the purpose of the change? What does it do, and why? --> - Displays missing packages as single-line warnings. - Adds support for `Editable project location` and `Required-by` fields in `pip show`. Part of #2526. # Conflicts: # crates/uv-dispatch/src/lib.rs # crates/uv-resolver/src/resolver/mod.rs # crates/uv-resolver/tests/resolver.rs # crates/uv-traits/src/lib.rs # crates/uv/src/commands/pip_compile.rs # Conflicts: # crates/uv/src/commands/pip_sync.rs
5bca934
to
e2fbf2e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This generally looks great to me.
@@ -613,26 +634,23 @@ impl<'a, Provider: ResolverProvider> Resolver<'a, Provider> { | |||
.ok_or(ResolveError::Unregistered)?; | |||
self.visited.insert(package_name.clone()); | |||
|
|||
let empty_version_map = VersionMap::default(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can do let empty_version_map;
here and then empty_version_map = VersionMap::default()
in each branch if you want.
&& self | ||
.installed_packages | ||
.get_packages(package_name) | ||
.is_empty() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe so but want to confirm: do you have any tests in which a package is already installed, but doesn't exist on the registry? I.e., exercising true for self.unavailable_packages.get(package_name).is_some()
and false for the latter condition.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes definitely.
.installed_packages | ||
.get_packages(package_name) | ||
.is_empty() | ||
{ | ||
debug_assert!( | ||
false, | ||
"Dependencies were requested for a package that is not available" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do we even get here btw?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe a dumb question since there's a debug_assert!
here anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah if a version map cannot be retrieved for a package we track the package in unavailable_packages
but that's no longer the sole way to have a candidate for a package so this is kind of a lazy way of allowing installed packages dependencies to be retrieved even if they were not available in the index.
# Conflicts: # crates/distribution-types/src/lib.rs # crates/uv-dev/src/install_many.rs # crates/uv-resolver/src/finder.rs # crates/uv-resolver/src/lib.rs # crates/uv-resolver/src/manifest.rs # crates/uv-resolver/tests/resolver.rs # crates/uv/src/commands/pip_compile.rs # crates/uv/src/commands/pip_install.rs # crates/uv/src/commands/pip_sync.rs # crates/uv/src/commands/reporters.rs # crates/uv/tests/pip_sync.rs
5188ca6
to
3815e3e
Compare
9217532
to
59b58dc
Compare
I've addressed all the feedback from the review. |
…tion in the resolver (#2779) Addresses panic introduced in #2596 and reported in #2763 (comment) When there are multiple versions of a package available, we remove the existing packages before installing the resolved version to "fix" the environment. We must remove all of the package versions and reinstall because removing _any_ of the package versions could break the others. Since reinstalls require a pull from the remote, this broke a contract between the resolver and the planner which must always agree on which packages should come from the remote. This further demonstrates that we should be constructing the install plan with more concrete knowledge from the resolver (i.e. `ResolvedDist` instead of `Requirement`) to avoid having to manually ensure logic matches. ## Test plan Fails on `main` with panic succeeds on branch ``` uv venv --seed source .venv/bin/activate pip install anyio==3.7.0 --ignore-installed pip install anyio==4.0.0 --ignore-installed cargo run -- pip install anyio black -v ```
Previously, we did not consider installed distributions as candidates while performing resolution. Here, we update the resolver to use installed distributions that satisfy requirements instead of pulling new distributions from the registry.
The implementation details are as follows:
SitePackages
to theCandidateSelector
Exclusions
type which tracks installed packages to ignore during selectionResolvedDist
wrapper withInstalled(InstalledDist)
andInstallable(Dist)
variantsThe user-facing behavior is thoroughly covered in the tests, but briefly:
Closes #1661
Addresses:
uv pip install -e {package}
#1476Test plan
charlesnicholson/uv-pep420-bug
passes[ ] Unit test for wheel not available in registry but already installed locally (#2282)(seems complicated and not worthwhile)pip compile
does not consider installed packages