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