about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-master.tar.gz
two version of R2R are here HEAD master
Diffstat (limited to '.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py')
-rw-r--r--.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py174
1 files changed, 174 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py b/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py
new file mode 100644
index 00000000..a1d57e0f
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py
@@ -0,0 +1,174 @@
+"""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 functools
+import logging
+from collections.abc import Sequence
+from typing import TYPE_CHECKING, Any, Callable, Iterator, Optional, Set, Tuple
+
+from pip._vendor.packaging.version import _BaseVersion
+
+from pip._internal.exceptions import MetadataInvalid
+
+from .base import Candidate
+
+logger = logging.getLogger(__name__)
+
+IndexCandidateInfo = Tuple[_BaseVersion, Callable[[], Optional[Candidate]]]
+
+if TYPE_CHECKING:
+    SequenceCandidate = Sequence[Candidate]
+else:
+    # For compatibility: Python before 3.9 does not support using [] on the
+    # Sequence class.
+    #
+    # >>> from collections.abc import Sequence
+    # >>> Sequence[str]
+    # Traceback (most recent call last):
+    #   File "<stdin>", line 1, in <module>
+    # TypeError: 'ABCMeta' object is not subscriptable
+    #
+    # TODO: Remove this block after dropping Python 3.8 support.
+    SequenceCandidate = Sequence
+
+
+def _iter_built(infos: Iterator[IndexCandidateInfo]) -> Iterator[Candidate]:
+    """Iterator for ``FoundCandidates``.
+
+    This iterator is used when the package is not already installed. Candidates
+    from index come later in their normal ordering.
+    """
+    versions_found: Set[_BaseVersion] = set()
+    for version, func in infos:
+        if version in versions_found:
+            continue
+        try:
+            candidate = func()
+        except MetadataInvalid as e:
+            logger.warning(
+                "Ignoring version %s of %s since it has invalid metadata:\n"
+                "%s\n"
+                "Please use pip<24.1 if you need to use this version.",
+                version,
+                e.ireq.name,
+                e,
+            )
+            # Mark version as found to avoid trying other candidates with the same
+            # version, since they most likely have invalid metadata as well.
+            versions_found.add(version)
+        else:
+            if candidate is None:
+                continue
+            yield candidate
+            versions_found.add(version)
+
+
+def _iter_built_with_prepended(
+    installed: Candidate, infos: Iterator[IndexCandidateInfo]
+) -> Iterator[Candidate]:
+    """Iterator for ``FoundCandidates``.
+
+    This iterator is used when the resolver prefers the already-installed
+    candidate and NOT to upgrade. The installed candidate is therefore
+    always yielded first, and candidates from index come later in their
+    normal ordering, except skipped when the version is already installed.
+    """
+    yield installed
+    versions_found: Set[_BaseVersion] = {installed.version}
+    for version, func in infos:
+        if version in versions_found:
+            continue
+        candidate = func()
+        if candidate is None:
+            continue
+        yield candidate
+        versions_found.add(version)
+
+
+def _iter_built_with_inserted(
+    installed: Candidate, infos: Iterator[IndexCandidateInfo]
+) -> 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.
+    """
+    versions_found: Set[_BaseVersion] = set()
+    for version, func in infos:
+        if version in versions_found:
+            continue
+        # If the installed candidate is better, yield it first.
+        if installed.version >= version:
+            yield installed
+            versions_found.add(installed.version)
+        candidate = func()
+        if candidate is None:
+            continue
+        yield candidate
+        versions_found.add(version)
+
+    # If the installed candidate is older than all other candidates.
+    if installed.version not in versions_found:
+        yield installed
+
+
+class FoundCandidates(SequenceCandidate):
+    """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_infos: Callable[[], Iterator[IndexCandidateInfo]],
+        installed: Optional[Candidate],
+        prefers_installed: bool,
+        incompatible_ids: Set[int],
+    ):
+        self._get_infos = get_infos
+        self._installed = installed
+        self._prefers_installed = prefers_installed
+        self._incompatible_ids = incompatible_ids
+
+    def __getitem__(self, index: Any) -> Any:
+        # 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) -> Iterator[Candidate]:
+        infos = self._get_infos()
+        if not self._installed:
+            iterator = _iter_built(infos)
+        elif self._prefers_installed:
+            iterator = _iter_built_with_prepended(self._installed, infos)
+        else:
+            iterator = _iter_built_with_inserted(self._installed, infos)
+        return (c for c in iterator if id(c) not in self._incompatible_ids)
+
+    def __len__(self) -> 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")
+
+    @functools.lru_cache(maxsize=1)
+    def __bool__(self) -> bool:
+        if self._prefers_installed and self._installed:
+            return True
+        return any(self)