diff --git a/pip/index.py b/pip/index.py index 11c291fa9e0..331499bcc8b 100644 --- a/pip/index.py +++ b/pip/index.py @@ -17,7 +17,7 @@ from pip.compat import ipaddress from pip.utils import ( - Inf, cached_property, splitext, normalize_path, + cached_property, splitext, normalize_path, ARCHIVE_EXTENSIONS, SUPPORTED_EXTENSIONS, canonicalize_name) from pip.utils.deprecation import RemovedInPip9Warning from pip.utils.logging import indent_log @@ -233,9 +233,7 @@ def _candidate_sort_key(self, candidate): with the same version, would have to be considered equal """ support_num = len(supported_tags) - if candidate.location == INSTALLED_VERSION: - pri = 1 - elif candidate.location.is_wheel: + if candidate.location.is_wheel: # can raise InvalidWheelFilename wheel = Wheel(candidate.location.filename) if not wheel.supported(): @@ -439,7 +437,7 @@ def find_requirement(self, req, upgrade): Returns a Link if found, Raises DistributionNotFound or BestVersionAlreadyInstalled otherwise """ - all_versions = self._find_all_versions(req.name) + all_candidates = self._find_all_versions(req.name) # Filter out anything which doesn't match our specifier _versions = set( @@ -451,58 +449,33 @@ def find_requirement(self, req, upgrade): # types. This way we'll use a str as a common data interchange # format. If we stop using the pkg_resources provided specifier # and start using our own, we can drop the cast to str(). - [str(x.version) for x in all_versions], + [str(c.version) for c in all_candidates], prereleases=( self.allow_all_prereleases if self.allow_all_prereleases else None ), ) ) - applicable_versions = [ + applicable_candidates = [ # Again, converting to str to deal with debundling. - x for x in all_versions if str(x.version) in _versions + c for c in all_candidates if str(c.version) in _versions ] + applicable_candidates = self._sort_versions(applicable_candidates) + if req.satisfied_by is not None: - # Finally add our existing versions to the front of our versions. - applicable_versions.insert( - 0, - InstallationCandidate( - req.name, - req.satisfied_by.version, - INSTALLED_VERSION, - ) - ) - existing_applicable = True + installed_version = parse_version(req.satisfied_by.version) else: - existing_applicable = False + installed_version = None - applicable_versions = self._sort_versions(applicable_versions) - - if not upgrade and existing_applicable: - if applicable_versions[0].location is INSTALLED_VERSION: - logger.debug( - 'Existing installed version (%s) is most up-to-date and ' - 'satisfies requirement', - req.satisfied_by.version, - ) - else: - logger.debug( - 'Existing installed version (%s) satisfies requirement ' - '(most up-to-date version is %s)', - req.satisfied_by.version, - applicable_versions[0][2], - ) - return None - - if not applicable_versions: + if installed_version is None and not applicable_candidates: logger.critical( 'Could not find a version that satisfies the requirement %s ' '(from versions: %s)', req, ', '.join( sorted( - set(str(i.version) for i in all_versions), + set(str(c.version) for c in all_candidates), key=parse_version, ) ) @@ -512,27 +485,46 @@ def find_requirement(self, req, upgrade): 'No matching distribution found for %s' % req ) - if applicable_versions[0].location is INSTALLED_VERSION: + best_installed = False + if installed_version and ( + not applicable_candidates or + applicable_candidates[0].version <= installed_version): + best_installed = True + + if not upgrade and installed_version is not None: + if best_installed: + logger.debug( + 'Existing installed version (%s) is most up-to-date and ' + 'satisfies requirement', + installed_version, + ) + else: + logger.debug( + 'Existing installed version (%s) satisfies requirement ' + '(most up-to-date version is %s)', + installed_version, + applicable_candidates[0].version, + ) + return None + + if best_installed: # We have an existing version, and its the best version logger.debug( 'Installed version (%s) is most up-to-date (past versions: ' '%s)', - req.satisfied_by.version, - ', '.join(str(i.version) for i in applicable_versions[1:]) or + installed_version, + ', '.join(str(c.version) for c in applicable_candidates) or "none", ) raise BestVersionAlreadyInstalled - if len(applicable_versions) > 1: - logger.debug( - 'Using version %s (newest of versions: %s)', - applicable_versions[0].version, - ', '.join(str(i.version) for i in applicable_versions) - ) - - selected_version = applicable_versions[0].location - - return selected_version + selected_candidate = applicable_candidates[0] + logger.debug( + 'Using version %s (newest of versions: %s)', + selected_candidate.version, + ', '.join(str(c.version) for c in applicable_candidates) + ) + return selected_candidate.location def _get_pages(self, locations, project_name): """ @@ -873,7 +865,7 @@ class Link(object): def __init__(self, url, comes_from=None): # url can be a UNC windows share - if url != Inf and url.startswith('\\\\'): + if url.startswith('\\\\'): url = path_to_url(url) self.url = url @@ -1002,11 +994,6 @@ def is_artifact(self): return True -# An object to represent the "link" for the installed version of a requirement. -# Using Inf as the url makes it sort higher. -INSTALLED_VERSION = Link(Inf) - - FormatControl = namedtuple('FormatControl', 'no_binary only_binary') """This object has two fields, no_binary and only_binary. diff --git a/pip/utils/__init__.py b/pip/utils/__init__.py index 30f5e28b458..55ee12dd803 100644 --- a/pip/utils/__init__.py +++ b/pip/utils/__init__.py @@ -31,7 +31,7 @@ from io import StringIO __all__ = ['rmtree', 'display_path', 'backup_dir', - 'ask', 'Inf', 'splitext', + 'ask', 'splitext', 'format_size', 'is_installable_dir', 'is_svn_page', 'file_contents', 'split_leading_dir', 'has_leading_dir', @@ -154,38 +154,6 @@ def ask(message, options): return response -class _Inf(object): - """I am bigger than everything!""" - - def __eq__(self, other): - if self is other: - return True - else: - return False - - def __ne__(self, other): - return not self.__eq__(other) - - def __lt__(self, other): - return False - - def __le__(self, other): - return False - - def __gt__(self, other): - return True - - def __ge__(self, other): - return True - - def __repr__(self): - return 'Inf' - - -Inf = _Inf() # this object is not currently used as a sortable in our code -del _Inf - - def format_size(bytes): if bytes > 1000 * 1000: return '%.1fMB' % (bytes / 1000.0 / 1000) diff --git a/tests/unit/test_finder.py b/tests/unit/test_finder.py index 6c30ac891d8..a0be615c23a 100644 --- a/tests/unit/test_finder.py +++ b/tests/unit/test_finder.py @@ -11,7 +11,6 @@ from pip.exceptions import ( BestVersionAlreadyInstalled, DistributionNotFound, InstallationError, ) -from pip.utils import Inf from pip.download import PipSession from mock import Mock, patch @@ -225,7 +224,6 @@ def test_link_sorting(self): Test link sorting """ links = [ - InstallationCandidate("simple", "2.0", Link(Inf)), InstallationCandidate("simple", "2.0", Link('simple-2.0.tar.gz')), InstallationCandidate( "simple", diff --git a/tests/unit/test_index.py b/tests/unit/test_index.py index 96a6d60ea56..9d3bb67d298 100644 --- a/tests/unit/test_index.py +++ b/tests/unit/test_index.py @@ -2,7 +2,7 @@ from pip.download import PipSession from pip.index import HTMLPage -from pip.index import PackageFinder, Link, INSTALLED_VERSION +from pip.index import PackageFinder, Link def test_sort_locations_file_expand_dir(data): @@ -27,11 +27,6 @@ def test_sort_locations_file_not_find_link(data): assert urls and not files, "urls, but not files should have been found" -def test_INSTALLED_VERSION_greater(): - """Test INSTALLED_VERSION compares greater.""" - assert INSTALLED_VERSION > Link("some link") - - class TestLink(object): def test_splitext(self): diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py index bb025a3f013..9191a00484c 100644 --- a/tests/unit/test_utils.py +++ b/tests/unit/test_utils.py @@ -12,7 +12,7 @@ import pytest from mock import Mock, patch -from pip.utils import (egg_link_path, Inf, get_installed_distributions, +from pip.utils import (egg_link_path, get_installed_distributions, untar_file, unzip_file, rmtree, normalize_path) from pip.operations.freeze import freeze_excludes @@ -151,16 +151,6 @@ def test_noegglink_in_sitepkgs_venv_global(self): assert egg_link_path(self.mock_dist) is None -def test_Inf_greater(): - """Test Inf compares greater.""" - assert Inf > object() - - -def test_Inf_equals_Inf(): - """Test Inf compares greater.""" - assert Inf == Inf - - @patch('pip.utils.dist_in_usersite') @patch('pip.utils.dist_is_local') @patch('pip.utils.dist_is_editable')