Mercurial > repos > guerler > springsuite
comparison planemo/lib/python3.7/site-packages/pip/_internal/commands/install.py @ 1:56ad4e20f292 draft
"planemo upload commit 6eee67778febed82ddd413c3ca40b3183a3898f1"
| author | guerler |
|---|---|
| date | Fri, 31 Jul 2020 00:32:28 -0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 0:d30785e31577 | 1:56ad4e20f292 |
|---|---|
| 1 from __future__ import absolute_import | |
| 2 | |
| 3 import errno | |
| 4 import logging | |
| 5 import operator | |
| 6 import os | |
| 7 import shutil | |
| 8 from optparse import SUPPRESS_HELP | |
| 9 | |
| 10 from pip._vendor import pkg_resources | |
| 11 | |
| 12 from pip._internal.cache import WheelCache | |
| 13 from pip._internal.cli import cmdoptions | |
| 14 from pip._internal.cli.base_command import RequirementCommand | |
| 15 from pip._internal.cli.cmdoptions import make_target_python | |
| 16 from pip._internal.cli.status_codes import ERROR | |
| 17 from pip._internal.exceptions import ( | |
| 18 CommandError, InstallationError, PreviousBuildDirError, | |
| 19 ) | |
| 20 from pip._internal.legacy_resolve import Resolver | |
| 21 from pip._internal.locations import distutils_scheme | |
| 22 from pip._internal.operations.check import check_install_conflicts | |
| 23 from pip._internal.operations.prepare import RequirementPreparer | |
| 24 from pip._internal.req import RequirementSet, install_given_reqs | |
| 25 from pip._internal.req.req_tracker import RequirementTracker | |
| 26 from pip._internal.utils.filesystem import check_path_owner | |
| 27 from pip._internal.utils.misc import ( | |
| 28 ensure_dir, get_installed_version, | |
| 29 protect_pip_from_modification_on_windows, | |
| 30 ) | |
| 31 from pip._internal.utils.temp_dir import TempDirectory | |
| 32 from pip._internal.utils.virtualenv import virtualenv_no_global | |
| 33 from pip._internal.wheel import WheelBuilder | |
| 34 | |
| 35 logger = logging.getLogger(__name__) | |
| 36 | |
| 37 | |
| 38 def is_wheel_installed(): | |
| 39 """ | |
| 40 Return whether the wheel package is installed. | |
| 41 """ | |
| 42 try: | |
| 43 import wheel # noqa: F401 | |
| 44 except ImportError: | |
| 45 return False | |
| 46 | |
| 47 return True | |
| 48 | |
| 49 | |
| 50 def build_wheels(builder, pep517_requirements, legacy_requirements, session): | |
| 51 """ | |
| 52 Build wheels for requirements, depending on whether wheel is installed. | |
| 53 """ | |
| 54 # We don't build wheels for legacy requirements if wheel is not installed. | |
| 55 should_build_legacy = is_wheel_installed() | |
| 56 | |
| 57 # Always build PEP 517 requirements | |
| 58 build_failures = builder.build( | |
| 59 pep517_requirements, | |
| 60 session=session, autobuilding=True | |
| 61 ) | |
| 62 | |
| 63 if should_build_legacy: | |
| 64 # We don't care about failures building legacy | |
| 65 # requirements, as we'll fall through to a direct | |
| 66 # install for those. | |
| 67 builder.build( | |
| 68 legacy_requirements, | |
| 69 session=session, autobuilding=True | |
| 70 ) | |
| 71 | |
| 72 return build_failures | |
| 73 | |
| 74 | |
| 75 class InstallCommand(RequirementCommand): | |
| 76 """ | |
| 77 Install packages from: | |
| 78 | |
| 79 - PyPI (and other indexes) using requirement specifiers. | |
| 80 - VCS project urls. | |
| 81 - Local project directories. | |
| 82 - Local or remote source archives. | |
| 83 | |
| 84 pip also supports installing from "requirements files," which provide | |
| 85 an easy way to specify a whole environment to be installed. | |
| 86 """ | |
| 87 name = 'install' | |
| 88 | |
| 89 usage = """ | |
| 90 %prog [options] <requirement specifier> [package-index-options] ... | |
| 91 %prog [options] -r <requirements file> [package-index-options] ... | |
| 92 %prog [options] [-e] <vcs project url> ... | |
| 93 %prog [options] [-e] <local project path> ... | |
| 94 %prog [options] <archive url/path> ...""" | |
| 95 | |
| 96 summary = 'Install packages.' | |
| 97 | |
| 98 def __init__(self, *args, **kw): | |
| 99 super(InstallCommand, self).__init__(*args, **kw) | |
| 100 | |
| 101 cmd_opts = self.cmd_opts | |
| 102 | |
| 103 cmd_opts.add_option(cmdoptions.requirements()) | |
| 104 cmd_opts.add_option(cmdoptions.constraints()) | |
| 105 cmd_opts.add_option(cmdoptions.no_deps()) | |
| 106 cmd_opts.add_option(cmdoptions.pre()) | |
| 107 | |
| 108 cmd_opts.add_option(cmdoptions.editable()) | |
| 109 cmd_opts.add_option( | |
| 110 '-t', '--target', | |
| 111 dest='target_dir', | |
| 112 metavar='dir', | |
| 113 default=None, | |
| 114 help='Install packages into <dir>. ' | |
| 115 'By default this will not replace existing files/folders in ' | |
| 116 '<dir>. Use --upgrade to replace existing packages in <dir> ' | |
| 117 'with new versions.' | |
| 118 ) | |
| 119 cmdoptions.add_target_python_options(cmd_opts) | |
| 120 | |
| 121 cmd_opts.add_option( | |
| 122 '--user', | |
| 123 dest='use_user_site', | |
| 124 action='store_true', | |
| 125 help="Install to the Python user install directory for your " | |
| 126 "platform. Typically ~/.local/, or %APPDATA%\\Python on " | |
| 127 "Windows. (See the Python documentation for site.USER_BASE " | |
| 128 "for full details.)") | |
| 129 cmd_opts.add_option( | |
| 130 '--no-user', | |
| 131 dest='use_user_site', | |
| 132 action='store_false', | |
| 133 help=SUPPRESS_HELP) | |
| 134 cmd_opts.add_option( | |
| 135 '--root', | |
| 136 dest='root_path', | |
| 137 metavar='dir', | |
| 138 default=None, | |
| 139 help="Install everything relative to this alternate root " | |
| 140 "directory.") | |
| 141 cmd_opts.add_option( | |
| 142 '--prefix', | |
| 143 dest='prefix_path', | |
| 144 metavar='dir', | |
| 145 default=None, | |
| 146 help="Installation prefix where lib, bin and other top-level " | |
| 147 "folders are placed") | |
| 148 | |
| 149 cmd_opts.add_option(cmdoptions.build_dir()) | |
| 150 | |
| 151 cmd_opts.add_option(cmdoptions.src()) | |
| 152 | |
| 153 cmd_opts.add_option( | |
| 154 '-U', '--upgrade', | |
| 155 dest='upgrade', | |
| 156 action='store_true', | |
| 157 help='Upgrade all specified packages to the newest available ' | |
| 158 'version. The handling of dependencies depends on the ' | |
| 159 'upgrade-strategy used.' | |
| 160 ) | |
| 161 | |
| 162 cmd_opts.add_option( | |
| 163 '--upgrade-strategy', | |
| 164 dest='upgrade_strategy', | |
| 165 default='only-if-needed', | |
| 166 choices=['only-if-needed', 'eager'], | |
| 167 help='Determines how dependency upgrading should be handled ' | |
| 168 '[default: %default]. ' | |
| 169 '"eager" - dependencies are upgraded regardless of ' | |
| 170 'whether the currently installed version satisfies the ' | |
| 171 'requirements of the upgraded package(s). ' | |
| 172 '"only-if-needed" - are upgraded only when they do not ' | |
| 173 'satisfy the requirements of the upgraded package(s).' | |
| 174 ) | |
| 175 | |
| 176 cmd_opts.add_option( | |
| 177 '--force-reinstall', | |
| 178 dest='force_reinstall', | |
| 179 action='store_true', | |
| 180 help='Reinstall all packages even if they are already ' | |
| 181 'up-to-date.') | |
| 182 | |
| 183 cmd_opts.add_option( | |
| 184 '-I', '--ignore-installed', | |
| 185 dest='ignore_installed', | |
| 186 action='store_true', | |
| 187 help='Ignore the installed packages (reinstalling instead).') | |
| 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 cmdoptions.check_install_build_global(options) | |
| 244 upgrade_strategy = "to-satisfy-only" | |
| 245 if options.upgrade: | |
| 246 upgrade_strategy = options.upgrade_strategy | |
| 247 | |
| 248 if options.build_dir: | |
| 249 options.build_dir = os.path.abspath(options.build_dir) | |
| 250 | |
| 251 cmdoptions.check_dist_restriction(options, check_target=True) | |
| 252 | |
| 253 options.src_dir = os.path.abspath(options.src_dir) | |
| 254 install_options = options.install_options or [] | |
| 255 if options.use_user_site: | |
| 256 if options.prefix_path: | |
| 257 raise CommandError( | |
| 258 "Can not combine '--user' and '--prefix' as they imply " | |
| 259 "different installation locations" | |
| 260 ) | |
| 261 if virtualenv_no_global(): | |
| 262 raise InstallationError( | |
| 263 "Can not perform a '--user' install. User site-packages " | |
| 264 "are not visible in this virtualenv." | |
| 265 ) | |
| 266 install_options.append('--user') | |
| 267 install_options.append('--prefix=') | |
| 268 | |
| 269 target_temp_dir = TempDirectory(kind="target") | |
| 270 if options.target_dir: | |
| 271 options.ignore_installed = True | |
| 272 options.target_dir = os.path.abspath(options.target_dir) | |
| 273 if (os.path.exists(options.target_dir) and not | |
| 274 os.path.isdir(options.target_dir)): | |
| 275 raise CommandError( | |
| 276 "Target path exists but is not a directory, will not " | |
| 277 "continue." | |
| 278 ) | |
| 279 | |
| 280 # Create a target directory for using with the target option | |
| 281 target_temp_dir.create() | |
| 282 install_options.append('--home=' + target_temp_dir.path) | |
| 283 | |
| 284 global_options = options.global_options or [] | |
| 285 | |
| 286 with self._build_session(options) as session: | |
| 287 target_python = make_target_python(options) | |
| 288 finder = self._build_package_finder( | |
| 289 options=options, | |
| 290 session=session, | |
| 291 target_python=target_python, | |
| 292 ignore_requires_python=options.ignore_requires_python, | |
| 293 ) | |
| 294 build_delete = (not (options.no_clean or options.build_dir)) | |
| 295 wheel_cache = WheelCache(options.cache_dir, options.format_control) | |
| 296 | |
| 297 if options.cache_dir and not check_path_owner(options.cache_dir): | |
| 298 logger.warning( | |
| 299 "The directory '%s' or its parent directory is not owned " | |
| 300 "by the current user and caching wheels has been " | |
| 301 "disabled. check the permissions and owner of that " | |
| 302 "directory. If executing pip with sudo, you may want " | |
| 303 "sudo's -H flag.", | |
| 304 options.cache_dir, | |
| 305 ) | |
| 306 options.cache_dir = None | |
| 307 | |
| 308 with RequirementTracker() as req_tracker, TempDirectory( | |
| 309 options.build_dir, delete=build_delete, kind="install" | |
| 310 ) as directory: | |
| 311 requirement_set = RequirementSet( | |
| 312 require_hashes=options.require_hashes, | |
| 313 check_supported_wheels=not options.target_dir, | |
| 314 ) | |
| 315 | |
| 316 try: | |
| 317 self.populate_requirement_set( | |
| 318 requirement_set, args, options, finder, session, | |
| 319 self.name, wheel_cache | |
| 320 ) | |
| 321 preparer = RequirementPreparer( | |
| 322 build_dir=directory.path, | |
| 323 src_dir=options.src_dir, | |
| 324 download_dir=None, | |
| 325 wheel_download_dir=None, | |
| 326 progress_bar=options.progress_bar, | |
| 327 build_isolation=options.build_isolation, | |
| 328 req_tracker=req_tracker, | |
| 329 ) | |
| 330 | |
| 331 resolver = Resolver( | |
| 332 preparer=preparer, | |
| 333 finder=finder, | |
| 334 session=session, | |
| 335 wheel_cache=wheel_cache, | |
| 336 use_user_site=options.use_user_site, | |
| 337 upgrade_strategy=upgrade_strategy, | |
| 338 force_reinstall=options.force_reinstall, | |
| 339 ignore_dependencies=options.ignore_dependencies, | |
| 340 ignore_requires_python=options.ignore_requires_python, | |
| 341 ignore_installed=options.ignore_installed, | |
| 342 isolated=options.isolated_mode, | |
| 343 use_pep517=options.use_pep517 | |
| 344 ) | |
| 345 resolver.resolve(requirement_set) | |
| 346 | |
| 347 protect_pip_from_modification_on_windows( | |
| 348 modifying_pip=requirement_set.has_requirement("pip") | |
| 349 ) | |
| 350 | |
| 351 # Consider legacy and PEP517-using requirements separately | |
| 352 legacy_requirements = [] | |
| 353 pep517_requirements = [] | |
| 354 for req in requirement_set.requirements.values(): | |
| 355 if req.use_pep517: | |
| 356 pep517_requirements.append(req) | |
| 357 else: | |
| 358 legacy_requirements.append(req) | |
| 359 | |
| 360 wheel_builder = WheelBuilder( | |
| 361 finder, preparer, wheel_cache, | |
| 362 build_options=[], global_options=[], | |
| 363 ) | |
| 364 | |
| 365 build_failures = build_wheels( | |
| 366 builder=wheel_builder, | |
| 367 pep517_requirements=pep517_requirements, | |
| 368 legacy_requirements=legacy_requirements, | |
| 369 session=session, | |
| 370 ) | |
| 371 | |
| 372 # If we're using PEP 517, we cannot do a direct install | |
| 373 # so we fail here. | |
| 374 if build_failures: | |
| 375 raise InstallationError( | |
| 376 "Could not build wheels for {} which use" | |
| 377 " PEP 517 and cannot be installed directly".format( | |
| 378 ", ".join(r.name for r in build_failures))) | |
| 379 | |
| 380 to_install = resolver.get_installation_order( | |
| 381 requirement_set | |
| 382 ) | |
| 383 | |
| 384 # Consistency Checking of the package set we're installing. | |
| 385 should_warn_about_conflicts = ( | |
| 386 not options.ignore_dependencies and | |
| 387 options.warn_about_conflicts | |
| 388 ) | |
| 389 if should_warn_about_conflicts: | |
| 390 self._warn_about_conflicts(to_install) | |
| 391 | |
| 392 # Don't warn about script install locations if | |
| 393 # --target has been specified | |
| 394 warn_script_location = options.warn_script_location | |
| 395 if options.target_dir: | |
| 396 warn_script_location = False | |
| 397 | |
| 398 installed = install_given_reqs( | |
| 399 to_install, | |
| 400 install_options, | |
| 401 global_options, | |
| 402 root=options.root_path, | |
| 403 home=target_temp_dir.path, | |
| 404 prefix=options.prefix_path, | |
| 405 pycompile=options.compile, | |
| 406 warn_script_location=warn_script_location, | |
| 407 use_user_site=options.use_user_site, | |
| 408 ) | |
| 409 | |
| 410 lib_locations = get_lib_location_guesses( | |
| 411 user=options.use_user_site, | |
| 412 home=target_temp_dir.path, | |
| 413 root=options.root_path, | |
| 414 prefix=options.prefix_path, | |
| 415 isolated=options.isolated_mode, | |
| 416 ) | |
| 417 working_set = pkg_resources.WorkingSet(lib_locations) | |
| 418 | |
| 419 reqs = sorted(installed, key=operator.attrgetter('name')) | |
| 420 items = [] | |
| 421 for req in reqs: | |
| 422 item = req.name | |
| 423 try: | |
| 424 installed_version = get_installed_version( | |
| 425 req.name, working_set=working_set | |
| 426 ) | |
| 427 if installed_version: | |
| 428 item += '-' + installed_version | |
| 429 except Exception: | |
| 430 pass | |
| 431 items.append(item) | |
| 432 installed = ' '.join(items) | |
| 433 if installed: | |
| 434 logger.info('Successfully installed %s', installed) | |
| 435 except EnvironmentError as error: | |
| 436 show_traceback = (self.verbosity >= 1) | |
| 437 | |
| 438 message = create_env_error_message( | |
| 439 error, show_traceback, options.use_user_site, | |
| 440 ) | |
| 441 logger.error(message, exc_info=show_traceback) | |
| 442 | |
| 443 return ERROR | |
| 444 except PreviousBuildDirError: | |
| 445 options.no_clean = True | |
| 446 raise | |
| 447 finally: | |
| 448 # Clean up | |
| 449 if not options.no_clean: | |
| 450 requirement_set.cleanup_files() | |
| 451 wheel_cache.cleanup() | |
| 452 | |
| 453 if options.target_dir: | |
| 454 self._handle_target_dir( | |
| 455 options.target_dir, target_temp_dir, options.upgrade | |
| 456 ) | |
| 457 return requirement_set | |
| 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 create_env_error_message(error, show_traceback, using_user_site): | |
| 548 """Format an error message for an EnvironmentError | |
| 549 | |
| 550 It may occur anytime during the execution of the install command. | |
| 551 """ | |
| 552 parts = [] | |
| 553 | |
| 554 # Mention the error if we are not going to show a traceback | |
| 555 parts.append("Could not install packages due to an EnvironmentError") | |
| 556 if not show_traceback: | |
| 557 parts.append(": ") | |
| 558 parts.append(str(error)) | |
| 559 else: | |
| 560 parts.append(".") | |
| 561 | |
| 562 # Spilt the error indication from a helper message (if any) | |
| 563 parts[-1] += "\n" | |
| 564 | |
| 565 # Suggest useful actions to the user: | |
| 566 # (1) using user site-packages or (2) verifying the permissions | |
| 567 if error.errno == errno.EACCES: | |
| 568 user_option_part = "Consider using the `--user` option" | |
| 569 permissions_part = "Check the permissions" | |
| 570 | |
| 571 if not using_user_site: | |
| 572 parts.extend([ | |
| 573 user_option_part, " or ", | |
| 574 permissions_part.lower(), | |
| 575 ]) | |
| 576 else: | |
| 577 parts.append(permissions_part) | |
| 578 parts.append(".\n") | |
| 579 | |
| 580 return "".join(parts).strip() + "\n" |
