2020-04-02 13:49:45 +02:00
|
|
|
from pip._vendor.pkg_resources import (
|
|
|
|
DistributionNotFound,
|
|
|
|
VersionConflict,
|
|
|
|
get_distribution,
|
|
|
|
)
|
|
|
|
|
2020-03-26 20:14:51 +01:00
|
|
|
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
|
|
|
|
|
2020-04-02 13:49:45 +02:00
|
|
|
from .candidates import (
|
2020-04-02 19:27:34 +02:00
|
|
|
AlreadyInstalledCandidate,
|
2020-04-02 13:49:45 +02:00
|
|
|
ExtrasCandidate,
|
|
|
|
LinkCandidate,
|
|
|
|
RequiresPythonCandidate,
|
|
|
|
)
|
2020-04-01 12:14:36 +02:00
|
|
|
from .requirements import (
|
|
|
|
ExplicitRequirement,
|
|
|
|
NoMatchRequirement,
|
|
|
|
SpecifierRequirement,
|
|
|
|
)
|
2020-03-26 20:14:51 +01:00
|
|
|
|
|
|
|
if MYPY_CHECK_RUNNING:
|
2020-04-01 12:14:36 +02:00
|
|
|
from typing import Dict, Optional, Set, Tuple
|
|
|
|
|
|
|
|
from pip._vendor.packaging.specifiers import SpecifierSet
|
2020-04-03 12:23:35 +02:00
|
|
|
from pip._vendor.packaging.version import _BaseVersion
|
2020-04-02 13:49:45 +02:00
|
|
|
from pip._vendor.pkg_resources import Distribution
|
2020-03-26 20:14:51 +01:00
|
|
|
|
|
|
|
from pip._internal.index.package_finder import PackageFinder
|
2020-04-02 13:49:45 +02:00
|
|
|
from pip._internal.models.candidate import InstallationCandidate
|
2020-03-26 20:14:51 +01:00
|
|
|
from pip._internal.models.link import Link
|
|
|
|
from pip._internal.operations.prepare import RequirementPreparer
|
|
|
|
from pip._internal.req.req_install import InstallRequirement
|
|
|
|
from pip._internal.resolution.base import InstallRequirementProvider
|
|
|
|
|
|
|
|
from .base import Candidate, Requirement
|
|
|
|
|
|
|
|
|
|
|
|
class Factory(object):
|
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
finder, # type: PackageFinder
|
|
|
|
preparer, # type: RequirementPreparer
|
|
|
|
make_install_req, # type: InstallRequirementProvider
|
2020-04-02 13:49:45 +02:00
|
|
|
ignore_installed, # type: bool
|
2020-04-01 12:14:36 +02:00
|
|
|
ignore_requires_python, # type: bool
|
|
|
|
py_version_info=None, # type: Optional[Tuple[int, ...]]
|
2020-03-26 20:14:51 +01:00
|
|
|
):
|
|
|
|
# type: (...) -> None
|
2020-03-27 15:40:05 +01:00
|
|
|
self.finder = finder
|
|
|
|
self.preparer = preparer
|
2020-04-01 12:14:36 +02:00
|
|
|
self._python_candidate = RequiresPythonCandidate(py_version_info)
|
2020-04-01 10:14:44 +02:00
|
|
|
self._make_install_req_from_spec = make_install_req
|
2020-04-02 13:49:45 +02:00
|
|
|
self._ignore_installed = ignore_installed
|
|
|
|
self._ignore_requires_python = ignore_requires_python
|
|
|
|
self._link_candidate_cache = {} # type: Dict[Link, LinkCandidate]
|
2020-03-26 20:14:51 +01:00
|
|
|
|
2020-04-02 13:49:45 +02:00
|
|
|
def _make_candidate_from_dist(
|
|
|
|
self,
|
|
|
|
dist, # type: Distribution
|
|
|
|
extras, # type: Set[str]
|
|
|
|
parent, # type: InstallRequirement
|
|
|
|
):
|
|
|
|
# type: (...) -> Candidate
|
2020-04-02 19:27:34 +02:00
|
|
|
base = AlreadyInstalledCandidate(dist, parent, factory=self)
|
2020-04-02 13:49:45 +02:00
|
|
|
if extras:
|
|
|
|
return ExtrasCandidate(base, extras)
|
|
|
|
return base
|
|
|
|
|
|
|
|
def _make_candidate_from_link(
|
2020-03-26 20:14:51 +01:00
|
|
|
self,
|
2020-04-03 12:23:35 +02:00
|
|
|
link, # type: Link
|
|
|
|
extras, # type: Set[str]
|
|
|
|
parent, # type: InstallRequirement
|
|
|
|
name=None, # type: Optional[str]
|
|
|
|
version=None, # type: Optional[_BaseVersion]
|
2020-03-26 20:14:51 +01:00
|
|
|
):
|
|
|
|
# type: (...) -> Candidate
|
2020-04-02 13:49:45 +02:00
|
|
|
if link not in self._link_candidate_cache:
|
|
|
|
self._link_candidate_cache[link] = LinkCandidate(
|
2020-04-03 12:23:35 +02:00
|
|
|
link, parent, factory=self, name=name, version=version,
|
2020-03-26 20:14:51 +01:00
|
|
|
)
|
2020-04-02 13:49:45 +02:00
|
|
|
base = self._link_candidate_cache[link]
|
2020-03-26 20:14:51 +01:00
|
|
|
if extras:
|
|
|
|
return ExtrasCandidate(base, extras)
|
|
|
|
return base
|
|
|
|
|
2020-04-02 13:49:45 +02:00
|
|
|
def _get_installed_distribution(self, name, version):
|
|
|
|
# type: (str, str) -> Optional[Distribution]
|
|
|
|
if self._ignore_installed:
|
|
|
|
return None
|
|
|
|
specifier = "{}=={}".format(name, version)
|
|
|
|
try:
|
|
|
|
dist = get_distribution(specifier)
|
|
|
|
except (DistributionNotFound, VersionConflict):
|
|
|
|
return None
|
|
|
|
return dist
|
|
|
|
|
|
|
|
def make_candidate_from_ican(
|
|
|
|
self,
|
|
|
|
ican, # type: InstallationCandidate
|
|
|
|
extras, # type: Set[str]
|
|
|
|
parent, # type: InstallRequirement
|
|
|
|
):
|
|
|
|
# type: (...) -> Candidate
|
|
|
|
dist = self._get_installed_distribution(ican.name, ican.version)
|
|
|
|
if dist is None:
|
|
|
|
return self._make_candidate_from_link(
|
|
|
|
link=ican.link,
|
|
|
|
extras=extras,
|
|
|
|
parent=parent,
|
2020-04-03 12:23:35 +02:00
|
|
|
name=ican.name,
|
|
|
|
version=ican.version,
|
2020-04-02 13:49:45 +02:00
|
|
|
)
|
|
|
|
return self._make_candidate_from_dist(
|
|
|
|
dist=dist,
|
|
|
|
extras=extras,
|
|
|
|
parent=parent,
|
|
|
|
)
|
|
|
|
|
2020-04-01 10:14:44 +02:00
|
|
|
def make_requirement_from_install_req(self, ireq):
|
2020-03-26 20:14:51 +01:00
|
|
|
# type: (InstallRequirement) -> Requirement
|
|
|
|
if ireq.link:
|
2020-04-03 12:23:35 +02:00
|
|
|
# TODO: Get name and version from ireq, if possible?
|
|
|
|
# Specifically, this might be needed in "name @ URL"
|
|
|
|
# syntax - need to check where that syntax is handled.
|
2020-04-02 13:49:45 +02:00
|
|
|
cand = self._make_candidate_from_link(
|
|
|
|
ireq.link, extras=set(), parent=ireq,
|
|
|
|
)
|
2020-03-26 20:14:51 +01:00
|
|
|
return ExplicitRequirement(cand)
|
2020-04-02 13:49:45 +02:00
|
|
|
return SpecifierRequirement(ireq, factory=self)
|
2020-04-01 10:14:44 +02:00
|
|
|
|
|
|
|
def make_requirement_from_spec(self, specifier, comes_from):
|
|
|
|
# type: (str, InstallRequirement) -> Requirement
|
|
|
|
ireq = self._make_install_req_from_spec(specifier, comes_from)
|
|
|
|
return self.make_requirement_from_install_req(ireq)
|
2020-04-01 12:14:36 +02:00
|
|
|
|
|
|
|
def make_requires_python_requirement(self, specifier):
|
|
|
|
# type: (Optional[SpecifierSet]) -> Optional[Requirement]
|
|
|
|
if self._ignore_requires_python or specifier is None:
|
|
|
|
return None
|
2020-04-02 12:50:23 +02:00
|
|
|
# The logic here is different from SpecifierRequirement, for which we
|
|
|
|
# "find" candidates matching the specifier. But for Requires-Python,
|
|
|
|
# there is always exactly one candidate (the one specified with
|
|
|
|
# py_version_info). Here we decide whether to return that based on
|
|
|
|
# whether Requires-Python matches that one candidate or not.
|
2020-04-01 12:14:36 +02:00
|
|
|
if self._python_candidate.version in specifier:
|
|
|
|
return ExplicitRequirement(self._python_candidate)
|
|
|
|
return NoMatchRequirement(self._python_candidate.name)
|