Mercurial > repos > guerler > hhblits
comparison lib/python3.8/site-packages/pip/_internal/commands/install.py @ 0:9e54283cc701 draft
"planemo upload commit d12c32a45bcd441307e632fca6d9af7d60289d44"
| author | guerler |
|---|---|
| date | Mon, 27 Jul 2020 03:47:31 -0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:9e54283cc701 |
|---|---|
| 1 # The following comment should be removed at some point in the future. | |
| 2 # It's included for now because without it InstallCommand.run() has a | |
| 3 # couple errors where we have to know req.name is str rather than | |
| 4 # Optional[str] for the InstallRequirement req. | |
| 5 # mypy: strict-optional=False | |
| 6 # mypy: disallow-untyped-defs=False | |
| 7 | |
| 8 from __future__ import absolute_import | |
| 9 | |
| 10 import errno | |
| 11 import logging | |
| 12 import operator | |
| 13 import os | |
| 14 import shutil | |
| 15 import site | |
| 16 from optparse import SUPPRESS_HELP | |
| 17 | |
| 18 from pip._vendor import pkg_resources | |
| 19 from pip._vendor.packaging.utils import canonicalize_name | |
| 20 | |
| 21 from pip._internal.cache import WheelCache | |
| 22 from pip._internal.cli import cmdoptions | |
| 23 from pip._internal.cli.cmdoptions import make_target_python | |
| 24 from pip._internal.cli.req_command import RequirementCommand | |
| 25 from pip._internal.cli.status_codes import ERROR, SUCCESS | |
| 26 from pip._internal.exceptions import ( | |
| 27 CommandError, | |
| 28 InstallationError, | |
| 29 PreviousBuildDirError, | |
| 30 ) | |
| 31 from pip._internal.locations import distutils_scheme | |
| 32 from pip._internal.operations.check import check_install_conflicts | |
| 33 from pip._internal.req import RequirementSet, install_given_reqs | |
| 34 from pip._internal.req.req_tracker import get_requirement_tracker | |
| 35 from pip._internal.utils.deprecation import deprecated | |
| 36 from pip._internal.utils.distutils_args import parse_distutils_args | |
| 37 from pip._internal.utils.filesystem import test_writable_dir | |
| 38 from pip._internal.utils.misc import ( | |
| 39 ensure_dir, | |
| 40 get_installed_version, | |
| 41 protect_pip_from_modification_on_windows, | |
| 42 write_output, | |
| 43 ) | |
| 44 from pip._internal.utils.temp_dir import TempDirectory | |
| 45 from pip._internal.utils.typing import MYPY_CHECK_RUNNING | |
| 46 from pip._internal.utils.virtualenv import virtualenv_no_global | |
| 47 from pip._internal.wheel_builder import build, should_build_for_install_command | |
| 48 | |
| 49 if MYPY_CHECK_RUNNING: | |
| 50 from optparse import Values | |
| 51 from typing import Any, Iterable, List, Optional | |
| 52 | |
| 53 from pip._internal.models.format_control import FormatControl | |
| 54 from pip._internal.req.req_install import InstallRequirement | |
| 55 from pip._internal.wheel_builder import BinaryAllowedPredicate | |
| 56 | |
| 57 | |
| 58 logger = logging.getLogger(__name__) | |
| 59 | |
| 60 | |
| 61 def get_check_binary_allowed(format_control): | |
| 62 # type: (FormatControl) -> BinaryAllowedPredicate | |
| 63 def check_binary_allowed(req): | |
| 64 # type: (InstallRequirement) -> bool | |
| 65 if req.use_pep517: | |
| 66 return True | |
| 67 canonical_name = canonicalize_name(req.name) | |
| 68 allowed_formats = format_control.get_allowed_formats(canonical_name) | |
| 69 return "binary" in allowed_formats | |
| 70 | |
| 71 return check_binary_allowed | |
| 72 | |
| 73 | |
| 74 class InstallCommand(RequirementCommand): | |
| 75 """ | |
| 76 Install packages from: | |
| 77 | |
| 78 - PyPI (and other indexes) using requirement specifiers. | |
| 79 - VCS project urls. | |
| 80 - Local project directories. | |
| 81 - Local or remote source archives. | |
| 82 | |
| 83 pip also supports installing from "requirements files", which provide | |
| 84 an easy way to specify a whole environment to be installed. | |
| 85 """ | |
| 86 | |
| 87 usage = """ | |
| 88 %prog [options] <requirement specifier> [package-index-options] ... | |
| 89 %prog [options] -r <requirements file> [package-index-options] ... | |
| 90 %prog [options] [-e] <vcs project url> ... | |
| 91 %prog [options] [-e] <local project path> ... | |
| 92 %prog [options] <archive url/path> ...""" | |
| 93 | |
| 94 def __init__(self, *args, **kw): | |
| 95 super(InstallCommand, self).__init__(*args, **kw) | |
| 96 | |
| 97 cmd_opts = self.cmd_opts | |
| 98 | |
| 99 cmd_opts.add_option(cmdoptions.requirements()) | |
| 100 cmd_opts.add_option(cmdoptions.constraints()) | |
| 101 cmd_opts.add_option(cmdoptions.no_deps()) | |
| 102 cmd_opts.add_option(cmdoptions.pre()) | |
| 103 | |
| 104 cmd_opts.add_option(cmdoptions.editable()) | |
| 105 cmd_opts.add_option( | |
| 106 '-t', '--target', | |
| 107 dest='target_dir', | |
| 108 metavar='dir', | |
| 109 default=None, | |
| 110 help='Install packages into <dir>. ' | |
| 111 'By default this will not replace existing files/folders in ' | |
| 112 '<dir>. Use --upgrade to replace existing packages in <dir> ' | |
| 113 'with new versions.' | |
| 114 ) | |
| 115 cmdoptions.add_target_python_options(cmd_opts) | |
| 116 | |
| 117 cmd_opts.add_option( | |
| 118 '--user', | |
| 119 dest='use_user_site', | |
| 120 action='store_true', | |
| 121 help="Install to the Python user install directory for your " | |
| 122 "platform. Typically ~/.local/, or %APPDATA%\\Python on " | |
| 123 "Windows. (See the Python documentation for site.USER_BASE " | |
| 124 "for full details.)") | |
| 125 cmd_opts.add_option( | |
| 126 '--no-user', | |
| 127 dest='use_user_site', | |
| 128 action='store_false', | |
| 129 help=SUPPRESS_HELP) | |
| 130 cmd_opts.add_option( | |
| 131 '--root', | |
| 132 dest='root_path', | |
| 133 metavar='dir', | |
| 134 default=None, | |
| 135 help="Install everything relative to this alternate root " | |
| 136 "directory.") | |
| 137 cmd_opts.add_option( | |
| 138 '--prefix', | |
| 139 dest='prefix_path', | |
| 140 metavar='dir', | |
| 141 default=None, | |
| 142 help="Installation prefix where lib, bin and other top-level " | |
| 143 "folders are placed") | |
| 144 | |
| 145 cmd_opts.add_option(cmdoptions.build_dir()) | |
| 146 | |
| 147 cmd_opts.add_option(cmdoptions.src()) | |
| 148 | |
| 149 cmd_opts.add_option( | |
| 150 '-U', '--upgrade', | |
| 151 dest='upgrade', | |
| 152 action='store_true', | |
| 153 help='Upgrade all specified packages to the newest available ' | |
| 154 'version. The handling of dependencies depends on the ' | |
| 155 'upgrade-strategy used.' | |
| 156 ) | |
| 157 | |
| 158 cmd_opts.add_option( | |
| 159 '--upgrade-strategy', | |
| 160 dest='upgrade_strategy', | |
| 161 default='only-if-needed', | |
| 162 choices=['only-if-needed', 'eager'], | |
| 163 help='Determines how dependency upgrading should be handled ' | |
| 164 '[default: %default]. ' | |
| 165 '"eager" - dependencies are upgraded regardless of ' | |
| 166 'whether the currently installed version satisfies the ' | |
| 167 'requirements of the upgraded package(s). ' | |
| 168 '"only-if-needed" - are upgraded only when they do not ' | |
| 169 'satisfy the requirements of the upgraded package(s).' | |
| 170 ) | |
| 171 | |
| 172 cmd_opts.add_option( | |
| 173 '--force-reinstall', | |
| 174 dest='force_reinstall', | |
| 175 action='store_true', | |
| 176 help='Reinstall all packages even if they are already ' | |
| 177 'up-to-date.') | |
| 178 | |
| 179 cmd_opts.add_option( | |
| 180 '-I', '--ignore-installed', | |
| 181 dest='ignore_installed', | |
| 182 action='store_true', | |
| 183 help='Ignore the installed packages, overwriting them. ' | |
| 184 'This can break your system if the existing package ' | |
| 185 'is of a different version or was installed ' | |
| 186 'with a different package manager!' | |
| 187 ) | |
| 188 | |
| 189 cmd_opts.add_option(cmdoptions.ignore_requires_python()) | |
| 190 cmd_opts.add_option(cmdoptions.no_build_isolation()) | |
| 191 cmd_opts.add_option(cmdoptions.use_pep517()) | |
| 192 cmd_opts.add_option(cmdoptions.no_use_pep517()) | |
| 193 | |
| 194 cmd_opts.add_option(cmdoptions.install_options()) | |
| 195 cmd_opts.add_option(cmdoptions.global_options()) | |
| 196 | |
| 197 cmd_opts.add_option( | |
| 198 "--compile", | |
| 199 action="store_true", | |
| 200 dest="compile", | |
| 201 default=True, | |
| 202 help="Compile Python source files to bytecode", | |
| 203 ) | |
| 204 | |
| 205 cmd_opts.add_option( | |
| 206 "--no-compile", | |
| 207 action="store_false", | |
| 208 dest="compile", | |
| 209 help="Do not compile Python source files to bytecode", | |
| 210 ) | |
| 211 | |
| 212 cmd_opts.add_option( | |
| 213 "--no-warn-script-location", | |
| 214 action="store_false", | |
| 215 dest="warn_script_location", | |
| 216 default=True, | |
| 217 help="Do not warn when installing scripts outside PATH", | |
| 218 ) | |
| 219 cmd_opts.add_option( | |
| 220 "--no-warn-conflicts", | |
| 221 action="store_false", | |
| 222 dest="warn_about_conflicts", | |
| 223 default=True, | |
| 224 help="Do not warn about broken dependencies", | |
| 225 ) | |
| 226 | |
| 227 cmd_opts.add_option(cmdoptions.no_binary()) | |
| 228 cmd_opts.add_option(cmdoptions.only_binary()) | |
| 229 cmd_opts.add_option(cmdoptions.prefer_binary()) | |
| 230 cmd_opts.add_option(cmdoptions.no_clean()) | |
| 231 cmd_opts.add_option(cmdoptions.require_hashes()) | |
| 232 cmd_opts.add_option(cmdoptions.progress_bar()) | |
| 233 | |
| 234 index_opts = cmdoptions.make_option_group( | |
| 235 cmdoptions.index_group, | |
| 236 self.parser, | |
| 237 ) | |
| 238 | |
| 239 self.parser.insert_option_group(0, index_opts) | |
| 240 self.parser.insert_option_group(0, cmd_opts) | |
| 241 | |
| 242 def run(self, options, args): | |
| 243 # type: (Values, List[Any]) -> int | |
| 244 cmdoptions.check_install_build_global(options) | |
| 245 upgrade_strategy = "to-satisfy-only" | |
| 246 if options.upgrade: | |
| 247 upgrade_strategy = options.upgrade_strategy | |
| 248 | |
| 249 cmdoptions.check_dist_restriction(options, check_target=True) | |
| 250 | |
| 251 install_options = options.install_options or [] | |
| 252 | |
| 253 options.use_user_site = decide_user_install( | |
| 254 options.use_user_site, | |
| 255 prefix_path=options.prefix_path, | |
| 256 target_dir=options.target_dir, | |
| 257 root_path=options.root_path, | |
| 258 isolated_mode=options.isolated_mode, | |
| 259 ) | |
| 260 | |
| 261 target_temp_dir = None # type: Optional[TempDirectory] | |
| 262 target_temp_dir_path = None # type: Optional[str] | |
| 263 if options.target_dir: | |
| 264 options.ignore_installed = True | |
| 265 options.target_dir = os.path.abspath(options.target_dir) | |
| 266 if (os.path.exists(options.target_dir) and not | |
| 267 os.path.isdir(options.target_dir)): | |
| 268 raise CommandError( | |
| 269 "Target path exists but is not a directory, will not " | |
| 270 "continue." | |
| 271 ) | |
| 272 | |
| 273 # Create a target directory for using with the target option | |
| 274 target_temp_dir = TempDirectory(kind="target") | |
| 275 target_temp_dir_path = target_temp_dir.path | |
| 276 | |
| 277 global_options = options.global_options or [] | |
| 278 | |
| 279 session = self.get_default_session(options) | |
| 280 | |
| 281 target_python = make_target_python(options) | |
| 282 finder = self._build_package_finder( | |
| 283 options=options, | |
| 284 session=session, | |
| 285 target_python=target_python, | |
| 286 ignore_requires_python=options.ignore_requires_python, | |
| 287 ) | |
| 288 build_delete = (not (options.no_clean or options.build_dir)) | |
| 289 wheel_cache = WheelCache(options.cache_dir, options.format_control) | |
| 290 | |
| 291 with get_requirement_tracker() as req_tracker, TempDirectory( | |
| 292 options.build_dir, delete=build_delete, kind="install" | |
| 293 ) as directory: | |
| 294 requirement_set = RequirementSet( | |
| 295 check_supported_wheels=not options.target_dir, | |
| 296 ) | |
| 297 | |
| 298 try: | |
| 299 self.populate_requirement_set( | |
| 300 requirement_set, args, options, finder, session, | |
| 301 wheel_cache | |
| 302 ) | |
| 303 | |
| 304 warn_deprecated_install_options( | |
| 305 requirement_set, options.install_options | |
| 306 ) | |
| 307 | |
| 308 preparer = self.make_requirement_preparer( | |
| 309 temp_build_dir=directory, | |
| 310 options=options, | |
| 311 req_tracker=req_tracker, | |
| 312 session=session, | |
| 313 finder=finder, | |
| 314 use_user_site=options.use_user_site, | |
| 315 ) | |
| 316 resolver = self.make_resolver( | |
| 317 preparer=preparer, | |
| 318 finder=finder, | |
| 319 options=options, | |
| 320 wheel_cache=wheel_cache, | |
| 321 use_user_site=options.use_user_site, | |
| 322 ignore_installed=options.ignore_installed, | |
| 323 ignore_requires_python=options.ignore_requires_python, | |
| 324 force_reinstall=options.force_reinstall, | |
| 325 upgrade_strategy=upgrade_strategy, | |
| 326 use_pep517=options.use_pep517, | |
| 327 ) | |
| 328 | |
| 329 self.trace_basic_info(finder) | |
| 330 | |
| 331 resolver.resolve(requirement_set) | |
| 332 | |
| 333 try: | |
| 334 pip_req = requirement_set.get_requirement("pip") | |
| 335 except KeyError: | |
| 336 modifying_pip = None | |
| 337 else: | |
| 338 # If we're not replacing an already installed pip, | |
| 339 # we're not modifying it. | |
| 340 modifying_pip = pip_req.satisfied_by is None | |
| 341 protect_pip_from_modification_on_windows( | |
| 342 modifying_pip=modifying_pip | |
| 343 ) | |
| 344 | |
| 345 check_binary_allowed = get_check_binary_allowed( | |
| 346 finder.format_control | |
| 347 ) | |
| 348 | |
| 349 reqs_to_build = [ | |
| 350 r for r in requirement_set.requirements.values() | |
| 351 if should_build_for_install_command( | |
| 352 r, check_binary_allowed | |
| 353 ) | |
| 354 ] | |
| 355 | |
| 356 _, build_failures = build( | |
| 357 reqs_to_build, | |
| 358 wheel_cache=wheel_cache, | |
| 359 build_options=[], | |
| 360 global_options=[], | |
| 361 ) | |
| 362 | |
| 363 # If we're using PEP 517, we cannot do a direct install | |
| 364 # so we fail here. | |
| 365 # We don't care about failures building legacy | |
| 366 # requirements, as we'll fall through to a direct | |
| 367 # install for those. | |
| 368 pep517_build_failures = [ | |
| 369 r for r in build_failures if r.use_pep517 | |
| 370 ] | |
| 371 if pep517_build_failures: | |
| 372 raise InstallationError( | |
| 373 "Could not build wheels for {} which use" | |
| 374 " PEP 517 and cannot be installed directly".format( | |
| 375 ", ".join(r.name for r in pep517_build_failures))) | |
| 376 | |
| 377 to_install = resolver.get_installation_order( | |
| 378 requirement_set | |
| 379 ) | |
| 380 | |
| 381 # Consistency Checking of the package set we're installing. | |
| 382 should_warn_about_conflicts = ( | |
| 383 not options.ignore_dependencies and | |
| 384 options.warn_about_conflicts | |
| 385 ) | |
| 386 if should_warn_about_conflicts: | |
| 387 self._warn_about_conflicts(to_install) | |
| 388 | |
| 389 # Don't warn about script install locations if | |
| 390 # --target has been specified | |
| 391 warn_script_location = options.warn_script_location | |
| 392 if options.target_dir: | |
| 393 warn_script_location = False | |
| 394 | |
| 395 installed = install_given_reqs( | |
| 396 to_install, | |
| 397 install_options, | |
| 398 global_options, | |
| 399 root=options.root_path, | |
| 400 home=target_temp_dir_path, | |
| 401 prefix=options.prefix_path, | |
| 402 pycompile=options.compile, | |
| 403 warn_script_location=warn_script_location, | |
| 404 use_user_site=options.use_user_site, | |
| 405 ) | |
| 406 | |
| 407 lib_locations = get_lib_location_guesses( | |
| 408 user=options.use_user_site, | |
| 409 home=target_temp_dir_path, | |
| 410 root=options.root_path, | |
| 411 prefix=options.prefix_path, | |
| 412 isolated=options.isolated_mode, | |
| 413 ) | |
| 414 working_set = pkg_resources.WorkingSet(lib_locations) | |
| 415 | |
| 416 installed.sort(key=operator.attrgetter('name')) | |
| 417 items = [] | |
| 418 for result in installed: | |
| 419 item = result.name | |
| 420 try: | |
| 421 installed_version = get_installed_version( | |
| 422 result.name, working_set=working_set | |
| 423 ) | |
| 424 if installed_version: | |
| 425 item += '-' + installed_version | |
| 426 except Exception: | |
| 427 pass | |
| 428 items.append(item) | |
| 429 installed_desc = ' '.join(items) | |
| 430 if installed_desc: | |
| 431 write_output( | |
| 432 'Successfully installed %s', installed_desc, | |
| 433 ) | |
| 434 except EnvironmentError as error: | |
| 435 show_traceback = (self.verbosity >= 1) | |
| 436 | |
| 437 message = create_env_error_message( | |
| 438 error, show_traceback, options.use_user_site, | |
| 439 ) | |
| 440 logger.error(message, exc_info=show_traceback) | |
| 441 | |
| 442 return ERROR | |
| 443 except PreviousBuildDirError: | |
| 444 options.no_clean = True | |
| 445 raise | |
| 446 finally: | |
| 447 # Clean up | |
| 448 if not options.no_clean: | |
| 449 requirement_set.cleanup_files() | |
| 450 wheel_cache.cleanup() | |
| 451 | |
| 452 if options.target_dir: | |
| 453 self._handle_target_dir( | |
| 454 options.target_dir, target_temp_dir, options.upgrade | |
| 455 ) | |
| 456 | |
| 457 return SUCCESS | |
| 458 | |
| 459 def _handle_target_dir(self, target_dir, target_temp_dir, upgrade): | |
| 460 ensure_dir(target_dir) | |
| 461 | |
| 462 # Checking both purelib and platlib directories for installed | |
| 463 # packages to be moved to target directory | |
| 464 lib_dir_list = [] | |
| 465 | |
| 466 with target_temp_dir: | |
| 467 # Checking both purelib and platlib directories for installed | |
| 468 # packages to be moved to target directory | |
| 469 scheme = distutils_scheme('', home=target_temp_dir.path) | |
| 470 purelib_dir = scheme['purelib'] | |
| 471 platlib_dir = scheme['platlib'] | |
| 472 data_dir = scheme['data'] | |
| 473 | |
| 474 if os.path.exists(purelib_dir): | |
| 475 lib_dir_list.append(purelib_dir) | |
| 476 if os.path.exists(platlib_dir) and platlib_dir != purelib_dir: | |
| 477 lib_dir_list.append(platlib_dir) | |
| 478 if os.path.exists(data_dir): | |
| 479 lib_dir_list.append(data_dir) | |
| 480 | |
| 481 for lib_dir in lib_dir_list: | |
| 482 for item in os.listdir(lib_dir): | |
| 483 if lib_dir == data_dir: | |
| 484 ddir = os.path.join(data_dir, item) | |
| 485 if any(s.startswith(ddir) for s in lib_dir_list[:-1]): | |
| 486 continue | |
| 487 target_item_dir = os.path.join(target_dir, item) | |
| 488 if os.path.exists(target_item_dir): | |
| 489 if not upgrade: | |
| 490 logger.warning( | |
| 491 'Target directory %s already exists. Specify ' | |
| 492 '--upgrade to force replacement.', | |
| 493 target_item_dir | |
| 494 ) | |
| 495 continue | |
| 496 if os.path.islink(target_item_dir): | |
| 497 logger.warning( | |
| 498 'Target directory %s already exists and is ' | |
| 499 'a link. Pip will not automatically replace ' | |
| 500 'links, please remove if replacement is ' | |
| 501 'desired.', | |
| 502 target_item_dir | |
| 503 ) | |
| 504 continue | |
| 505 if os.path.isdir(target_item_dir): | |
| 506 shutil.rmtree(target_item_dir) | |
| 507 else: | |
| 508 os.remove(target_item_dir) | |
| 509 | |
| 510 shutil.move( | |
| 511 os.path.join(lib_dir, item), | |
| 512 target_item_dir | |
| 513 ) | |
| 514 | |
| 515 def _warn_about_conflicts(self, to_install): | |
| 516 try: | |
| 517 package_set, _dep_info = check_install_conflicts(to_install) | |
| 518 except Exception: | |
| 519 logger.error("Error checking for conflicts.", exc_info=True) | |
| 520 return | |
| 521 missing, conflicting = _dep_info | |
| 522 | |
| 523 # NOTE: There is some duplication here from pip check | |
| 524 for project_name in missing: | |
| 525 version = package_set[project_name][0] | |
| 526 for dependency in missing[project_name]: | |
| 527 logger.critical( | |
| 528 "%s %s requires %s, which is not installed.", | |
| 529 project_name, version, dependency[1], | |
| 530 ) | |
| 531 | |
| 532 for project_name in conflicting: | |
| 533 version = package_set[project_name][0] | |
| 534 for dep_name, dep_version, req in conflicting[project_name]: | |
| 535 logger.critical( | |
| 536 "%s %s has requirement %s, but you'll have %s %s which is " | |
| 537 "incompatible.", | |
| 538 project_name, version, req, dep_name, dep_version, | |
| 539 ) | |
| 540 | |
| 541 | |
| 542 def get_lib_location_guesses(*args, **kwargs): | |
| 543 scheme = distutils_scheme('', *args, **kwargs) | |
| 544 return [scheme['purelib'], scheme['platlib']] | |
| 545 | |
| 546 | |
| 547 def site_packages_writable(**kwargs): | |
| 548 return all( | |
| 549 test_writable_dir(d) for d in set(get_lib_location_guesses(**kwargs)) | |
| 550 ) | |
| 551 | |
| 552 | |
| 553 def decide_user_install( | |
| 554 use_user_site, # type: Optional[bool] | |
| 555 prefix_path=None, # type: Optional[str] | |
| 556 target_dir=None, # type: Optional[str] | |
| 557 root_path=None, # type: Optional[str] | |
| 558 isolated_mode=False, # type: bool | |
| 559 ): | |
| 560 # type: (...) -> bool | |
| 561 """Determine whether to do a user install based on the input options. | |
| 562 | |
| 563 If use_user_site is False, no additional checks are done. | |
| 564 If use_user_site is True, it is checked for compatibility with other | |
| 565 options. | |
| 566 If use_user_site is None, the default behaviour depends on the environment, | |
| 567 which is provided by the other arguments. | |
| 568 """ | |
| 569 # In some cases (config from tox), use_user_site can be set to an integer | |
| 570 # rather than a bool, which 'use_user_site is False' wouldn't catch. | |
| 571 if (use_user_site is not None) and (not use_user_site): | |
| 572 logger.debug("Non-user install by explicit request") | |
| 573 return False | |
| 574 | |
| 575 if use_user_site: | |
| 576 if prefix_path: | |
| 577 raise CommandError( | |
| 578 "Can not combine '--user' and '--prefix' as they imply " | |
| 579 "different installation locations" | |
| 580 ) | |
| 581 if virtualenv_no_global(): | |
| 582 raise InstallationError( | |
| 583 "Can not perform a '--user' install. User site-packages " | |
| 584 "are not visible in this virtualenv." | |
| 585 ) | |
| 586 logger.debug("User install by explicit request") | |
| 587 return True | |
| 588 | |
| 589 # If we are here, user installs have not been explicitly requested/avoided | |
| 590 assert use_user_site is None | |
| 591 | |
| 592 # user install incompatible with --prefix/--target | |
| 593 if prefix_path or target_dir: | |
| 594 logger.debug("Non-user install due to --prefix or --target option") | |
| 595 return False | |
| 596 | |
| 597 # If user installs are not enabled, choose a non-user install | |
| 598 if not site.ENABLE_USER_SITE: | |
| 599 logger.debug("Non-user install because user site-packages disabled") | |
| 600 return False | |
| 601 | |
| 602 # If we have permission for a non-user install, do that, | |
| 603 # otherwise do a user install. | |
| 604 if site_packages_writable(root=root_path, isolated=isolated_mode): | |
| 605 logger.debug("Non-user install because site-packages writeable") | |
| 606 return False | |
| 607 | |
| 608 logger.info("Defaulting to user installation because normal site-packages " | |
| 609 "is not writeable") | |
| 610 return True | |
| 611 | |
| 612 | |
| 613 def warn_deprecated_install_options(requirement_set, options): | |
| 614 # type: (RequirementSet, Optional[List[str]]) -> None | |
| 615 """If any location-changing --install-option arguments were passed for | |
| 616 requirements or on the command-line, then show a deprecation warning. | |
| 617 """ | |
| 618 def format_options(option_names): | |
| 619 # type: (Iterable[str]) -> List[str] | |
| 620 return ["--{}".format(name.replace("_", "-")) for name in option_names] | |
| 621 | |
| 622 requirements = ( | |
| 623 requirement_set.unnamed_requirements + | |
| 624 list(requirement_set.requirements.values()) | |
| 625 ) | |
| 626 | |
| 627 offenders = [] | |
| 628 | |
| 629 for requirement in requirements: | |
| 630 install_options = requirement.options.get("install_options", []) | |
| 631 location_options = parse_distutils_args(install_options) | |
| 632 if location_options: | |
| 633 offenders.append( | |
| 634 "{!r} from {}".format( | |
| 635 format_options(location_options.keys()), requirement | |
| 636 ) | |
| 637 ) | |
| 638 | |
| 639 if options: | |
| 640 location_options = parse_distutils_args(options) | |
| 641 if location_options: | |
| 642 offenders.append( | |
| 643 "{!r} from command line".format( | |
| 644 format_options(location_options.keys()) | |
| 645 ) | |
| 646 ) | |
| 647 | |
| 648 if not offenders: | |
| 649 return | |
| 650 | |
| 651 deprecated( | |
| 652 reason=( | |
| 653 "Location-changing options found in --install-option: {}. " | |
| 654 "This configuration may cause unexpected behavior and is " | |
| 655 "unsupported.".format( | |
| 656 "; ".join(offenders) | |
| 657 ) | |
| 658 ), | |
| 659 replacement=( | |
| 660 "using pip-level options like --user, --prefix, --root, and " | |
| 661 "--target" | |
| 662 ), | |
| 663 gone_in="20.2", | |
| 664 issue=7309, | |
| 665 ) | |
| 666 | |
| 667 | |
| 668 def create_env_error_message(error, show_traceback, using_user_site): | |
| 669 """Format an error message for an EnvironmentError | |
| 670 | |
| 671 It may occur anytime during the execution of the install command. | |
| 672 """ | |
| 673 parts = [] | |
| 674 | |
| 675 # Mention the error if we are not going to show a traceback | |
| 676 parts.append("Could not install packages due to an EnvironmentError") | |
| 677 if not show_traceback: | |
| 678 parts.append(": ") | |
| 679 parts.append(str(error)) | |
| 680 else: | |
| 681 parts.append(".") | |
| 682 | |
| 683 # Spilt the error indication from a helper message (if any) | |
| 684 parts[-1] += "\n" | |
| 685 | |
| 686 # Suggest useful actions to the user: | |
| 687 # (1) using user site-packages or (2) verifying the permissions | |
| 688 if error.errno == errno.EACCES: | |
| 689 user_option_part = "Consider using the `--user` option" | |
| 690 permissions_part = "Check the permissions" | |
| 691 | |
| 692 if not using_user_site: | |
| 693 parts.extend([ | |
| 694 user_option_part, " or ", | |
| 695 permissions_part.lower(), | |
| 696 ]) | |
| 697 else: | |
| 698 parts.append(permissions_part) | |
| 699 parts.append(".\n") | |
| 700 | |
| 701 return "".join(parts).strip() + "\n" |
