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