1import unittest 2import unittest.mock 3import test.support 4import os 5import os.path 6import contextlib 7import sys 8 9import ensurepip 10import ensurepip._uninstall 11 12 13class TestEnsurePipVersion(unittest.TestCase): 14 15 def test_returns_version(self): 16 self.assertEqual(ensurepip._PIP_VERSION, ensurepip.version()) 17 18class EnsurepipMixin: 19 20 def setUp(self): 21 run_pip_patch = unittest.mock.patch("ensurepip._run_pip") 22 self.run_pip = run_pip_patch.start() 23 self.addCleanup(run_pip_patch.stop) 24 25 # Avoid side effects on the actual os module 26 real_devnull = os.devnull 27 os_patch = unittest.mock.patch("ensurepip.os") 28 patched_os = os_patch.start() 29 self.addCleanup(os_patch.stop) 30 patched_os.devnull = real_devnull 31 patched_os.path = os.path 32 self.os_environ = patched_os.environ = os.environ.copy() 33 34 35class TestBootstrap(EnsurepipMixin, unittest.TestCase): 36 37 def test_basic_bootstrapping(self): 38 ensurepip.bootstrap() 39 40 self.run_pip.assert_called_once_with( 41 [ 42 "install", "--no-index", "--find-links", 43 unittest.mock.ANY, "setuptools", "pip", 44 ], 45 unittest.mock.ANY, 46 ) 47 48 additional_paths = self.run_pip.call_args[0][1] 49 self.assertEqual(len(additional_paths), 2) 50 51 def test_bootstrapping_with_root(self): 52 ensurepip.bootstrap(root="/foo/bar/") 53 54 self.run_pip.assert_called_once_with( 55 [ 56 "install", "--no-index", "--find-links", 57 unittest.mock.ANY, "--root", "/foo/bar/", 58 "setuptools", "pip", 59 ], 60 unittest.mock.ANY, 61 ) 62 63 def test_bootstrapping_with_user(self): 64 ensurepip.bootstrap(user=True) 65 66 self.run_pip.assert_called_once_with( 67 [ 68 "install", "--no-index", "--find-links", 69 unittest.mock.ANY, "--user", "setuptools", "pip", 70 ], 71 unittest.mock.ANY, 72 ) 73 74 def test_bootstrapping_with_upgrade(self): 75 ensurepip.bootstrap(upgrade=True) 76 77 self.run_pip.assert_called_once_with( 78 [ 79 "install", "--no-index", "--find-links", 80 unittest.mock.ANY, "--upgrade", "setuptools", "pip", 81 ], 82 unittest.mock.ANY, 83 ) 84 85 def test_bootstrapping_with_verbosity_1(self): 86 ensurepip.bootstrap(verbosity=1) 87 88 self.run_pip.assert_called_once_with( 89 [ 90 "install", "--no-index", "--find-links", 91 unittest.mock.ANY, "-v", "setuptools", "pip", 92 ], 93 unittest.mock.ANY, 94 ) 95 96 def test_bootstrapping_with_verbosity_2(self): 97 ensurepip.bootstrap(verbosity=2) 98 99 self.run_pip.assert_called_once_with( 100 [ 101 "install", "--no-index", "--find-links", 102 unittest.mock.ANY, "-vv", "setuptools", "pip", 103 ], 104 unittest.mock.ANY, 105 ) 106 107 def test_bootstrapping_with_verbosity_3(self): 108 ensurepip.bootstrap(verbosity=3) 109 110 self.run_pip.assert_called_once_with( 111 [ 112 "install", "--no-index", "--find-links", 113 unittest.mock.ANY, "-vvv", "setuptools", "pip", 114 ], 115 unittest.mock.ANY, 116 ) 117 118 def test_bootstrapping_with_regular_install(self): 119 ensurepip.bootstrap() 120 self.assertEqual(self.os_environ["ENSUREPIP_OPTIONS"], "install") 121 122 def test_bootstrapping_with_alt_install(self): 123 ensurepip.bootstrap(altinstall=True) 124 self.assertEqual(self.os_environ["ENSUREPIP_OPTIONS"], "altinstall") 125 126 def test_bootstrapping_with_default_pip(self): 127 ensurepip.bootstrap(default_pip=True) 128 self.assertNotIn("ENSUREPIP_OPTIONS", self.os_environ) 129 130 def test_altinstall_default_pip_conflict(self): 131 with self.assertRaises(ValueError): 132 ensurepip.bootstrap(altinstall=True, default_pip=True) 133 self.assertFalse(self.run_pip.called) 134 135 def test_pip_environment_variables_removed(self): 136 # ensurepip deliberately ignores all pip environment variables 137 # See http://bugs.python.org/issue19734 for details 138 self.os_environ["PIP_THIS_SHOULD_GO_AWAY"] = "test fodder" 139 ensurepip.bootstrap() 140 self.assertNotIn("PIP_THIS_SHOULD_GO_AWAY", self.os_environ) 141 142 def test_pip_config_file_disabled(self): 143 # ensurepip deliberately ignores the pip config file 144 # See http://bugs.python.org/issue20053 for details 145 ensurepip.bootstrap() 146 self.assertEqual(self.os_environ["PIP_CONFIG_FILE"], os.devnull) 147 148@contextlib.contextmanager 149def fake_pip(version=ensurepip._PIP_VERSION): 150 if version is None: 151 pip = None 152 else: 153 class FakePip(): 154 __version__ = version 155 pip = FakePip() 156 sentinel = object() 157 orig_pip = sys.modules.get("pip", sentinel) 158 sys.modules["pip"] = pip 159 try: 160 yield pip 161 finally: 162 if orig_pip is sentinel: 163 del sys.modules["pip"] 164 else: 165 sys.modules["pip"] = orig_pip 166 167class TestUninstall(EnsurepipMixin, unittest.TestCase): 168 169 def test_uninstall_skipped_when_not_installed(self): 170 with fake_pip(None): 171 ensurepip._uninstall_helper() 172 self.assertFalse(self.run_pip.called) 173 174 def test_uninstall_skipped_with_warning_for_wrong_version(self): 175 with fake_pip("not a valid version"): 176 with test.support.captured_stderr() as stderr: 177 ensurepip._uninstall_helper() 178 warning = stderr.getvalue().strip() 179 self.assertIn("only uninstall a matching version", warning) 180 self.assertFalse(self.run_pip.called) 181 182 183 def test_uninstall(self): 184 with fake_pip(): 185 ensurepip._uninstall_helper() 186 187 self.run_pip.assert_called_once_with( 188 [ 189 "uninstall", "-y", "--disable-pip-version-check", "pip", 190 "setuptools", 191 ] 192 ) 193 194 def test_uninstall_with_verbosity_1(self): 195 with fake_pip(): 196 ensurepip._uninstall_helper(verbosity=1) 197 198 self.run_pip.assert_called_once_with( 199 [ 200 "uninstall", "-y", "--disable-pip-version-check", "-v", "pip", 201 "setuptools", 202 ] 203 ) 204 205 def test_uninstall_with_verbosity_2(self): 206 with fake_pip(): 207 ensurepip._uninstall_helper(verbosity=2) 208 209 self.run_pip.assert_called_once_with( 210 [ 211 "uninstall", "-y", "--disable-pip-version-check", "-vv", "pip", 212 "setuptools", 213 ] 214 ) 215 216 def test_uninstall_with_verbosity_3(self): 217 with fake_pip(): 218 ensurepip._uninstall_helper(verbosity=3) 219 220 self.run_pip.assert_called_once_with( 221 [ 222 "uninstall", "-y", "--disable-pip-version-check", "-vvv", 223 "pip", "setuptools", 224 ] 225 ) 226 227 def test_pip_environment_variables_removed(self): 228 # ensurepip deliberately ignores all pip environment variables 229 # See http://bugs.python.org/issue19734 for details 230 self.os_environ["PIP_THIS_SHOULD_GO_AWAY"] = "test fodder" 231 with fake_pip(): 232 ensurepip._uninstall_helper() 233 self.assertNotIn("PIP_THIS_SHOULD_GO_AWAY", self.os_environ) 234 235 def test_pip_config_file_disabled(self): 236 # ensurepip deliberately ignores the pip config file 237 # See http://bugs.python.org/issue20053 for details 238 with fake_pip(): 239 ensurepip._uninstall_helper() 240 self.assertEqual(self.os_environ["PIP_CONFIG_FILE"], os.devnull) 241 242 243# Basic testing of the main functions and their argument parsing 244 245EXPECTED_VERSION_OUTPUT = "pip " + ensurepip._PIP_VERSION 246 247class TestBootstrappingMainFunction(EnsurepipMixin, unittest.TestCase): 248 249 def test_bootstrap_version(self): 250 with test.support.captured_stdout() as stdout: 251 with self.assertRaises(SystemExit): 252 ensurepip._main(["--version"]) 253 result = stdout.getvalue().strip() 254 self.assertEqual(result, EXPECTED_VERSION_OUTPUT) 255 self.assertFalse(self.run_pip.called) 256 257 def test_basic_bootstrapping(self): 258 ensurepip._main([]) 259 260 self.run_pip.assert_called_once_with( 261 [ 262 "install", "--no-index", "--find-links", 263 unittest.mock.ANY, "setuptools", "pip", 264 ], 265 unittest.mock.ANY, 266 ) 267 268 additional_paths = self.run_pip.call_args[0][1] 269 self.assertEqual(len(additional_paths), 2) 270 271class TestUninstallationMainFunction(EnsurepipMixin, unittest.TestCase): 272 273 def test_uninstall_version(self): 274 with test.support.captured_stdout() as stdout: 275 with self.assertRaises(SystemExit): 276 ensurepip._uninstall._main(["--version"]) 277 result = stdout.getvalue().strip() 278 self.assertEqual(result, EXPECTED_VERSION_OUTPUT) 279 self.assertFalse(self.run_pip.called) 280 281 def test_basic_uninstall(self): 282 with fake_pip(): 283 ensurepip._uninstall._main([]) 284 285 self.run_pip.assert_called_once_with( 286 [ 287 "uninstall", "-y", "--disable-pip-version-check", "pip", 288 "setuptools", 289 ] 290 ) 291 292 293 294if __name__ == "__main__": 295 unittest.main() 296