123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101 |
- """Utilities to lazily create and visit candidates found.
- Creating and visiting a candidate is a *very* costly operation. It involves
- fetching, extracting, potentially building modules from source, and verifying
- distribution metadata. It is therefore crucial for performance to keep
- everything here lazy all the way down, so we only touch candidates that we
- absolutely need, and not "download the world" when we only need one version of
- something.
- """
- import itertools
- from pip._vendor.six.moves import collections_abc # type: ignore
- from pip._internal.utils.compat import lru_cache
- from pip._internal.utils.typing import MYPY_CHECK_RUNNING
- if MYPY_CHECK_RUNNING:
- from typing import Callable, Iterator, Optional
- from .base import Candidate
- def _insert_installed(installed, others):
- # type: (Candidate, Iterator[Candidate]) -> Iterator[Candidate]
- """Iterator for ``FoundCandidates``.
- This iterator is used when the resolver prefers to upgrade an
- already-installed package. Candidates from index are returned in their
- normal ordering, except replaced when the version is already installed.
- The implementation iterates through and yields other candidates, inserting
- the installed candidate exactly once before we start yielding older or
- equivalent candidates, or after all other candidates if they are all newer.
- """
- installed_yielded = False
- for candidate in others:
- # If the installed candidate is better, yield it first.
- if not installed_yielded and installed.version >= candidate.version:
- yield installed
- installed_yielded = True
- yield candidate
- # If the installed candidate is older than all other candidates.
- if not installed_yielded:
- yield installed
- class FoundCandidates(collections_abc.Sequence):
- """A lazy sequence to provide candidates to the resolver.
- The intended usage is to return this from `find_matches()` so the resolver
- can iterate through the sequence multiple times, but only access the index
- page when remote packages are actually needed. This improve performances
- when suitable candidates are already installed on disk.
- """
- def __init__(
- self,
- get_others, # type: Callable[[], Iterator[Candidate]]
- installed, # type: Optional[Candidate]
- prefers_installed, # type: bool
- ):
- self._get_others = get_others
- self._installed = installed
- self._prefers_installed = prefers_installed
- def __getitem__(self, index):
- # type: (int) -> Candidate
- # Implemented to satisfy the ABC check. This is not needed by the
- # resolver, and should not be used by the provider either (for
- # performance reasons).
- raise NotImplementedError("don't do this")
- def __iter__(self):
- # type: () -> Iterator[Candidate]
- if not self._installed:
- return self._get_others()
- others = (
- candidate
- for candidate in self._get_others()
- if candidate.version != self._installed.version
- )
- if self._prefers_installed:
- return itertools.chain([self._installed], others)
- return _insert_installed(self._installed, others)
- def __len__(self):
- # type: () -> int
- # Implemented to satisfy the ABC check. This is not needed by the
- # resolver, and should not be used by the provider either (for
- # performance reasons).
- raise NotImplementedError("don't do this")
- @lru_cache(maxsize=1)
- def __bool__(self):
- # type: () -> bool
- if self._prefers_installed and self._installed:
- return True
- return any(self)
- __nonzero__ = __bool__ # XXX: Python 2.
|