candidates.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. import logging
  2. import sys
  3. from pip._vendor.packaging.specifiers import InvalidSpecifier, SpecifierSet
  4. from pip._vendor.packaging.utils import canonicalize_name
  5. from pip._vendor.packaging.version import Version
  6. from pip._internal.exceptions import HashError, MetadataInconsistent
  7. from pip._internal.models.wheel import Wheel
  8. from pip._internal.req.constructors import (
  9. install_req_from_editable,
  10. install_req_from_line,
  11. )
  12. from pip._internal.req.req_install import InstallRequirement
  13. from pip._internal.utils.misc import dist_is_editable, normalize_version_info
  14. from pip._internal.utils.packaging import get_requires_python
  15. from pip._internal.utils.typing import MYPY_CHECK_RUNNING
  16. from .base import Candidate, format_name
  17. if MYPY_CHECK_RUNNING:
  18. from typing import Any, FrozenSet, Iterable, Optional, Tuple, Union
  19. from pip._vendor.packaging.version import _BaseVersion
  20. from pip._vendor.pkg_resources import Distribution
  21. from pip._internal.models.link import Link
  22. from .base import Requirement
  23. from .factory import Factory
  24. BaseCandidate = Union[
  25. "AlreadyInstalledCandidate",
  26. "EditableCandidate",
  27. "LinkCandidate",
  28. ]
  29. logger = logging.getLogger(__name__)
  30. def make_install_req_from_link(link, template):
  31. # type: (Link, InstallRequirement) -> InstallRequirement
  32. assert not template.editable, "template is editable"
  33. if template.req:
  34. line = str(template.req)
  35. else:
  36. line = link.url
  37. ireq = install_req_from_line(
  38. line,
  39. user_supplied=template.user_supplied,
  40. comes_from=template.comes_from,
  41. use_pep517=template.use_pep517,
  42. isolated=template.isolated,
  43. constraint=template.constraint,
  44. options=dict(
  45. install_options=template.install_options,
  46. global_options=template.global_options,
  47. hashes=template.hash_options
  48. ),
  49. )
  50. ireq.original_link = template.original_link
  51. ireq.link = link
  52. return ireq
  53. def make_install_req_from_editable(link, template):
  54. # type: (Link, InstallRequirement) -> InstallRequirement
  55. assert template.editable, "template not editable"
  56. return install_req_from_editable(
  57. link.url,
  58. user_supplied=template.user_supplied,
  59. comes_from=template.comes_from,
  60. use_pep517=template.use_pep517,
  61. isolated=template.isolated,
  62. constraint=template.constraint,
  63. options=dict(
  64. install_options=template.install_options,
  65. global_options=template.global_options,
  66. hashes=template.hash_options
  67. ),
  68. )
  69. def make_install_req_from_dist(dist, template):
  70. # type: (Distribution, InstallRequirement) -> InstallRequirement
  71. project_name = canonicalize_name(dist.project_name)
  72. if template.req:
  73. line = str(template.req)
  74. elif template.link:
  75. line = "{} @ {}".format(project_name, template.link.url)
  76. else:
  77. line = "{}=={}".format(project_name, dist.parsed_version)
  78. ireq = install_req_from_line(
  79. line,
  80. user_supplied=template.user_supplied,
  81. comes_from=template.comes_from,
  82. use_pep517=template.use_pep517,
  83. isolated=template.isolated,
  84. constraint=template.constraint,
  85. options=dict(
  86. install_options=template.install_options,
  87. global_options=template.global_options,
  88. hashes=template.hash_options
  89. ),
  90. )
  91. ireq.satisfied_by = dist
  92. return ireq
  93. class _InstallRequirementBackedCandidate(Candidate):
  94. """A candidate backed by an ``InstallRequirement``.
  95. This represents a package request with the target not being already
  96. in the environment, and needs to be fetched and installed. The backing
  97. ``InstallRequirement`` is responsible for most of the leg work; this
  98. class exposes appropriate information to the resolver.
  99. :param link: The link passed to the ``InstallRequirement``. The backing
  100. ``InstallRequirement`` will use this link to fetch the distribution.
  101. :param source_link: The link this candidate "originates" from. This is
  102. different from ``link`` when the link is found in the wheel cache.
  103. ``link`` would point to the wheel cache, while this points to the
  104. found remote link (e.g. from pypi.org).
  105. """
  106. is_installed = False
  107. def __init__(
  108. self,
  109. link, # type: Link
  110. source_link, # type: Link
  111. ireq, # type: InstallRequirement
  112. factory, # type: Factory
  113. name=None, # type: Optional[str]
  114. version=None, # type: Optional[_BaseVersion]
  115. ):
  116. # type: (...) -> None
  117. self._link = link
  118. self._source_link = source_link
  119. self._factory = factory
  120. self._ireq = ireq
  121. self._name = name
  122. self._version = version
  123. self.dist = self._prepare()
  124. def __str__(self):
  125. # type: () -> str
  126. return "{} {}".format(self.name, self.version)
  127. def __repr__(self):
  128. # type: () -> str
  129. return "{class_name}({link!r})".format(
  130. class_name=self.__class__.__name__,
  131. link=str(self._link),
  132. )
  133. def __hash__(self):
  134. # type: () -> int
  135. return hash((self.__class__, self._link))
  136. def __eq__(self, other):
  137. # type: (Any) -> bool
  138. if isinstance(other, self.__class__):
  139. return self._link == other._link
  140. return False
  141. # Needed for Python 2, which does not implement this by default
  142. def __ne__(self, other):
  143. # type: (Any) -> bool
  144. return not self.__eq__(other)
  145. @property
  146. def source_link(self):
  147. # type: () -> Optional[Link]
  148. return self._source_link
  149. @property
  150. def project_name(self):
  151. # type: () -> str
  152. """The normalised name of the project the candidate refers to"""
  153. if self._name is None:
  154. self._name = canonicalize_name(self.dist.project_name)
  155. return self._name
  156. @property
  157. def name(self):
  158. # type: () -> str
  159. return self.project_name
  160. @property
  161. def version(self):
  162. # type: () -> _BaseVersion
  163. if self._version is None:
  164. self._version = self.dist.parsed_version
  165. return self._version
  166. def format_for_error(self):
  167. # type: () -> str
  168. return "{} {} (from {})".format(
  169. self.name,
  170. self.version,
  171. self._link.file_path if self._link.is_file else self._link
  172. )
  173. def _prepare_distribution(self):
  174. # type: () -> Distribution
  175. raise NotImplementedError("Override in subclass")
  176. def _check_metadata_consistency(self, dist):
  177. # type: (Distribution) -> None
  178. """Check for consistency of project name and version of dist."""
  179. name = canonicalize_name(dist.project_name)
  180. if self._name is not None and self._name != name:
  181. raise MetadataInconsistent(self._ireq, "name", dist.project_name)
  182. version = dist.parsed_version
  183. if self._version is not None and self._version != version:
  184. raise MetadataInconsistent(self._ireq, "version", dist.version)
  185. def _prepare(self):
  186. # type: () -> Distribution
  187. try:
  188. dist = self._prepare_distribution()
  189. except HashError as e:
  190. # Provide HashError the underlying ireq that caused it. This
  191. # provides context for the resulting error message to show the
  192. # offending line to the user.
  193. e.req = self._ireq
  194. raise
  195. self._check_metadata_consistency(dist)
  196. return dist
  197. def _get_requires_python_dependency(self):
  198. # type: () -> Optional[Requirement]
  199. requires_python = get_requires_python(self.dist)
  200. if requires_python is None:
  201. return None
  202. try:
  203. spec = SpecifierSet(requires_python)
  204. except InvalidSpecifier as e:
  205. message = "Package %r has an invalid Requires-Python: %s"
  206. logger.warning(message, self.name, e)
  207. return None
  208. return self._factory.make_requires_python_requirement(spec)
  209. def iter_dependencies(self, with_requires):
  210. # type: (bool) -> Iterable[Optional[Requirement]]
  211. requires = self.dist.requires() if with_requires else ()
  212. for r in requires:
  213. yield self._factory.make_requirement_from_spec(str(r), self._ireq)
  214. yield self._get_requires_python_dependency()
  215. def get_install_requirement(self):
  216. # type: () -> Optional[InstallRequirement]
  217. return self._ireq
  218. class LinkCandidate(_InstallRequirementBackedCandidate):
  219. is_editable = False
  220. def __init__(
  221. self,
  222. link, # type: Link
  223. template, # type: InstallRequirement
  224. factory, # type: Factory
  225. name=None, # type: Optional[str]
  226. version=None, # type: Optional[_BaseVersion]
  227. ):
  228. # type: (...) -> None
  229. source_link = link
  230. cache_entry = factory.get_wheel_cache_entry(link, name)
  231. if cache_entry is not None:
  232. logger.debug("Using cached wheel link: %s", cache_entry.link)
  233. link = cache_entry.link
  234. ireq = make_install_req_from_link(link, template)
  235. assert ireq.link == link
  236. if ireq.link.is_wheel and not ireq.link.is_file:
  237. wheel = Wheel(ireq.link.filename)
  238. wheel_name = canonicalize_name(wheel.name)
  239. assert name == wheel_name, (
  240. "{!r} != {!r} for wheel".format(name, wheel_name)
  241. )
  242. # Version may not be present for PEP 508 direct URLs
  243. if version is not None:
  244. wheel_version = Version(wheel.version)
  245. assert version == wheel_version, (
  246. "{!r} != {!r} for wheel {}".format(
  247. version, wheel_version, name
  248. )
  249. )
  250. if (cache_entry is not None and
  251. cache_entry.persistent and
  252. template.link is template.original_link):
  253. ireq.original_link_is_in_wheel_cache = True
  254. super(LinkCandidate, self).__init__(
  255. link=link,
  256. source_link=source_link,
  257. ireq=ireq,
  258. factory=factory,
  259. name=name,
  260. version=version,
  261. )
  262. def _prepare_distribution(self):
  263. # type: () -> Distribution
  264. return self._factory.preparer.prepare_linked_requirement(
  265. self._ireq, parallel_builds=True,
  266. )
  267. class EditableCandidate(_InstallRequirementBackedCandidate):
  268. is_editable = True
  269. def __init__(
  270. self,
  271. link, # type: Link
  272. template, # type: InstallRequirement
  273. factory, # type: Factory
  274. name=None, # type: Optional[str]
  275. version=None, # type: Optional[_BaseVersion]
  276. ):
  277. # type: (...) -> None
  278. super(EditableCandidate, self).__init__(
  279. link=link,
  280. source_link=link,
  281. ireq=make_install_req_from_editable(link, template),
  282. factory=factory,
  283. name=name,
  284. version=version,
  285. )
  286. def _prepare_distribution(self):
  287. # type: () -> Distribution
  288. return self._factory.preparer.prepare_editable_requirement(self._ireq)
  289. class AlreadyInstalledCandidate(Candidate):
  290. is_installed = True
  291. source_link = None
  292. def __init__(
  293. self,
  294. dist, # type: Distribution
  295. template, # type: InstallRequirement
  296. factory, # type: Factory
  297. ):
  298. # type: (...) -> None
  299. self.dist = dist
  300. self._ireq = make_install_req_from_dist(dist, template)
  301. self._factory = factory
  302. # This is just logging some messages, so we can do it eagerly.
  303. # The returned dist would be exactly the same as self.dist because we
  304. # set satisfied_by in make_install_req_from_dist.
  305. # TODO: Supply reason based on force_reinstall and upgrade_strategy.
  306. skip_reason = "already satisfied"
  307. factory.preparer.prepare_installed_requirement(self._ireq, skip_reason)
  308. def __str__(self):
  309. # type: () -> str
  310. return str(self.dist)
  311. def __repr__(self):
  312. # type: () -> str
  313. return "{class_name}({distribution!r})".format(
  314. class_name=self.__class__.__name__,
  315. distribution=self.dist,
  316. )
  317. def __hash__(self):
  318. # type: () -> int
  319. return hash((self.__class__, self.name, self.version))
  320. def __eq__(self, other):
  321. # type: (Any) -> bool
  322. if isinstance(other, self.__class__):
  323. return self.name == other.name and self.version == other.version
  324. return False
  325. # Needed for Python 2, which does not implement this by default
  326. def __ne__(self, other):
  327. # type: (Any) -> bool
  328. return not self.__eq__(other)
  329. @property
  330. def project_name(self):
  331. # type: () -> str
  332. return canonicalize_name(self.dist.project_name)
  333. @property
  334. def name(self):
  335. # type: () -> str
  336. return self.project_name
  337. @property
  338. def version(self):
  339. # type: () -> _BaseVersion
  340. return self.dist.parsed_version
  341. @property
  342. def is_editable(self):
  343. # type: () -> bool
  344. return dist_is_editable(self.dist)
  345. def format_for_error(self):
  346. # type: () -> str
  347. return "{} {} (Installed)".format(self.name, self.version)
  348. def iter_dependencies(self, with_requires):
  349. # type: (bool) -> Iterable[Optional[Requirement]]
  350. if not with_requires:
  351. return
  352. for r in self.dist.requires():
  353. yield self._factory.make_requirement_from_spec(str(r), self._ireq)
  354. def get_install_requirement(self):
  355. # type: () -> Optional[InstallRequirement]
  356. return None
  357. class ExtrasCandidate(Candidate):
  358. """A candidate that has 'extras', indicating additional dependencies.
  359. Requirements can be for a project with dependencies, something like
  360. foo[extra]. The extras don't affect the project/version being installed
  361. directly, but indicate that we need additional dependencies. We model that
  362. by having an artificial ExtrasCandidate that wraps the "base" candidate.
  363. The ExtrasCandidate differs from the base in the following ways:
  364. 1. It has a unique name, of the form foo[extra]. This causes the resolver
  365. to treat it as a separate node in the dependency graph.
  366. 2. When we're getting the candidate's dependencies,
  367. a) We specify that we want the extra dependencies as well.
  368. b) We add a dependency on the base candidate.
  369. See below for why this is needed.
  370. 3. We return None for the underlying InstallRequirement, as the base
  371. candidate will provide it, and we don't want to end up with duplicates.
  372. The dependency on the base candidate is needed so that the resolver can't
  373. decide that it should recommend foo[extra1] version 1.0 and foo[extra2]
  374. version 2.0. Having those candidates depend on foo=1.0 and foo=2.0
  375. respectively forces the resolver to recognise that this is a conflict.
  376. """
  377. def __init__(
  378. self,
  379. base, # type: BaseCandidate
  380. extras, # type: FrozenSet[str]
  381. ):
  382. # type: (...) -> None
  383. self.base = base
  384. self.extras = extras
  385. def __str__(self):
  386. # type: () -> str
  387. name, rest = str(self.base).split(" ", 1)
  388. return "{}[{}] {}".format(name, ",".join(self.extras), rest)
  389. def __repr__(self):
  390. # type: () -> str
  391. return "{class_name}(base={base!r}, extras={extras!r})".format(
  392. class_name=self.__class__.__name__,
  393. base=self.base,
  394. extras=self.extras,
  395. )
  396. def __hash__(self):
  397. # type: () -> int
  398. return hash((self.base, self.extras))
  399. def __eq__(self, other):
  400. # type: (Any) -> bool
  401. if isinstance(other, self.__class__):
  402. return self.base == other.base and self.extras == other.extras
  403. return False
  404. # Needed for Python 2, which does not implement this by default
  405. def __ne__(self, other):
  406. # type: (Any) -> bool
  407. return not self.__eq__(other)
  408. @property
  409. def project_name(self):
  410. # type: () -> str
  411. return self.base.project_name
  412. @property
  413. def name(self):
  414. # type: () -> str
  415. """The normalised name of the project the candidate refers to"""
  416. return format_name(self.base.project_name, self.extras)
  417. @property
  418. def version(self):
  419. # type: () -> _BaseVersion
  420. return self.base.version
  421. def format_for_error(self):
  422. # type: () -> str
  423. return "{} [{}]".format(
  424. self.base.format_for_error(),
  425. ", ".join(sorted(self.extras))
  426. )
  427. @property
  428. def is_installed(self):
  429. # type: () -> bool
  430. return self.base.is_installed
  431. @property
  432. def is_editable(self):
  433. # type: () -> bool
  434. return self.base.is_editable
  435. @property
  436. def source_link(self):
  437. # type: () -> Optional[Link]
  438. return self.base.source_link
  439. def iter_dependencies(self, with_requires):
  440. # type: (bool) -> Iterable[Optional[Requirement]]
  441. factory = self.base._factory
  442. # Add a dependency on the exact base
  443. # (See note 2b in the class docstring)
  444. yield factory.make_requirement_from_candidate(self.base)
  445. if not with_requires:
  446. return
  447. # The user may have specified extras that the candidate doesn't
  448. # support. We ignore any unsupported extras here.
  449. valid_extras = self.extras.intersection(self.base.dist.extras)
  450. invalid_extras = self.extras.difference(self.base.dist.extras)
  451. for extra in sorted(invalid_extras):
  452. logger.warning(
  453. "%s %s does not provide the extra '%s'",
  454. self.base.name,
  455. self.version,
  456. extra
  457. )
  458. for r in self.base.dist.requires(valid_extras):
  459. requirement = factory.make_requirement_from_spec(
  460. str(r), self.base._ireq, valid_extras,
  461. )
  462. if requirement:
  463. yield requirement
  464. def get_install_requirement(self):
  465. # type: () -> Optional[InstallRequirement]
  466. # We don't return anything here, because we always
  467. # depend on the base candidate, and we'll get the
  468. # install requirement from that.
  469. return None
  470. class RequiresPythonCandidate(Candidate):
  471. is_installed = False
  472. source_link = None
  473. def __init__(self, py_version_info):
  474. # type: (Optional[Tuple[int, ...]]) -> None
  475. if py_version_info is not None:
  476. version_info = normalize_version_info(py_version_info)
  477. else:
  478. version_info = sys.version_info[:3]
  479. self._version = Version(".".join(str(c) for c in version_info))
  480. # We don't need to implement __eq__() and __ne__() since there is always
  481. # only one RequiresPythonCandidate in a resolution, i.e. the host Python.
  482. # The built-in object.__eq__() and object.__ne__() do exactly what we want.
  483. def __str__(self):
  484. # type: () -> str
  485. return "Python {}".format(self._version)
  486. @property
  487. def project_name(self):
  488. # type: () -> str
  489. # Avoid conflicting with the PyPI package "Python".
  490. return "<Python from Requires-Python>"
  491. @property
  492. def name(self):
  493. # type: () -> str
  494. return self.project_name
  495. @property
  496. def version(self):
  497. # type: () -> _BaseVersion
  498. return self._version
  499. def format_for_error(self):
  500. # type: () -> str
  501. return "Python {}".format(self.version)
  502. def iter_dependencies(self, with_requires):
  503. # type: (bool) -> Iterable[Optional[Requirement]]
  504. return ()
  505. def get_install_requirement(self):
  506. # type: () -> Optional[InstallRequirement]
  507. return None