diff --git a/news/5346.bugfix b/news/5346.bugfix new file mode 100644 index 000000000..3a652ac55 --- /dev/null +++ b/news/5346.bugfix @@ -0,0 +1,5 @@ +Disable pip's version check (and upgrade message) when installed by a different package manager. + +This works better with Linux distributions where pip's upgrade message may +result in users running pip in a manner that modifies files that should be +managed by the OS's package manager. diff --git a/src/pip/_internal/utils/outdated.py b/src/pip/_internal/utils/outdated.py index d7246da55..8c3b50b98 100644 --- a/src/pip/_internal/utils/outdated.py +++ b/src/pip/_internal/utils/outdated.py @@ -6,7 +6,7 @@ import logging import os.path import sys -from pip._vendor import lockfile +from pip._vendor import lockfile, pkg_resources from pip._vendor.packaging import version as packaging_version from pip._internal.compat import WINDOWS @@ -58,6 +58,20 @@ class SelfCheckState(object): separators=(",", ":")) +def pip_installed_by_pip(): + """Checks whether pip was installed by pip + + This is used not to display the upgrade message when pip is in fact + installed by system package manager, such as dnf on Fedora. + """ + try: + dist = pkg_resources.get_distribution('pip') + return (dist.has_metadata('INSTALLER') and + 'pip' in dist.get_metadata_lines('INSTALLER')) + except pkg_resources.DistributionNotFound: + return False + + def pip_version_check(session, options): """Check for an update for pip. @@ -110,7 +124,8 @@ def pip_version_check(session, options): # Determine if our pypi_version is older if (pip_version < remote_version and - pip_version.base_version != remote_version.base_version): + pip_version.base_version != remote_version.base_version and + pip_installed_by_pip()): # Advise "python -m pip" on Windows to avoid issues # with overwriting pip.exe. if WINDOWS: diff --git a/tests/unit/test_unit_outdated.py b/tests/unit/test_unit_outdated.py index 26a28f723..853531db5 100644 --- a/tests/unit/test_unit_outdated.py +++ b/tests/unit/test_unit_outdated.py @@ -7,7 +7,7 @@ from contextlib import contextmanager import freezegun import pretend import pytest -from pip._vendor import lockfile +from pip._vendor import lockfile, pkg_resources from pip._internal.index import InstallationCandidate from pip._internal.utils import outdated @@ -33,6 +33,20 @@ class MockPackageFinder(object): return self.INSTALLATION_CANDIDATES +class MockDistribution(object): + def __init__(self, installer): + self.installer = installer + + def has_metadata(self, name): + return name == 'INSTALLER' + + def get_metadata_lines(self, name): + if self.has_metadata(name): + yield self.installer + else: + raise NotImplementedError('nope') + + def _options(): ''' Some default options that we pass to outdated.pip_version_check ''' return pretend.stub( @@ -47,20 +61,24 @@ def _options(): 'stored_time', 'installed_ver', 'new_ver', + 'installer', 'check_if_upgrade_required', 'check_warn_logs', ], [ # Test we return None when installed version is None - ('1970-01-01T10:00:00Z', None, '1.0', False, False), + ('1970-01-01T10:00:00Z', None, '1.0', 'pip', False, False), # Need an upgrade - upgrade warning should print - ('1970-01-01T10:00:00Z', '1.0', '6.9.0', True, True), + ('1970-01-01T10:00:00Z', '1.0', '6.9.0', 'pip', True, True), + # Upgrade available, pip installed via rpm - warning should not print + ('1970-01-01T10:00:00Z', '1.0', '6.9.0', 'rpm', True, False), # No upgrade - upgrade warning should not print - ('1970-01-9T10:00:00Z', '6.9.0', '6.9.0', False, False), + ('1970-01-9T10:00:00Z', '6.9.0', '6.9.0', 'pip', False, False), ] ) def test_pip_version_check(monkeypatch, stored_time, installed_ver, new_ver, - check_if_upgrade_required, check_warn_logs): + installer, check_if_upgrade_required, + check_warn_logs): monkeypatch.setattr(outdated, 'get_installed_version', lambda name: installed_ver) monkeypatch.setattr(outdated, 'PackageFinder', MockPackageFinder) @@ -68,6 +86,8 @@ def test_pip_version_check(monkeypatch, stored_time, installed_ver, new_ver, pretend.call_recorder(lambda *a, **kw: None)) monkeypatch.setattr(outdated.logger, 'debug', pretend.call_recorder(lambda s, exc_info=None: None)) + monkeypatch.setattr(pkg_resources, 'get_distribution', + lambda name: MockDistribution(installer)) fake_state = pretend.stub( state={"last_check": stored_time, 'pypi_version': installed_ver},