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" |