From ec86cb1970ff670fb374c31337587c0b41ffa435 Mon Sep 17 00:00:00 2001 From: Tzu-ping Chung Date: Mon, 18 May 2020 16:35:09 +0800 Subject: [PATCH 1/2] Use OrderedDict to prefer links found *later* --- .../resolution/resolvelib/factory.py | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/pip/_internal/resolution/resolvelib/factory.py b/src/pip/_internal/resolution/resolvelib/factory.py index ce93707b7..46e6f1d08 100644 --- a/src/pip/_internal/resolution/resolvelib/factory.py +++ b/src/pip/_internal/resolution/resolvelib/factory.py @@ -1,3 +1,6 @@ +import collections + +from pip._vendor import six from pip._vendor.packaging.utils import canonicalize_name from pip._internal.exceptions import ( @@ -127,11 +130,13 @@ class Factory(object): # requirement needs to return only one candidate per version, so we # implement that logic here so that requirements using this helper # don't all have to do the same thing later. - seen_versions = set() # type: Set[_BaseVersion] + version_candidates = collections.OrderedDict( + ) # type: Dict[_BaseVersion, Candidate] # Yield the installed version, if it matches, unless the user # specified `--force-reinstall`, when we want the version from # the index instead. + installed_version = None if not self._force_reinstall and name in self._installed_dists: installed_dist = self._installed_dists[name] installed_version = installed_dist.parsed_version @@ -139,12 +144,12 @@ class Factory(object): installed_version, prereleases=True ): - seen_versions.add(installed_version) - yield self._make_candidate_from_dist( + candidate = self._make_candidate_from_dist( dist=installed_dist, extras=extras, parent=ireq, ) + version_candidates[installed_version] = candidate found = self.finder.find_best_candidate( project_name=ireq.req.name, @@ -152,15 +157,18 @@ class Factory(object): hashes=ireq.hashes(trust_internet=False), ) for ican in found.iter_applicable(): - if ican.version not in seen_versions: - seen_versions.add(ican.version) - yield self._make_candidate_from_link( - link=ican.link, - extras=extras, - parent=ireq, - name=name, - version=ican.version, - ) + if ican.version == installed_version: + continue + candidate = self._make_candidate_from_link( + link=ican.link, + extras=extras, + parent=ireq, + name=name, + version=ican.version, + ) + version_candidates[ican.version] = candidate + + return six.itervalues(version_candidates) def make_requirement_from_install_req(self, ireq): # type: (InstallRequirement) -> Requirement From f39134699b3f57c409e2b9c1bc986ceeb70cc4d8 Mon Sep 17 00:00:00 2001 From: Tzu-ping Chung Date: Mon, 18 May 2020 17:15:04 +0800 Subject: [PATCH 2/2] Avoid the horrendous line break for type hints --- src/pip/_internal/resolution/resolvelib/factory.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pip/_internal/resolution/resolvelib/factory.py b/src/pip/_internal/resolution/resolvelib/factory.py index 46e6f1d08..3246caffe 100644 --- a/src/pip/_internal/resolution/resolvelib/factory.py +++ b/src/pip/_internal/resolution/resolvelib/factory.py @@ -47,6 +47,7 @@ if MYPY_CHECK_RUNNING: C = TypeVar("C") Cache = Dict[Link, C] + VersionCandidates = Dict[_BaseVersion, Candidate] class Factory(object): @@ -130,8 +131,7 @@ class Factory(object): # requirement needs to return only one candidate per version, so we # implement that logic here so that requirements using this helper # don't all have to do the same thing later. - version_candidates = collections.OrderedDict( - ) # type: Dict[_BaseVersion, Candidate] + candidates = collections.OrderedDict() # type: VersionCandidates # Yield the installed version, if it matches, unless the user # specified `--force-reinstall`, when we want the version from @@ -149,7 +149,7 @@ class Factory(object): extras=extras, parent=ireq, ) - version_candidates[installed_version] = candidate + candidates[installed_version] = candidate found = self.finder.find_best_candidate( project_name=ireq.req.name, @@ -166,9 +166,9 @@ class Factory(object): name=name, version=ican.version, ) - version_candidates[ican.version] = candidate + candidates[ican.version] = candidate - return six.itervalues(version_candidates) + return six.itervalues(candidates) def make_requirement_from_install_req(self, ireq): # type: (InstallRequirement) -> Requirement