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