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