bpo-31351: Set return code in ensurepip when pip fails (GH-3626) (GH-3683)

Previously ensurepip would always report success, even if the
pip installation failed.
(cherry picked from commit 9adda0cdf8)

* Update version changed notice for backport
This commit is contained in:
Miss Islington (bot) 2017-09-22 06:45:37 -07:00 committed by Mariatta
parent 0c4997f191
commit eef49f5dd0
6 changed files with 46 additions and 9 deletions

View File

@ -78,6 +78,9 @@ options:
Providing both of the script selection options will trigger an exception.
.. versionchanged:: 3.6.3
The exit status is non-zero if the command fails.
Module API
----------

View File

@ -25,7 +25,7 @@ def _run_pip(args, additional_paths=None):
# Install the bundled software
import pip
pip.main(args)
return pip.main(args)
def version():
@ -53,6 +53,21 @@ def bootstrap(*, root=None, upgrade=False, user=False,
Bootstrap pip into the current Python installation (or the given root
directory).
Note that calling this function will alter both sys.path and os.environ.
"""
# Discard the return value
_bootstrap(root=root, upgrade=upgrade, user=user,
altinstall=altinstall, default_pip=default_pip,
verbosity=verbosity)
def _bootstrap(*, root=None, upgrade=False, user=False,
altinstall=False, default_pip=False,
verbosity=0):
"""
Bootstrap pip into the current Python installation (or the given root
directory). Returns pip command status code.
Note that calling this function will alter both sys.path and os.environ.
"""
if altinstall and default_pip:
@ -99,7 +114,7 @@ def bootstrap(*, root=None, upgrade=False, user=False,
if verbosity:
args += ["-" + "v" * verbosity]
_run_pip(args + [p[0] for p in _PROJECTS], additional_paths)
return _run_pip(args + [p[0] for p in _PROJECTS], additional_paths)
def _uninstall_helper(*, verbosity=0):
"""Helper to support a clean default uninstall process on Windows
@ -126,7 +141,7 @@ def _uninstall_helper(*, verbosity=0):
if verbosity:
args += ["-" + "v" * verbosity]
_run_pip(args + [p[0] for p in reversed(_PROJECTS)])
return _run_pip(args + [p[0] for p in reversed(_PROJECTS)])
def _main(argv=None):
@ -180,7 +195,7 @@ def _main(argv=None):
args = parser.parse_args(argv)
bootstrap(
return _bootstrap(
root=args.root,
upgrade=args.upgrade,
user=args.user,

View File

@ -1,4 +1,5 @@
import ensurepip
import sys
if __name__ == "__main__":
ensurepip._main()
sys.exit(ensurepip._main())

View File

@ -2,6 +2,7 @@
import argparse
import ensurepip
import sys
def _main(argv=None):
@ -23,8 +24,8 @@ def _main(argv=None):
args = parser.parse_args(argv)
ensurepip._uninstall_helper(verbosity=args.verbosity)
return ensurepip._uninstall_helper(verbosity=args.verbosity)
if __name__ == "__main__":
_main()
sys.exit(_main())

View File

@ -20,6 +20,7 @@ class EnsurepipMixin:
def setUp(self):
run_pip_patch = unittest.mock.patch("ensurepip._run_pip")
self.run_pip = run_pip_patch.start()
self.run_pip.return_value = 0
self.addCleanup(run_pip_patch.stop)
# Avoid side effects on the actual os module
@ -255,7 +256,7 @@ class TestBootstrappingMainFunction(EnsurepipMixin, unittest.TestCase):
self.assertFalse(self.run_pip.called)
def test_basic_bootstrapping(self):
ensurepip._main([])
exit_code = ensurepip._main([])
self.run_pip.assert_called_once_with(
[
@ -267,6 +268,13 @@ class TestBootstrappingMainFunction(EnsurepipMixin, unittest.TestCase):
additional_paths = self.run_pip.call_args[0][1]
self.assertEqual(len(additional_paths), 2)
self.assertEqual(exit_code, 0)
def test_bootstrapping_error_code(self):
self.run_pip.return_value = 2
exit_code = ensurepip._main([])
self.assertEqual(exit_code, 2)
class TestUninstallationMainFunction(EnsurepipMixin, unittest.TestCase):
@ -280,7 +288,7 @@ class TestUninstallationMainFunction(EnsurepipMixin, unittest.TestCase):
def test_basic_uninstall(self):
with fake_pip():
ensurepip._uninstall._main([])
exit_code = ensurepip._uninstall._main([])
self.run_pip.assert_called_once_with(
[
@ -289,6 +297,13 @@ class TestUninstallationMainFunction(EnsurepipMixin, unittest.TestCase):
]
)
self.assertEqual(exit_code, 0)
def test_uninstall_error_code(self):
with fake_pip():
self.run_pip.return_value = 2
exit_code = ensurepip._uninstall._main([])
self.assertEqual(exit_code, 2)
if __name__ == "__main__":

View File

@ -0,0 +1,2 @@
python -m ensurepip now exits with non-zero exit code if pip bootstrapping
has failed.