[2.7] bpo-31351: Set return code in ensurepip when pip fails (GH-3734)
Previously ensurepip would always report success, even if the
pip installation failed.
(cherry picked from commit 9adda0cdf8
)
This commit is contained in:
parent
da86874a3d
commit
cf7197ae43
|
@ -76,6 +76,9 @@ options:
|
|||
* ``--no-default-pip``: if a non-default installation is request, the ``pip``
|
||||
script will *not* be installed.
|
||||
|
||||
.. versionchanged:: 2.7.15
|
||||
The exit status is non-zero if the command fails.
|
||||
|
||||
|
||||
Module API
|
||||
----------
|
||||
|
|
|
@ -29,7 +29,7 @@ def _run_pip(args, additional_paths=None):
|
|||
|
||||
# Install the bundled software
|
||||
import pip
|
||||
pip.main(args)
|
||||
return pip.main(args)
|
||||
|
||||
|
||||
def version():
|
||||
|
@ -58,6 +58,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=True,
|
||||
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:
|
||||
|
@ -105,11 +120,10 @@ 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)
|
||||
finally:
|
||||
shutil.rmtree(tmpdir, ignore_errors=True)
|
||||
|
||||
|
||||
def _uninstall_helper(verbosity=0):
|
||||
"""Helper to support a clean default uninstall process on Windows
|
||||
|
||||
|
@ -135,7 +149,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):
|
||||
|
@ -196,7 +210,7 @@ def _main(argv=None):
|
|||
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
bootstrap(
|
||||
return _bootstrap(
|
||||
root=args.root,
|
||||
upgrade=args.upgrade,
|
||||
user=args.user,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import ensurepip
|
||||
import sys
|
||||
|
||||
if __name__ == "__main__":
|
||||
ensurepip._main()
|
||||
sys.exit(ensurepip._main())
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -21,6 +21,7 @@ class EnsurepipMixin:
|
|||
def setUp(self):
|
||||
run_pip_patch = 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
|
||||
|
@ -258,7 +259,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(
|
||||
[
|
||||
|
@ -270,6 +271,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):
|
||||
|
@ -284,7 +292,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(
|
||||
[
|
||||
|
@ -293,6 +301,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__":
|
||||
test.test_support.run_unittest(__name__)
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
python -m ensurepip now exits with non-zero exit code if pip bootstrapping
|
||||
has failed.
|
Loading…
Reference in New Issue