[Python-checkins] [2.7] bpo-31351: Set return code in ensurepip when pip fails (GH-3734)

Nick Coghlan webhook-mailer at python.org
Sun Sep 24 21:03:27 EDT 2017


https://github.com/python/cpython/commit/cf7197ae43767c4346864e5b41246f628edd9b51
commit: cf7197ae43767c4346864e5b41246f628edd9b51
branch: 2.7
author: Igor Filatov <iafilatov at users.noreply.github.com>
committer: Nick Coghlan <ncoghlan at gmail.com>
date: 2017年09月25日T11:03:24+10:00
summary:
[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 9adda0cdf89432386b7a04444a6199b580d287a1)
files:
A Misc/NEWS.d/next/Library/2017-09-17-15-24-25.bpo-31351.yQdKv-.rst
M Doc/library/ensurepip.rst
M Lib/ensurepip/__init__.py
M Lib/ensurepip/__main__.py
M Lib/ensurepip/_uninstall.py
M Lib/test/test_ensurepip.py
diff --git a/Doc/library/ensurepip.rst b/Doc/library/ensurepip.rst
index a6358e44b15..b6f7120947c 100644
--- a/Doc/library/ensurepip.rst
+++ b/Doc/library/ensurepip.rst
@@ -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
 ----------
diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py
index c2abed84ef0..ea2a5e63482 100644
--- a/Lib/ensurepip/__init__.py
+++ b/Lib/ensurepip/__init__.py
@@ -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():
@@ -60,6 +60,21 @@ def bootstrap(root=None, upgrade=False, user=False,
 
 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:
 raise ValueError("Cannot use altinstall and default_pip together")
 
@@ -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,
diff --git a/Lib/ensurepip/__main__.py b/Lib/ensurepip/__main__.py
index 77527d7a351..03eef0dd94d 100644
--- a/Lib/ensurepip/__main__.py
+++ b/Lib/ensurepip/__main__.py
@@ -1,4 +1,5 @@
 import ensurepip
+import sys
 
 if __name__ == "__main__":
- ensurepip._main()
+ sys.exit(ensurepip._main())
diff --git a/Lib/ensurepip/_uninstall.py b/Lib/ensurepip/_uninstall.py
index 750365ec4d0..b257904328d 100644
--- a/Lib/ensurepip/_uninstall.py
+++ b/Lib/ensurepip/_uninstall.py
@@ -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())
diff --git a/Lib/test/test_ensurepip.py b/Lib/test/test_ensurepip.py
index 3316fcfaa16..cb9d10a1049 100644
--- a/Lib/test/test_ensurepip.py
+++ b/Lib/test/test_ensurepip.py
@@ -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 @@ def test_bootstrap_version(self):
 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 @@ def test_basic_bootstrapping(self):
 
 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 @@ def test_uninstall_version(self):
 
 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 @@ def test_basic_uninstall(self):
 ]
 )
 
+ 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__)
diff --git a/Misc/NEWS.d/next/Library/2017-09-17-15-24-25.bpo-31351.yQdKv-.rst b/Misc/NEWS.d/next/Library/2017-09-17-15-24-25.bpo-31351.yQdKv-.rst
new file mode 100644
index 00000000000..20f2c1bdc11
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2017-09-17-15-24-25.bpo-31351.yQdKv-.rst
@@ -0,0 +1,2 @@
+python -m ensurepip now exits with non-zero exit code if pip bootstrapping
+has failed.


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /