Skip to content

Commit f5a70cc

Browse files
committed
Pre-warm find_all_candidates cache in finder
1 parent 75c11c4 commit f5a70cc

File tree

2 files changed

+41
-1
lines changed

2 files changed

+41
-1
lines changed

src/pip/_internal/resolution/resolvelib/resolver.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import functools
22
import logging
33
import os
4-
from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple, cast
4+
from typing import TYPE_CHECKING, Dict, Iterator, List, Optional, Set, Tuple, cast
55

66
from pip._vendor.packaging.utils import canonicalize_name
77
from pip._vendor.resolvelib import BaseReporter, ResolutionImpossible
@@ -19,6 +19,7 @@
1919
PipDebuggingReporter,
2020
PipReporter,
2121
)
22+
from pip._internal.utils.parallel import LACK_SEM_OPEN, map_multithread
2223

2324
from .base import Candidate, Requirement
2425
from .factory import Factory
@@ -66,6 +67,7 @@ def __init__(
6667
self.ignore_dependencies = ignore_dependencies
6768
self.upgrade_strategy = upgrade_strategy
6869
self._result: Optional[Result] = None
70+
self._finder = finder
6971

7072
def resolve(
7173
self, root_reqs: List[InstallRequirement], check_supported_wheels: bool
@@ -87,6 +89,8 @@ def resolve(
8789
reporter,
8890
)
8991

92+
self.prime_finder_cache(provider.identify(r) for r in collected.requirements)
93+
9094
try:
9195
try_to_avoid_resolution_too_deep = 2000000
9296
result = self._result = resolver.resolve(
@@ -161,6 +165,22 @@ def resolve(
161165
self.factory.preparer.prepare_linked_requirements_more(reqs)
162166
return req_set
163167

168+
def prime_finder_cache(self, project_names: Iterator[str]) -> None:
169+
if LACK_SEM_OPEN:
170+
return
171+
172+
if not hasattr(self._finder.find_all_candidates, "cache_info"):
173+
return
174+
175+
def _maybe_find_candidates(project_name: str) -> None:
176+
try:
177+
self._finder.find_all_candidates(project_name)
178+
except AttributeError:
179+
pass
180+
181+
for _ in map_multithread(_maybe_find_candidates, project_names):
182+
pass
183+
164184
def get_installation_order(
165185
self, req_set: RequirementSet
166186
) -> List[InstallRequirement]:

tests/unit/test_finder.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,3 +558,23 @@ def test_find_all_candidates_find_links_and_index(data: TestData) -> None:
558558
versions = finder.find_all_candidates("simple")
559559
# first the find-links versions then the page versions
560560
assert [str(v.version) for v in versions] == ["3.0", "2.0", "1.0", "1.0"]
561+
562+
def test_finder_caching(data: TestData) -> None:
563+
finder = make_test_finder(
564+
find_links=[data.find_links],
565+
index_urls=[data.index_url("simple")],
566+
)
567+
def get_findall_cacheinfo():
568+
cacheinfo = finder.find_all_candidates.cache_info()
569+
return {k: getattr(cacheinfo, k) for k in ['currsize', 'hits', 'misses']}
570+
571+
# empty before any calls
572+
assert get_findall_cacheinfo() == {"currsize": 0, "hits": 0, "misses": 0}
573+
574+
# first findall is a miss
575+
finder.find_all_candidates("simple")
576+
assert get_findall_cacheinfo() == {"currsize": 1, "hits": 0, "misses": 1}
577+
578+
# find best following a find all is a hit
579+
finder.find_best_candidate("simple")
580+
assert get_findall_cacheinfo() == {"currsize": 1, "hits": 1, "misses": 1}

0 commit comments

Comments
 (0)