From 00166c3999af8afa9b991da91e4756961580816e Mon Sep 17 00:00:00 2001 From: Shardul D Date: Tue, 8 Sep 2026 09:17:44 +0530 Subject: [PATCH 1/2] gh-131178: Add tests for `ensurepip` command-line interface The documented options of ``python -m ensurepip`` (--upgrade, --user, --root, --altinstall, --default-pip, --verbose) were only tested through bootstrap(), not through the command line. Drive each one through _main() with pip mocked, including the altinstall/default-pip conflict, --help and an unknown option. --- Lib/test/test_ensurepip.py | 109 ++++++++++++++++++ ...-09-08-02-05-00.gh-issue-131178.siIaKc.rst | 1 + 2 files changed, 110 insertions(+) create mode 100644 Misc/NEWS.d/next/Tests/2026-09-08-02-05-00.gh-issue-131178.siIaKc.rst diff --git a/Lib/test/test_ensurepip.py b/Lib/test/test_ensurepip.py index 20a56ed715d8abd..0331df1d24d416a 100644 --- a/Lib/test/test_ensurepip.py +++ b/Lib/test/test_ensurepip.py @@ -342,6 +342,115 @@ def test_bootstrapping_error_code(self): exit_code = ensurepip._main([]) self.assertEqual(exit_code, 2) + def test_bootstrapping_with_root(self): + exit_code = ensurepip._main(["--root", "/foo/bar/"]) + + self.run_pip.assert_called_once_with( + [ + "install", "--no-cache-dir", "--no-index", "--find-links", + unittest.mock.ANY, "--root", "/foo/bar/", *COMPILE_OPT, + "pip", + ], + unittest.mock.ANY, + ) + self.assertEqual(exit_code, 0) + + def test_bootstrapping_with_user(self): + ensurepip._main(["--user"]) + + self.run_pip.assert_called_once_with( + [ + "install", "--no-cache-dir", "--no-index", "--find-links", + unittest.mock.ANY, "--user", *COMPILE_OPT, "pip", + ], + unittest.mock.ANY, + ) + + def test_bootstrapping_with_upgrade(self): + for option in ("--upgrade", "-U"): + with self.subTest(option=option): + self.run_pip.reset_mock() + ensurepip._main([option]) + + self.run_pip.assert_called_once_with( + [ + "install", "--no-cache-dir", "--no-index", + "--find-links", unittest.mock.ANY, "--upgrade", + *COMPILE_OPT, "pip", + ], + unittest.mock.ANY, + ) + + def test_bootstrapping_with_verbosity(self): + for argv, expected in ( + (["-v"], "-v"), + (["--verbose"], "-v"), + (["-vv"], "-vv"), + (["-v", "-v", "-v"], "-vvv"), + ): + with self.subTest(argv=argv): + self.run_pip.reset_mock() + ensurepip._main(argv) + + self.run_pip.assert_called_once_with( + [ + "install", "--no-cache-dir", "--no-index", + "--find-links", unittest.mock.ANY, expected, + *COMPILE_OPT, "pip", + ], + unittest.mock.ANY, + ) + + def test_bootstrapping_with_altinstall(self): + ensurepip._main(["--altinstall"]) + self.assertEqual(self.os_environ["ENSUREPIP_OPTIONS"], "altinstall") + + def test_bootstrapping_with_default_pip(self): + ensurepip._main(["--default-pip"]) + self.assertNotIn("ENSUREPIP_OPTIONS", self.os_environ) + + def test_altinstall_default_pip_conflict(self): + with self.assertRaises(ValueError): + ensurepip._main(["--altinstall", "--default-pip"]) + self.assertFalse(self.run_pip.called) + + def test_bootstrapping_with_all_options(self): + # The order of the options on the command line doesn't matter. + exit_code = ensurepip._main([ + "-v", "--user", "--upgrade", "--root", "/foo/bar/", + "--altinstall", "-v", + ]) + + self.run_pip.assert_called_once_with( + [ + "install", "--no-cache-dir", "--no-index", "--find-links", + unittest.mock.ANY, "--root", "/foo/bar/", "--upgrade", + "--user", "-vv", *COMPILE_OPT, "pip", + ], + unittest.mock.ANY, + ) + self.assertEqual(self.os_environ["ENSUREPIP_OPTIONS"], "altinstall") + self.assertEqual(exit_code, 0) + + def test_help(self): + with test.support.captured_stdout() as stdout: + with self.assertRaises(SystemExit) as cm: + ensurepip._main(["--help"]) + self.assertEqual(cm.exception.code, 0) + help_text = stdout.getvalue() + for option in ("--version", "--verbose", "--upgrade", "--user", + "--root", "--altinstall", "--default-pip"): + self.assertIn(option, help_text) + self.assertFalse(self.run_pip.called) + + def test_unknown_option(self): + with test.support.captured_stderr() as stderr: + with self.assertRaises(SystemExit) as cm: + ensurepip._main(["--unknown"]) + self.assertEqual(cm.exception.code, 2) + self.assertIn("unrecognized arguments: --unknown", stderr.getvalue()) + self.assertFalse(self.run_pip.called) + class TestUninstallationMainFunction(EnsurepipMixin, unittest.TestCase): diff --git a/Misc/NEWS.d/next/Tests/2026-09-08-02-05-00.gh-issue-131178.siIaKc.rst b/Misc/NEWS.d/next/Tests/2026-09-08-02-05-00.gh-issue-131178.siIaKc.rst new file mode 100644 index 000000000000000..7552e7c11992fe8 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2026-09-08-02-05-00.gh-issue-131178.siIaKc.rst @@ -0,0 +1 @@ +Add tests for the :mod:`ensurepip` command-line interface. From 2b8f3af8fbf3ca29f3d1335c52b5b9477dde272d Mon Sep 17 00:00:00 2001 From: Shardul D Date: Wed, 9 Sep 2026 14:04:00 +0530 Subject: [PATCH 2/2] Remove the NEWS entry --- .../next/Tests/2026-09-08-02-05-00.gh-issue-131178.siIaKc.rst | 1 - 1 file changed, 1 deletion(-) delete mode 100644 Misc/NEWS.d/next/Tests/2026-09-08-02-05-00.gh-issue-131178.siIaKc.rst diff --git a/Misc/NEWS.d/next/Tests/2026-09-08-02-05-00.gh-issue-131178.siIaKc.rst b/Misc/NEWS.d/next/Tests/2026-09-08-02-05-00.gh-issue-131178.siIaKc.rst deleted file mode 100644 index 7552e7c11992fe8..000000000000000 --- a/Misc/NEWS.d/next/Tests/2026-09-08-02-05-00.gh-issue-131178.siIaKc.rst +++ /dev/null @@ -1 +0,0 @@ -Add tests for the :mod:`ensurepip` command-line interface.