Skip to content

Instantly share code, notes, and snippets.

@pfmoore
Created March 12, 2020 14:08
Show Gist options
  • Save pfmoore/128f2c74032efab97a2f83fa6dd3be31 to your computer and use it in GitHub Desktop.
Save pfmoore/128f2c74032efab97a2f83fa6dd3be31 to your computer and use it in GitHub Desktop.
Notes on the interface between Candidate and InstallRequirement
Thoughts on the interface between a Candidate and an InstallRequirement.
The Candidate will hold a pip Link object as its "identifier" of the
distribution file/directory it represents. So it needs to be able to
say "Give me the (unique) InstallRequirement that's representing this
Link". I'd suggest that the interface has internally a Link->InstallRequirement
dictionary.
Creating the InstallRequirement needs a "parent" InstallRequirement from
which the options:
- editable
- markers
- use_pep517
- isolated
- install_options
- global_options
- hash_options
- constraint
- extras (?)
will be copied.
We also need to be able to say "this has already been created with an
incompatible parent". Simple example - requirements.txt containing:
.
-e .
(first has a parent which is not editable, second has a parent which is
editable).
We need to create the InstallRequirement when we create the Candidate, as
that's the only time we have the parent (and the preparer) available.
So:
- find_matches creates a Candidate, providing a Link
- Candidate constructor calls "get me an InstallRequirement for this
Link, based on this Parent"
* If it gets back an InstallRequirement, save it for later.
* If it doesn't, that's because there's already an InstallRequirement
with an incompatible parent, and we can error. (The function that
gives back the link can raise the error directly, in fact).
The Candidate will only do one thing with the InstallRequirement - request
a pip._vendor.pkg_resources.Distribution from it.
Code for this is basically:
@property
def dist(self):
# type: () -> Distribution
if self._dist is None:
abstract_dist = self._preparer.prepare_linked_requirement(
self._install_requirement
)
self._dist = abstract_dist.get_pkg_resources_distribution()
# These should be "proper" errors, not just asserts, as they
# can result from user errors like a requirement "foo @ URL"
# when the project at URL has a name of "bar" in its metadata.
assert self._name is None or self._name == self._dist.project_name
assert self._version is None or self._version == self.dist.parsed_version
return self._dist
If the Candidate has no name, this will happen immediately, so we can
always assume candidates are named. But if the candidate has a name (e.g
`name @ URL`, or `foo >= 1.0`) then we'll lazily assume the given name is
correct until we need to prepare, hence the asserts in the above code.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment