diff --git a/pip/req/req_set.py b/pip/req/req_set.py index 9c382650a46..1b80f191ef8 100644 --- a/pip/req/req_set.py +++ b/pip/req/req_set.py @@ -225,7 +225,12 @@ def prepare_files(self, finder): if not self.ignore_installed and not req_to_install.editable: req_to_install.check_if_exists() if req_to_install.satisfied_by: - if self.upgrade: + # check that we don't already have an exact version match + # i.e. with at least one strict req operator + strict_req = set(('==', '===')) & set( + op for op, _ in req_to_install.req.specs) + if self.upgrade and (not strict_req or + self.force_reinstall): if not (self.force_reinstall or req_to_install.link): try: link = finder.find_requirement( diff --git a/tests/unit/test_req.py b/tests/unit/test_req.py index 35d7cd11ac2..7f38cfdcc9c 100644 --- a/tests/unit/test_req.py +++ b/tests/unit/test_req.py @@ -8,6 +8,7 @@ from mock import Mock, patch, mock_open from pip.exceptions import ( PreviousBuildDirError, InvalidWheelFilename, UnsupportedWheel, + BestVersionAlreadyInstalled, ) from pip.download import PipSession from pip.index import PackageFinder @@ -54,6 +55,60 @@ def test_no_reuse_existing_build_dir(self, data): finder, ) + @patch( + 'pip.req.req_install.pkg_resources.get_distribution', + lambda x: pkg_resources.Distribution( + project_name='Pygments', + version='2.0.2', + location='/python', + ) + ) + def test_upgrade_no_look_at_pypi_if_exact_version_installed( + self, data): + """ + If an exact version is specified for install, and that version is + already installed, then there is no point going to pypi as no install + is needed. + """ + reqset = self.basic_reqset() + reqset.upgrade = True + req = InstallRequirement.from_line('pygments==2.0.2') + req.url = None + reqset.add_requirement(req) + finder = PackageFinder([data.find_links], [], session=PipSession()) + with patch.object(finder, 'find_requirement') as find_requirement: + find_requirement.side_effect = AssertionError( + 'find_requirement should NOT be called') + reqset.prepare_files(finder) + + @patch( + 'pip.req.req_install.pkg_resources.get_distribution', + lambda x: pkg_resources.Distribution( + project_name='Pygments', + version='2.0.2', + location='/python', + ) + ) + def test_upgrade_look_at_pypi_if_exact_version_installed_and_force( + self, data): + """ + If an exact version is specified for install, and that version is + already installed, but --force-reinstall was provided, we should hit + PyPI. + """ + reqset = self.basic_reqset() + reqset.upgrade = True + reqset.force_reinstall = True + req = InstallRequirement.from_line('pygments==2.0.2') + req.url = None + reqset.add_requirement(req) + finder = PackageFinder([data.find_links], [], session=PipSession()) + with patch.object(finder, 'find_requirement') as find_requirement: + find_requirement.side_effect = BestVersionAlreadyInstalled + with pytest.raises(BestVersionAlreadyInstalled): + reqset.prepare_files(finder) + find_requirement.assert_called_once() + def test_environment_marker_extras(self, data): """ Test that the environment marker extras are used with