From 8bf159f4c777e22fc3e07ae89af73503cad64107 Mon Sep 17 00:00:00 2001 From: Tzu-ping Chung Date: Wed, 9 Dec 2020 11:27:51 +0800 Subject: [PATCH 1/3] Intentionally delay resolving setuptools --- src/pip/_internal/resolution/resolvelib/provider.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/pip/_internal/resolution/resolvelib/provider.py b/src/pip/_internal/resolution/resolvelib/provider.py index 3883135f1..40a641a2a 100644 --- a/src/pip/_internal/resolution/resolvelib/provider.py +++ b/src/pip/_internal/resolution/resolvelib/provider.py @@ -117,7 +117,18 @@ class PipProvider(AbstractProvider): restrictive = _get_restrictive_rating(req for req, _ in information) transitive = all(parent is not None for _, parent in information) key = next(iter(candidates)).name if candidates else "" - return (restrictive, transitive, key) + + # HACK: Setuptools have a very long and solid backward compatibility + # track record, and extremely few projects would request a narrow, + # non-recent version range of it since that would break a lot things. + # (Most projects specify it only to request for an installer feature, + # which does not work, but that's another topic.) Intentionally + # delaying Setuptools helps reduce branches the resolver has to check. + # This serves as a temporary fix for issues like "apache-airlfow[all]" + # while we work on "proper" branch pruning techniques. + delay_this = (key == "setuptools") + + return (delay_this, restrictive, transitive, key) def find_matches(self, requirements): # type: (Sequence[Requirement]) -> Iterable[Candidate] From 52523832481d33237acb9f03a2154500d2b63ad5 Mon Sep 17 00:00:00 2001 From: Tzu-ping Chung Date: Wed, 9 Dec 2020 18:42:17 +0800 Subject: [PATCH 2/3] News entry for setuptools priority hack --- news/9249.feature.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 news/9249.feature.rst diff --git a/news/9249.feature.rst b/news/9249.feature.rst new file mode 100644 index 000000000..1c56b39ef --- /dev/null +++ b/news/9249.feature.rst @@ -0,0 +1 @@ +Add a mechanism to delay resolving certain packages, and use it for setuptools. From 120105d3e8566f79449bea968515944dcb68dbfc Mon Sep 17 00:00:00 2001 From: Tzu-ping Chung Date: Sat, 12 Dec 2020 02:19:51 +0800 Subject: [PATCH 3/3] Cache AlreadyInstalledCandidate Since the "Requirement already satisfied" message is printed during candidate preparation, instantiating the candidate multiple times result in excessive logging during intensive backtracking. By caching the already-installed candidates, each package is only prepared, and thus only logged once. --- news/9117.bugfix.rst | 2 ++ src/pip/_internal/resolution/resolvelib/factory.py | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 news/9117.bugfix.rst diff --git a/news/9117.bugfix.rst b/news/9117.bugfix.rst new file mode 100644 index 000000000..7991dac7d --- /dev/null +++ b/news/9117.bugfix.rst @@ -0,0 +1,2 @@ +New resolver: The "Requirement already satisfied" log is not printed only once +for each package during resolution. diff --git a/src/pip/_internal/resolution/resolvelib/factory.py b/src/pip/_internal/resolution/resolvelib/factory.py index c723d343b..b4c7bf113 100644 --- a/src/pip/_internal/resolution/resolvelib/factory.py +++ b/src/pip/_internal/resolution/resolvelib/factory.py @@ -96,6 +96,8 @@ class Factory(object): self._link_candidate_cache = {} # type: Cache[LinkCandidate] self._editable_candidate_cache = {} # type: Cache[EditableCandidate] + self._installed_candidate_cache = { + } # type: Dict[str, AlreadyInstalledCandidate] if not ignore_installed: self._installed_dists = { @@ -117,7 +119,11 @@ class Factory(object): template, # type: InstallRequirement ): # type: (...) -> Candidate - base = AlreadyInstalledCandidate(dist, template, factory=self) + try: + base = self._installed_candidate_cache[dist.key] + except KeyError: + base = AlreadyInstalledCandidate(dist, template, factory=self) + self._installed_candidate_cache[dist.key] = base if extras: return ExtrasCandidate(base, extras) return base