Support conflicting URL in separate forks#4435
Conversation
CodSpeed Performance ReportMerging #4435 will improve performances by 23.65%Comparing Summary
Benchmarks breakdown
|
b1c9cfd to
714df58
Compare
4f77bc4 to
4965708
Compare
714df58 to
aaa0acb
Compare
I caused this error during development and having the name of the task on it is helpful for debugging. Split out from #4435
I have to add yet another indentation level to the prerelease-available check in `PubGrubReportFormatter::hints` for #4435, so i've broken the code into methods and decreased indentation in this split out refactoring-only change.
I have to add yet another indentation level to the prerelease-available check in `PubGrubReportFormatter::hints` for #4435, so i've broken the code into methods and decreased indentation in this split out refactoring-only change.
3a08323 to
8386382
Compare
4965708 to
8fb9c69
Compare
In the last PR (#4430), we flatten the requirements. In the next PR (#4435), we want to pass `Url` around next to `PubGrubPackage` and `Range<Version>` to keep track of which `Requirement`s added a url across forking. This PR is a refactoring split out from #4435 that rolls the dependency conversion into a single iterator and introduces a new `PubGrubDependency` struct as abstraction over `(PubGrubPackage, Range<Version>)` (or `(PubGrubPackage, Range<Version>, VerbatimParsedUrl)` in the next PR), and it removes the now unnecessary `PubGrubDependencies` abstraction.
In the last PR (#4430), we flatten the requirements. In the next PR (#4435), we want to pass `Url` around next to `PubGrubPackage` and `Range<Version>` to keep track of which `Requirement`s added a url across forking. This PR is a refactoring split out from #4435 that rolls the dependency conversion into a single iterator and introduces a new `PubGrubDependency` struct as abstraction over `(PubGrubPackage, Range<Version>)` (or `(PubGrubPackage, Range<Version>, VerbatimParsedUrl)` in the next PR), and it removes the now unnecessary `PubGrubDependencies` abstraction.
61e1fcc to
0a33469
Compare
0a33469 to
01883ea
Compare
| // since we weren't sure whether it might also be a URL requirement when | ||
| // transforming the requirements. For that case, we do another request here | ||
| // (idempotent due to caching). | ||
| self.request_package(&state.next, url, &request_sink)?; |
There was a problem hiding this comment.
Is this only necessary if url is None?
There was a problem hiding this comment.
I guess that's the majority of the time anyway.
There was a problem hiding this comment.
We need it if fork_urls return None and Urls return something, that is the case when it's ambiguous. I didn't add that check specifically because request_package already checks if the request was previously registered
Whenever we encounter an override URL, that takes precedence over everything else. We also only allow only a single URL per package from overrides, not supporting splitting on overrides. Does that make it clearer?
Yes, i think we have to make the same changes for them too. |
In the last PR (#4430), we flatten the requirements. In the next PR (#4435), we want to pass `Url` around next to `PubGrubPackage` and `Range<Version>` to keep track of which `Requirement`s added a url across forking. This PR is a refactoring split out from #4435 that rolls the dependency conversion into a single iterator and introduces a new `PubGrubDependency` struct as abstraction over `(PubGrubPackage, Range<Version>)` (or `(PubGrubPackage, Range<Version>, VerbatimParsedUrl)` in the next PR), and it removes the now unnecessary `PubGrubDependencies` abstraction.
8362f3b to
9b7e47c
Compare
30f4c2f to
0101939
Compare
In the last PR (#4430), we flatten the requirements. In the next PR (#4435), we want to pass `Url` around next to `PubGrubPackage` and `Range<Version>` to keep track of which `Requirement`s added a url across forking. This PR is a refactoring split out from #4435 that rolls the dependency conversion into a single iterator and introduces a new `PubGrubDependency` struct as abstraction over `(PubGrubPackage, Range<Version>)` (or `(PubGrubPackage, Range<Version>, VerbatimParsedUrl)` in the next PR), and it removes the now unnecessary `PubGrubDependencies` abstraction.
9b7e47c to
c75b822
Compare
In the last PR (#4430), we flatten the requirements. In the next PR (#4435), we want to pass `Url` around next to `PubGrubPackage` and `Range<Version>` to keep track of which `Requirement`s added a url across forking. This PR is a refactoring split out from #4435 that rolls the dependency conversion into a single iterator and introduces a new `PubGrubDependency` struct as abstraction over `(PubGrubPackage, Range<Version>)` (or `(PubGrubPackage, Range<Version>, VerbatimParsedUrl)` in the next PR), and it removes the now unnecessary `PubGrubDependencies` abstraction.
d21ab02 to
cb32b21
Compare
`ResolverState::choose_version` had become huge, with an odd match due to the url handling from #4435. This refactoring breaks it into `choose_version`, `choose_version_registry` and `choose_version_url`. No functional changes.
`ResolverState::choose_version` had become huge, with an odd match due to the url handling from #4435. This refactoring breaks it into `choose_version`, `choose_version_registry` and `choose_version_url`. No functional changes.
`ResolverState::choose_version` had become huge, with an odd match due to the url handling from #4435. This refactoring breaks it into `choose_version`, `choose_version_registry` and `choose_version_url`. No functional changes.
`ResolverState::choose_version` had become huge, with an odd match due to the url handling from #4435. This refactoring breaks it into `choose_version`, `choose_version_registry` and `choose_version_url`. No functional changes.
## Summary Currently, the `Locals` type relies on there being a single local version for a given package. With marker expressions this may not be true, a similar problem to #4435. This changes the `Locals` type to `ForkLocals`, which tracks locals for a given fork. Local versions are now tracked on `PubGrubRequirement` before forking. Resolves #4580.
Downstack PR: #4481
Introduction
We support forking the dependency resolution to support conflicting registry requirements for different platforms, say on package range is required for an older python version while a newer is required for newer python versions, or dependencies that are different per platform. We need to extend this support to direct URL requirements.
This did not work because
Urlswas built on the assumption that there is a single allowed URL per package. We collect all allowed URL ahead of resolution by following direct URL dependencies (including path dependencies) transitively, i.e. a registry distribution can't require a URL.The same package can have Registry and URL requirements
Consider the following two cases:
requirements.in:
pyproject.toml:
In the first case, we want the URL to override the registry dependency, in the second case we want to fork and have one branch use the registry and the other the URL. We have to know about this in
PubGrubRequirement::from_registry_requirement, but we only fork after the current method.Consider the following case too:
a:
b:
When we convert the requirements of
a, we can't know the url ofcyet. The solution is to remove theUrlfromPubGrubPackage: TheUrlis redundant withPackageName, there can be only one url per package name per fork. We now do the following: We track the urls from requirements inPubGrubDependency. After forking, we calladd_package_version_dependencieswhere we apply override URLs, check if the URL is allowed and check if the url is unique in this fork. When we request a distribution, we ask the fork urls for the real URL. Since we prioritize url dependencies over registry dependencies and skip packages withUrlsentries in pre-visiting, we know that when fetching a package, we know if it has a url or not.URL conflicts
pyproject.toml (invalid):
On the fork state, we keep
ForkUrlsthat check for conflicts after forking, rejecting the third case because we added two packages of the same name with different URLs.We need to flatten out the requirements before transformation into pubgrub requirements to get the full list of other requirements which may contain a URL, which was changed in a previous PR: #4430.
Complex Example
a:
b:
b1:
b2:
b3:
In this example, all packages are url requirements (directory requirements) and the root package is
a. We first split ona,bbeing in each split. In the first fork, we reachb1, the fork URLs are empty, we insert the iniconfig 1.1.1 URL, and then we skip overb2andb3since the mark is disjoint with the fork markers. In the second fork, we skip overb1, visitb2, insert the iniconfig 2.0.0 URL into the again empty fork URLs, then visitb3and try to insert the iniconfig 1.1.0 URL. At this point we find a conflict for the iniconfig URL and error.Closing
The git tests are slow, but they make the best example for different URL types i could find.
Part of #3927. This PR does not handle
Localsor pre-releases yet.