Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +1 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/opencv_python.libs/libQt5XcbQpa-5b2d853e.so.5.15.0 +3 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/__pycache__/__init__.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/__pycache__/build_env.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/__pycache__/cache.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/__pycache__/exceptions.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/__pycache__/main.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/__pycache__/pyproject.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/__pycache__/self_outdated_check.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/__pycache__/wheel_builder.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/cli/__init__.py +4 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/cli/base_command.py +236 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/cli/cmdoptions.py +1074 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/cli/command_context.py +27 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/cli/main.py +79 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/cli/main_parser.py +134 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/cli/parser.py +294 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/cli/progress_bars.py +68 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/cli/status_codes.py +6 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/locations/_distutils.py +172 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/locations/base.py +81 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/models/index.py +28 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/models/installation_report.py +56 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/__init__.py +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/_jaraco_text.py +109 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/_log.py +38 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/appdirs.py +52 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/compatibility_tags.py +165 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/encoding.py +36 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/entrypoints.py +84 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/filesystem.py +153 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/filetypes.py +27 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/glibc.py +88 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/misc.py +783 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/models.py +39 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/packaging.py +57 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/setuptools_build.py +146 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/subprocess.py +260 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/temp_dir.py +296 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/urls.py +62 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/wheel.py +134 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_vendor/distro/__pycache__/__init__.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_vendor/distro/__pycache__/__main__.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_vendor/distro/__pycache__/distro.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/__init__.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/_manylinux.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/_musllinux.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/requirements.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/specifiers.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/tags.cpython-38.pyc +0 -0
.gitattributes
CHANGED
|
@@ -357,3 +357,4 @@ my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/aiohttp/_ht
|
|
| 357 |
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/Pillow.libs/libharfbuzz-17f91c2d.so.0.40201.0 filter=lfs diff=lfs merge=lfs -text
|
| 358 |
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/opencv_python.libs/libavformat-3ff1be5b.so.59.27.100 filter=lfs diff=lfs merge=lfs -text
|
| 359 |
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_vendor/distlib/w64.exe filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 357 |
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/Pillow.libs/libharfbuzz-17f91c2d.so.0.40201.0 filter=lfs diff=lfs merge=lfs -text
|
| 358 |
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/opencv_python.libs/libavformat-3ff1be5b.so.59.27.100 filter=lfs diff=lfs merge=lfs -text
|
| 359 |
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_vendor/distlib/w64.exe filter=lfs diff=lfs merge=lfs -text
|
| 360 |
+
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/opencv_python.libs/libQt5XcbQpa-5b2d853e.so.5.15.0 filter=lfs diff=lfs merge=lfs -text
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/opencv_python.libs/libQt5XcbQpa-5b2d853e.so.5.15.0
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:943745b9c7c801f8172b7740fa960ab18882127af415ab37059d6fd16777396a
|
| 3 |
+
size 1796105
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/__pycache__/__init__.cpython-38.pyc
ADDED
|
Binary file (652 Bytes). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/__pycache__/build_env.cpython-38.pyc
ADDED
|
Binary file (9.59 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/__pycache__/cache.cpython-38.pyc
ADDED
|
Binary file (8.97 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/__pycache__/exceptions.cpython-38.pyc
ADDED
|
Binary file (25.6 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/__pycache__/main.cpython-38.pyc
ADDED
|
Binary file (576 Bytes). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/__pycache__/pyproject.cpython-38.pyc
ADDED
|
Binary file (3.61 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/__pycache__/self_outdated_check.cpython-38.pyc
ADDED
|
Binary file (6.84 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/__pycache__/wheel_builder.cpython-38.pyc
ADDED
|
Binary file (8.62 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/cli/__init__.py
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Subpackage containing all of pip's command line interface related code
|
| 2 |
+
"""
|
| 3 |
+
|
| 4 |
+
# This file intentionally does not import submodules
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/cli/base_command.py
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Base Command class, and related routines"""
|
| 2 |
+
|
| 3 |
+
import functools
|
| 4 |
+
import logging
|
| 5 |
+
import logging.config
|
| 6 |
+
import optparse
|
| 7 |
+
import os
|
| 8 |
+
import sys
|
| 9 |
+
import traceback
|
| 10 |
+
from optparse import Values
|
| 11 |
+
from typing import Any, Callable, List, Optional, Tuple
|
| 12 |
+
|
| 13 |
+
from pip._vendor.rich import traceback as rich_traceback
|
| 14 |
+
|
| 15 |
+
from pip._internal.cli import cmdoptions
|
| 16 |
+
from pip._internal.cli.command_context import CommandContextMixIn
|
| 17 |
+
from pip._internal.cli.parser import ConfigOptionParser, UpdatingDefaultsHelpFormatter
|
| 18 |
+
from pip._internal.cli.status_codes import (
|
| 19 |
+
ERROR,
|
| 20 |
+
PREVIOUS_BUILD_DIR_ERROR,
|
| 21 |
+
UNKNOWN_ERROR,
|
| 22 |
+
VIRTUALENV_NOT_FOUND,
|
| 23 |
+
)
|
| 24 |
+
from pip._internal.exceptions import (
|
| 25 |
+
BadCommand,
|
| 26 |
+
CommandError,
|
| 27 |
+
DiagnosticPipError,
|
| 28 |
+
InstallationError,
|
| 29 |
+
NetworkConnectionError,
|
| 30 |
+
PreviousBuildDirError,
|
| 31 |
+
UninstallationError,
|
| 32 |
+
)
|
| 33 |
+
from pip._internal.utils.filesystem import check_path_owner
|
| 34 |
+
from pip._internal.utils.logging import BrokenStdoutLoggingError, setup_logging
|
| 35 |
+
from pip._internal.utils.misc import get_prog, normalize_path
|
| 36 |
+
from pip._internal.utils.temp_dir import TempDirectoryTypeRegistry as TempDirRegistry
|
| 37 |
+
from pip._internal.utils.temp_dir import global_tempdir_manager, tempdir_registry
|
| 38 |
+
from pip._internal.utils.virtualenv import running_under_virtualenv
|
| 39 |
+
|
| 40 |
+
__all__ = ["Command"]
|
| 41 |
+
|
| 42 |
+
logger = logging.getLogger(__name__)
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
class Command(CommandContextMixIn):
|
| 46 |
+
usage: str = ""
|
| 47 |
+
ignore_require_venv: bool = False
|
| 48 |
+
|
| 49 |
+
def __init__(self, name: str, summary: str, isolated: bool = False) -> None:
|
| 50 |
+
super().__init__()
|
| 51 |
+
|
| 52 |
+
self.name = name
|
| 53 |
+
self.summary = summary
|
| 54 |
+
self.parser = ConfigOptionParser(
|
| 55 |
+
usage=self.usage,
|
| 56 |
+
prog=f"{get_prog()} {name}",
|
| 57 |
+
formatter=UpdatingDefaultsHelpFormatter(),
|
| 58 |
+
add_help_option=False,
|
| 59 |
+
name=name,
|
| 60 |
+
description=self.__doc__,
|
| 61 |
+
isolated=isolated,
|
| 62 |
+
)
|
| 63 |
+
|
| 64 |
+
self.tempdir_registry: Optional[TempDirRegistry] = None
|
| 65 |
+
|
| 66 |
+
# Commands should add options to this option group
|
| 67 |
+
optgroup_name = f"{self.name.capitalize()} Options"
|
| 68 |
+
self.cmd_opts = optparse.OptionGroup(self.parser, optgroup_name)
|
| 69 |
+
|
| 70 |
+
# Add the general options
|
| 71 |
+
gen_opts = cmdoptions.make_option_group(
|
| 72 |
+
cmdoptions.general_group,
|
| 73 |
+
self.parser,
|
| 74 |
+
)
|
| 75 |
+
self.parser.add_option_group(gen_opts)
|
| 76 |
+
|
| 77 |
+
self.add_options()
|
| 78 |
+
|
| 79 |
+
def add_options(self) -> None:
|
| 80 |
+
pass
|
| 81 |
+
|
| 82 |
+
def handle_pip_version_check(self, options: Values) -> None:
|
| 83 |
+
"""
|
| 84 |
+
This is a no-op so that commands by default do not do the pip version
|
| 85 |
+
check.
|
| 86 |
+
"""
|
| 87 |
+
# Make sure we do the pip version check if the index_group options
|
| 88 |
+
# are present.
|
| 89 |
+
assert not hasattr(options, "no_index")
|
| 90 |
+
|
| 91 |
+
def run(self, options: Values, args: List[str]) -> int:
|
| 92 |
+
raise NotImplementedError
|
| 93 |
+
|
| 94 |
+
def parse_args(self, args: List[str]) -> Tuple[Values, List[str]]:
|
| 95 |
+
# factored out for testability
|
| 96 |
+
return self.parser.parse_args(args)
|
| 97 |
+
|
| 98 |
+
def main(self, args: List[str]) -> int:
|
| 99 |
+
try:
|
| 100 |
+
with self.main_context():
|
| 101 |
+
return self._main(args)
|
| 102 |
+
finally:
|
| 103 |
+
logging.shutdown()
|
| 104 |
+
|
| 105 |
+
def _main(self, args: List[str]) -> int:
|
| 106 |
+
# We must initialize this before the tempdir manager, otherwise the
|
| 107 |
+
# configuration would not be accessible by the time we clean up the
|
| 108 |
+
# tempdir manager.
|
| 109 |
+
self.tempdir_registry = self.enter_context(tempdir_registry())
|
| 110 |
+
# Intentionally set as early as possible so globally-managed temporary
|
| 111 |
+
# directories are available to the rest of the code.
|
| 112 |
+
self.enter_context(global_tempdir_manager())
|
| 113 |
+
|
| 114 |
+
options, args = self.parse_args(args)
|
| 115 |
+
|
| 116 |
+
# Set verbosity so that it can be used elsewhere.
|
| 117 |
+
self.verbosity = options.verbose - options.quiet
|
| 118 |
+
|
| 119 |
+
level_number = setup_logging(
|
| 120 |
+
verbosity=self.verbosity,
|
| 121 |
+
no_color=options.no_color,
|
| 122 |
+
user_log_file=options.log,
|
| 123 |
+
)
|
| 124 |
+
|
| 125 |
+
always_enabled_features = set(options.features_enabled) & set(
|
| 126 |
+
cmdoptions.ALWAYS_ENABLED_FEATURES
|
| 127 |
+
)
|
| 128 |
+
if always_enabled_features:
|
| 129 |
+
logger.warning(
|
| 130 |
+
"The following features are always enabled: %s. ",
|
| 131 |
+
", ".join(sorted(always_enabled_features)),
|
| 132 |
+
)
|
| 133 |
+
|
| 134 |
+
# Make sure that the --python argument isn't specified after the
|
| 135 |
+
# subcommand. We can tell, because if --python was specified,
|
| 136 |
+
# we should only reach this point if we're running in the created
|
| 137 |
+
# subprocess, which has the _PIP_RUNNING_IN_SUBPROCESS environment
|
| 138 |
+
# variable set.
|
| 139 |
+
if options.python and "_PIP_RUNNING_IN_SUBPROCESS" not in os.environ:
|
| 140 |
+
logger.critical(
|
| 141 |
+
"The --python option must be placed before the pip subcommand name"
|
| 142 |
+
)
|
| 143 |
+
sys.exit(ERROR)
|
| 144 |
+
|
| 145 |
+
# TODO: Try to get these passing down from the command?
|
| 146 |
+
# without resorting to os.environ to hold these.
|
| 147 |
+
# This also affects isolated builds and it should.
|
| 148 |
+
|
| 149 |
+
if options.no_input:
|
| 150 |
+
os.environ["PIP_NO_INPUT"] = "1"
|
| 151 |
+
|
| 152 |
+
if options.exists_action:
|
| 153 |
+
os.environ["PIP_EXISTS_ACTION"] = " ".join(options.exists_action)
|
| 154 |
+
|
| 155 |
+
if options.require_venv and not self.ignore_require_venv:
|
| 156 |
+
# If a venv is required check if it can really be found
|
| 157 |
+
if not running_under_virtualenv():
|
| 158 |
+
logger.critical("Could not find an activated virtualenv (required).")
|
| 159 |
+
sys.exit(VIRTUALENV_NOT_FOUND)
|
| 160 |
+
|
| 161 |
+
if options.cache_dir:
|
| 162 |
+
options.cache_dir = normalize_path(options.cache_dir)
|
| 163 |
+
if not check_path_owner(options.cache_dir):
|
| 164 |
+
logger.warning(
|
| 165 |
+
"The directory '%s' or its parent directory is not owned "
|
| 166 |
+
"or is not writable by the current user. The cache "
|
| 167 |
+
"has been disabled. Check the permissions and owner of "
|
| 168 |
+
"that directory. If executing pip with sudo, you should "
|
| 169 |
+
"use sudo's -H flag.",
|
| 170 |
+
options.cache_dir,
|
| 171 |
+
)
|
| 172 |
+
options.cache_dir = None
|
| 173 |
+
|
| 174 |
+
def intercepts_unhandled_exc(
|
| 175 |
+
run_func: Callable[..., int]
|
| 176 |
+
) -> Callable[..., int]:
|
| 177 |
+
@functools.wraps(run_func)
|
| 178 |
+
def exc_logging_wrapper(*args: Any) -> int:
|
| 179 |
+
try:
|
| 180 |
+
status = run_func(*args)
|
| 181 |
+
assert isinstance(status, int)
|
| 182 |
+
return status
|
| 183 |
+
except DiagnosticPipError as exc:
|
| 184 |
+
logger.error("%s", exc, extra={"rich": True})
|
| 185 |
+
logger.debug("Exception information:", exc_info=True)
|
| 186 |
+
|
| 187 |
+
return ERROR
|
| 188 |
+
except PreviousBuildDirError as exc:
|
| 189 |
+
logger.critical(str(exc))
|
| 190 |
+
logger.debug("Exception information:", exc_info=True)
|
| 191 |
+
|
| 192 |
+
return PREVIOUS_BUILD_DIR_ERROR
|
| 193 |
+
except (
|
| 194 |
+
InstallationError,
|
| 195 |
+
UninstallationError,
|
| 196 |
+
BadCommand,
|
| 197 |
+
NetworkConnectionError,
|
| 198 |
+
) as exc:
|
| 199 |
+
logger.critical(str(exc))
|
| 200 |
+
logger.debug("Exception information:", exc_info=True)
|
| 201 |
+
|
| 202 |
+
return ERROR
|
| 203 |
+
except CommandError as exc:
|
| 204 |
+
logger.critical("%s", exc)
|
| 205 |
+
logger.debug("Exception information:", exc_info=True)
|
| 206 |
+
|
| 207 |
+
return ERROR
|
| 208 |
+
except BrokenStdoutLoggingError:
|
| 209 |
+
# Bypass our logger and write any remaining messages to
|
| 210 |
+
# stderr because stdout no longer works.
|
| 211 |
+
print("ERROR: Pipe to stdout was broken", file=sys.stderr)
|
| 212 |
+
if level_number <= logging.DEBUG:
|
| 213 |
+
traceback.print_exc(file=sys.stderr)
|
| 214 |
+
|
| 215 |
+
return ERROR
|
| 216 |
+
except KeyboardInterrupt:
|
| 217 |
+
logger.critical("Operation cancelled by user")
|
| 218 |
+
logger.debug("Exception information:", exc_info=True)
|
| 219 |
+
|
| 220 |
+
return ERROR
|
| 221 |
+
except BaseException:
|
| 222 |
+
logger.critical("Exception:", exc_info=True)
|
| 223 |
+
|
| 224 |
+
return UNKNOWN_ERROR
|
| 225 |
+
|
| 226 |
+
return exc_logging_wrapper
|
| 227 |
+
|
| 228 |
+
try:
|
| 229 |
+
if not options.debug_mode:
|
| 230 |
+
run = intercepts_unhandled_exc(self.run)
|
| 231 |
+
else:
|
| 232 |
+
run = self.run
|
| 233 |
+
rich_traceback.install(show_locals=True)
|
| 234 |
+
return run(options, args)
|
| 235 |
+
finally:
|
| 236 |
+
self.handle_pip_version_check(options)
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/cli/cmdoptions.py
ADDED
|
@@ -0,0 +1,1074 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
shared options and groups
|
| 3 |
+
|
| 4 |
+
The principle here is to define options once, but *not* instantiate them
|
| 5 |
+
globally. One reason being that options with action='append' can carry state
|
| 6 |
+
between parses. pip parses general options twice internally, and shouldn't
|
| 7 |
+
pass on state. To be consistent, all options will follow this design.
|
| 8 |
+
"""
|
| 9 |
+
|
| 10 |
+
# The following comment should be removed at some point in the future.
|
| 11 |
+
# mypy: strict-optional=False
|
| 12 |
+
|
| 13 |
+
import importlib.util
|
| 14 |
+
import logging
|
| 15 |
+
import os
|
| 16 |
+
import textwrap
|
| 17 |
+
from functools import partial
|
| 18 |
+
from optparse import SUPPRESS_HELP, Option, OptionGroup, OptionParser, Values
|
| 19 |
+
from textwrap import dedent
|
| 20 |
+
from typing import Any, Callable, Dict, Optional, Tuple
|
| 21 |
+
|
| 22 |
+
from pip._vendor.packaging.utils import canonicalize_name
|
| 23 |
+
|
| 24 |
+
from pip._internal.cli.parser import ConfigOptionParser
|
| 25 |
+
from pip._internal.exceptions import CommandError
|
| 26 |
+
from pip._internal.locations import USER_CACHE_DIR, get_src_prefix
|
| 27 |
+
from pip._internal.models.format_control import FormatControl
|
| 28 |
+
from pip._internal.models.index import PyPI
|
| 29 |
+
from pip._internal.models.target_python import TargetPython
|
| 30 |
+
from pip._internal.utils.hashes import STRONG_HASHES
|
| 31 |
+
from pip._internal.utils.misc import strtobool
|
| 32 |
+
|
| 33 |
+
logger = logging.getLogger(__name__)
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def raise_option_error(parser: OptionParser, option: Option, msg: str) -> None:
|
| 37 |
+
"""
|
| 38 |
+
Raise an option parsing error using parser.error().
|
| 39 |
+
|
| 40 |
+
Args:
|
| 41 |
+
parser: an OptionParser instance.
|
| 42 |
+
option: an Option instance.
|
| 43 |
+
msg: the error text.
|
| 44 |
+
"""
|
| 45 |
+
msg = f"{option} error: {msg}"
|
| 46 |
+
msg = textwrap.fill(" ".join(msg.split()))
|
| 47 |
+
parser.error(msg)
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def make_option_group(group: Dict[str, Any], parser: ConfigOptionParser) -> OptionGroup:
|
| 51 |
+
"""
|
| 52 |
+
Return an OptionGroup object
|
| 53 |
+
group -- assumed to be dict with 'name' and 'options' keys
|
| 54 |
+
parser -- an optparse Parser
|
| 55 |
+
"""
|
| 56 |
+
option_group = OptionGroup(parser, group["name"])
|
| 57 |
+
for option in group["options"]:
|
| 58 |
+
option_group.add_option(option())
|
| 59 |
+
return option_group
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
def check_dist_restriction(options: Values, check_target: bool = False) -> None:
|
| 63 |
+
"""Function for determining if custom platform options are allowed.
|
| 64 |
+
|
| 65 |
+
:param options: The OptionParser options.
|
| 66 |
+
:param check_target: Whether or not to check if --target is being used.
|
| 67 |
+
"""
|
| 68 |
+
dist_restriction_set = any(
|
| 69 |
+
[
|
| 70 |
+
options.python_version,
|
| 71 |
+
options.platforms,
|
| 72 |
+
options.abis,
|
| 73 |
+
options.implementation,
|
| 74 |
+
]
|
| 75 |
+
)
|
| 76 |
+
|
| 77 |
+
binary_only = FormatControl(set(), {":all:"})
|
| 78 |
+
sdist_dependencies_allowed = (
|
| 79 |
+
options.format_control != binary_only and not options.ignore_dependencies
|
| 80 |
+
)
|
| 81 |
+
|
| 82 |
+
# Installations or downloads using dist restrictions must not combine
|
| 83 |
+
# source distributions and dist-specific wheels, as they are not
|
| 84 |
+
# guaranteed to be locally compatible.
|
| 85 |
+
if dist_restriction_set and sdist_dependencies_allowed:
|
| 86 |
+
raise CommandError(
|
| 87 |
+
"When restricting platform and interpreter constraints using "
|
| 88 |
+
"--python-version, --platform, --abi, or --implementation, "
|
| 89 |
+
"either --no-deps must be set, or --only-binary=:all: must be "
|
| 90 |
+
"set and --no-binary must not be set (or must be set to "
|
| 91 |
+
":none:)."
|
| 92 |
+
)
|
| 93 |
+
|
| 94 |
+
if check_target:
|
| 95 |
+
if not options.dry_run and dist_restriction_set and not options.target_dir:
|
| 96 |
+
raise CommandError(
|
| 97 |
+
"Can not use any platform or abi specific options unless "
|
| 98 |
+
"installing via '--target' or using '--dry-run'"
|
| 99 |
+
)
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
def _path_option_check(option: Option, opt: str, value: str) -> str:
|
| 103 |
+
return os.path.expanduser(value)
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
def _package_name_option_check(option: Option, opt: str, value: str) -> str:
|
| 107 |
+
return canonicalize_name(value)
|
| 108 |
+
|
| 109 |
+
|
| 110 |
+
class PipOption(Option):
|
| 111 |
+
TYPES = Option.TYPES + ("path", "package_name")
|
| 112 |
+
TYPE_CHECKER = Option.TYPE_CHECKER.copy()
|
| 113 |
+
TYPE_CHECKER["package_name"] = _package_name_option_check
|
| 114 |
+
TYPE_CHECKER["path"] = _path_option_check
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
###########
|
| 118 |
+
# options #
|
| 119 |
+
###########
|
| 120 |
+
|
| 121 |
+
help_: Callable[..., Option] = partial(
|
| 122 |
+
Option,
|
| 123 |
+
"-h",
|
| 124 |
+
"--help",
|
| 125 |
+
dest="help",
|
| 126 |
+
action="help",
|
| 127 |
+
help="Show help.",
|
| 128 |
+
)
|
| 129 |
+
|
| 130 |
+
debug_mode: Callable[..., Option] = partial(
|
| 131 |
+
Option,
|
| 132 |
+
"--debug",
|
| 133 |
+
dest="debug_mode",
|
| 134 |
+
action="store_true",
|
| 135 |
+
default=False,
|
| 136 |
+
help=(
|
| 137 |
+
"Let unhandled exceptions propagate outside the main subroutine, "
|
| 138 |
+
"instead of logging them to stderr."
|
| 139 |
+
),
|
| 140 |
+
)
|
| 141 |
+
|
| 142 |
+
isolated_mode: Callable[..., Option] = partial(
|
| 143 |
+
Option,
|
| 144 |
+
"--isolated",
|
| 145 |
+
dest="isolated_mode",
|
| 146 |
+
action="store_true",
|
| 147 |
+
default=False,
|
| 148 |
+
help=(
|
| 149 |
+
"Run pip in an isolated mode, ignoring environment variables and user "
|
| 150 |
+
"configuration."
|
| 151 |
+
),
|
| 152 |
+
)
|
| 153 |
+
|
| 154 |
+
require_virtualenv: Callable[..., Option] = partial(
|
| 155 |
+
Option,
|
| 156 |
+
"--require-virtualenv",
|
| 157 |
+
"--require-venv",
|
| 158 |
+
dest="require_venv",
|
| 159 |
+
action="store_true",
|
| 160 |
+
default=False,
|
| 161 |
+
help=(
|
| 162 |
+
"Allow pip to only run in a virtual environment; "
|
| 163 |
+
"exit with an error otherwise."
|
| 164 |
+
),
|
| 165 |
+
)
|
| 166 |
+
|
| 167 |
+
override_externally_managed: Callable[..., Option] = partial(
|
| 168 |
+
Option,
|
| 169 |
+
"--break-system-packages",
|
| 170 |
+
dest="override_externally_managed",
|
| 171 |
+
action="store_true",
|
| 172 |
+
help="Allow pip to modify an EXTERNALLY-MANAGED Python installation",
|
| 173 |
+
)
|
| 174 |
+
|
| 175 |
+
python: Callable[..., Option] = partial(
|
| 176 |
+
Option,
|
| 177 |
+
"--python",
|
| 178 |
+
dest="python",
|
| 179 |
+
help="Run pip with the specified Python interpreter.",
|
| 180 |
+
)
|
| 181 |
+
|
| 182 |
+
verbose: Callable[..., Option] = partial(
|
| 183 |
+
Option,
|
| 184 |
+
"-v",
|
| 185 |
+
"--verbose",
|
| 186 |
+
dest="verbose",
|
| 187 |
+
action="count",
|
| 188 |
+
default=0,
|
| 189 |
+
help="Give more output. Option is additive, and can be used up to 3 times.",
|
| 190 |
+
)
|
| 191 |
+
|
| 192 |
+
no_color: Callable[..., Option] = partial(
|
| 193 |
+
Option,
|
| 194 |
+
"--no-color",
|
| 195 |
+
dest="no_color",
|
| 196 |
+
action="store_true",
|
| 197 |
+
default=False,
|
| 198 |
+
help="Suppress colored output.",
|
| 199 |
+
)
|
| 200 |
+
|
| 201 |
+
version: Callable[..., Option] = partial(
|
| 202 |
+
Option,
|
| 203 |
+
"-V",
|
| 204 |
+
"--version",
|
| 205 |
+
dest="version",
|
| 206 |
+
action="store_true",
|
| 207 |
+
help="Show version and exit.",
|
| 208 |
+
)
|
| 209 |
+
|
| 210 |
+
quiet: Callable[..., Option] = partial(
|
| 211 |
+
Option,
|
| 212 |
+
"-q",
|
| 213 |
+
"--quiet",
|
| 214 |
+
dest="quiet",
|
| 215 |
+
action="count",
|
| 216 |
+
default=0,
|
| 217 |
+
help=(
|
| 218 |
+
"Give less output. Option is additive, and can be used up to 3"
|
| 219 |
+
" times (corresponding to WARNING, ERROR, and CRITICAL logging"
|
| 220 |
+
" levels)."
|
| 221 |
+
),
|
| 222 |
+
)
|
| 223 |
+
|
| 224 |
+
progress_bar: Callable[..., Option] = partial(
|
| 225 |
+
Option,
|
| 226 |
+
"--progress-bar",
|
| 227 |
+
dest="progress_bar",
|
| 228 |
+
type="choice",
|
| 229 |
+
choices=["on", "off"],
|
| 230 |
+
default="on",
|
| 231 |
+
help="Specify whether the progress bar should be used [on, off] (default: on)",
|
| 232 |
+
)
|
| 233 |
+
|
| 234 |
+
log: Callable[..., Option] = partial(
|
| 235 |
+
PipOption,
|
| 236 |
+
"--log",
|
| 237 |
+
"--log-file",
|
| 238 |
+
"--local-log",
|
| 239 |
+
dest="log",
|
| 240 |
+
metavar="path",
|
| 241 |
+
type="path",
|
| 242 |
+
help="Path to a verbose appending log.",
|
| 243 |
+
)
|
| 244 |
+
|
| 245 |
+
no_input: Callable[..., Option] = partial(
|
| 246 |
+
Option,
|
| 247 |
+
# Don't ask for input
|
| 248 |
+
"--no-input",
|
| 249 |
+
dest="no_input",
|
| 250 |
+
action="store_true",
|
| 251 |
+
default=False,
|
| 252 |
+
help="Disable prompting for input.",
|
| 253 |
+
)
|
| 254 |
+
|
| 255 |
+
keyring_provider: Callable[..., Option] = partial(
|
| 256 |
+
Option,
|
| 257 |
+
"--keyring-provider",
|
| 258 |
+
dest="keyring_provider",
|
| 259 |
+
choices=["auto", "disabled", "import", "subprocess"],
|
| 260 |
+
default="auto",
|
| 261 |
+
help=(
|
| 262 |
+
"Enable the credential lookup via the keyring library if user input is allowed."
|
| 263 |
+
" Specify which mechanism to use [disabled, import, subprocess]."
|
| 264 |
+
" (default: disabled)"
|
| 265 |
+
),
|
| 266 |
+
)
|
| 267 |
+
|
| 268 |
+
proxy: Callable[..., Option] = partial(
|
| 269 |
+
Option,
|
| 270 |
+
"--proxy",
|
| 271 |
+
dest="proxy",
|
| 272 |
+
type="str",
|
| 273 |
+
default="",
|
| 274 |
+
help="Specify a proxy in the form scheme://[user:passwd@]proxy.server:port.",
|
| 275 |
+
)
|
| 276 |
+
|
| 277 |
+
retries: Callable[..., Option] = partial(
|
| 278 |
+
Option,
|
| 279 |
+
"--retries",
|
| 280 |
+
dest="retries",
|
| 281 |
+
type="int",
|
| 282 |
+
default=5,
|
| 283 |
+
help="Maximum number of retries each connection should attempt "
|
| 284 |
+
"(default %default times).",
|
| 285 |
+
)
|
| 286 |
+
|
| 287 |
+
timeout: Callable[..., Option] = partial(
|
| 288 |
+
Option,
|
| 289 |
+
"--timeout",
|
| 290 |
+
"--default-timeout",
|
| 291 |
+
metavar="sec",
|
| 292 |
+
dest="timeout",
|
| 293 |
+
type="float",
|
| 294 |
+
default=15,
|
| 295 |
+
help="Set the socket timeout (default %default seconds).",
|
| 296 |
+
)
|
| 297 |
+
|
| 298 |
+
|
| 299 |
+
def exists_action() -> Option:
|
| 300 |
+
return Option(
|
| 301 |
+
# Option when path already exist
|
| 302 |
+
"--exists-action",
|
| 303 |
+
dest="exists_action",
|
| 304 |
+
type="choice",
|
| 305 |
+
choices=["s", "i", "w", "b", "a"],
|
| 306 |
+
default=[],
|
| 307 |
+
action="append",
|
| 308 |
+
metavar="action",
|
| 309 |
+
help="Default action when a path already exists: "
|
| 310 |
+
"(s)witch, (i)gnore, (w)ipe, (b)ackup, (a)bort.",
|
| 311 |
+
)
|
| 312 |
+
|
| 313 |
+
|
| 314 |
+
cert: Callable[..., Option] = partial(
|
| 315 |
+
PipOption,
|
| 316 |
+
"--cert",
|
| 317 |
+
dest="cert",
|
| 318 |
+
type="path",
|
| 319 |
+
metavar="path",
|
| 320 |
+
help=(
|
| 321 |
+
"Path to PEM-encoded CA certificate bundle. "
|
| 322 |
+
"If provided, overrides the default. "
|
| 323 |
+
"See 'SSL Certificate Verification' in pip documentation "
|
| 324 |
+
"for more information."
|
| 325 |
+
),
|
| 326 |
+
)
|
| 327 |
+
|
| 328 |
+
client_cert: Callable[..., Option] = partial(
|
| 329 |
+
PipOption,
|
| 330 |
+
"--client-cert",
|
| 331 |
+
dest="client_cert",
|
| 332 |
+
type="path",
|
| 333 |
+
default=None,
|
| 334 |
+
metavar="path",
|
| 335 |
+
help="Path to SSL client certificate, a single file containing the "
|
| 336 |
+
"private key and the certificate in PEM format.",
|
| 337 |
+
)
|
| 338 |
+
|
| 339 |
+
index_url: Callable[..., Option] = partial(
|
| 340 |
+
Option,
|
| 341 |
+
"-i",
|
| 342 |
+
"--index-url",
|
| 343 |
+
"--pypi-url",
|
| 344 |
+
dest="index_url",
|
| 345 |
+
metavar="URL",
|
| 346 |
+
default=PyPI.simple_url,
|
| 347 |
+
help="Base URL of the Python Package Index (default %default). "
|
| 348 |
+
"This should point to a repository compliant with PEP 503 "
|
| 349 |
+
"(the simple repository API) or a local directory laid out "
|
| 350 |
+
"in the same format.",
|
| 351 |
+
)
|
| 352 |
+
|
| 353 |
+
|
| 354 |
+
def extra_index_url() -> Option:
|
| 355 |
+
return Option(
|
| 356 |
+
"--extra-index-url",
|
| 357 |
+
dest="extra_index_urls",
|
| 358 |
+
metavar="URL",
|
| 359 |
+
action="append",
|
| 360 |
+
default=[],
|
| 361 |
+
help="Extra URLs of package indexes to use in addition to "
|
| 362 |
+
"--index-url. Should follow the same rules as "
|
| 363 |
+
"--index-url.",
|
| 364 |
+
)
|
| 365 |
+
|
| 366 |
+
|
| 367 |
+
no_index: Callable[..., Option] = partial(
|
| 368 |
+
Option,
|
| 369 |
+
"--no-index",
|
| 370 |
+
dest="no_index",
|
| 371 |
+
action="store_true",
|
| 372 |
+
default=False,
|
| 373 |
+
help="Ignore package index (only looking at --find-links URLs instead).",
|
| 374 |
+
)
|
| 375 |
+
|
| 376 |
+
|
| 377 |
+
def find_links() -> Option:
|
| 378 |
+
return Option(
|
| 379 |
+
"-f",
|
| 380 |
+
"--find-links",
|
| 381 |
+
dest="find_links",
|
| 382 |
+
action="append",
|
| 383 |
+
default=[],
|
| 384 |
+
metavar="url",
|
| 385 |
+
help="If a URL or path to an html file, then parse for links to "
|
| 386 |
+
"archives such as sdist (.tar.gz) or wheel (.whl) files. "
|
| 387 |
+
"If a local path or file:// URL that's a directory, "
|
| 388 |
+
"then look for archives in the directory listing. "
|
| 389 |
+
"Links to VCS project URLs are not supported.",
|
| 390 |
+
)
|
| 391 |
+
|
| 392 |
+
|
| 393 |
+
def trusted_host() -> Option:
|
| 394 |
+
return Option(
|
| 395 |
+
"--trusted-host",
|
| 396 |
+
dest="trusted_hosts",
|
| 397 |
+
action="append",
|
| 398 |
+
metavar="HOSTNAME",
|
| 399 |
+
default=[],
|
| 400 |
+
help="Mark this host or host:port pair as trusted, even though it "
|
| 401 |
+
"does not have valid or any HTTPS.",
|
| 402 |
+
)
|
| 403 |
+
|
| 404 |
+
|
| 405 |
+
def constraints() -> Option:
|
| 406 |
+
return Option(
|
| 407 |
+
"-c",
|
| 408 |
+
"--constraint",
|
| 409 |
+
dest="constraints",
|
| 410 |
+
action="append",
|
| 411 |
+
default=[],
|
| 412 |
+
metavar="file",
|
| 413 |
+
help="Constrain versions using the given constraints file. "
|
| 414 |
+
"This option can be used multiple times.",
|
| 415 |
+
)
|
| 416 |
+
|
| 417 |
+
|
| 418 |
+
def requirements() -> Option:
|
| 419 |
+
return Option(
|
| 420 |
+
"-r",
|
| 421 |
+
"--requirement",
|
| 422 |
+
dest="requirements",
|
| 423 |
+
action="append",
|
| 424 |
+
default=[],
|
| 425 |
+
metavar="file",
|
| 426 |
+
help="Install from the given requirements file. "
|
| 427 |
+
"This option can be used multiple times.",
|
| 428 |
+
)
|
| 429 |
+
|
| 430 |
+
|
| 431 |
+
def editable() -> Option:
|
| 432 |
+
return Option(
|
| 433 |
+
"-e",
|
| 434 |
+
"--editable",
|
| 435 |
+
dest="editables",
|
| 436 |
+
action="append",
|
| 437 |
+
default=[],
|
| 438 |
+
metavar="path/url",
|
| 439 |
+
help=(
|
| 440 |
+
"Install a project in editable mode (i.e. setuptools "
|
| 441 |
+
'"develop mode") from a local project path or a VCS url.'
|
| 442 |
+
),
|
| 443 |
+
)
|
| 444 |
+
|
| 445 |
+
|
| 446 |
+
def _handle_src(option: Option, opt_str: str, value: str, parser: OptionParser) -> None:
|
| 447 |
+
value = os.path.abspath(value)
|
| 448 |
+
setattr(parser.values, option.dest, value)
|
| 449 |
+
|
| 450 |
+
|
| 451 |
+
src: Callable[..., Option] = partial(
|
| 452 |
+
PipOption,
|
| 453 |
+
"--src",
|
| 454 |
+
"--source",
|
| 455 |
+
"--source-dir",
|
| 456 |
+
"--source-directory",
|
| 457 |
+
dest="src_dir",
|
| 458 |
+
type="path",
|
| 459 |
+
metavar="dir",
|
| 460 |
+
default=get_src_prefix(),
|
| 461 |
+
action="callback",
|
| 462 |
+
callback=_handle_src,
|
| 463 |
+
help="Directory to check out editable projects into. "
|
| 464 |
+
'The default in a virtualenv is "<venv path>/src". '
|
| 465 |
+
'The default for global installs is "<current dir>/src".',
|
| 466 |
+
)
|
| 467 |
+
|
| 468 |
+
|
| 469 |
+
def _get_format_control(values: Values, option: Option) -> Any:
|
| 470 |
+
"""Get a format_control object."""
|
| 471 |
+
return getattr(values, option.dest)
|
| 472 |
+
|
| 473 |
+
|
| 474 |
+
def _handle_no_binary(
|
| 475 |
+
option: Option, opt_str: str, value: str, parser: OptionParser
|
| 476 |
+
) -> None:
|
| 477 |
+
existing = _get_format_control(parser.values, option)
|
| 478 |
+
FormatControl.handle_mutual_excludes(
|
| 479 |
+
value,
|
| 480 |
+
existing.no_binary,
|
| 481 |
+
existing.only_binary,
|
| 482 |
+
)
|
| 483 |
+
|
| 484 |
+
|
| 485 |
+
def _handle_only_binary(
|
| 486 |
+
option: Option, opt_str: str, value: str, parser: OptionParser
|
| 487 |
+
) -> None:
|
| 488 |
+
existing = _get_format_control(parser.values, option)
|
| 489 |
+
FormatControl.handle_mutual_excludes(
|
| 490 |
+
value,
|
| 491 |
+
existing.only_binary,
|
| 492 |
+
existing.no_binary,
|
| 493 |
+
)
|
| 494 |
+
|
| 495 |
+
|
| 496 |
+
def no_binary() -> Option:
|
| 497 |
+
format_control = FormatControl(set(), set())
|
| 498 |
+
return Option(
|
| 499 |
+
"--no-binary",
|
| 500 |
+
dest="format_control",
|
| 501 |
+
action="callback",
|
| 502 |
+
callback=_handle_no_binary,
|
| 503 |
+
type="str",
|
| 504 |
+
default=format_control,
|
| 505 |
+
help="Do not use binary packages. Can be supplied multiple times, and "
|
| 506 |
+
'each time adds to the existing value. Accepts either ":all:" to '
|
| 507 |
+
'disable all binary packages, ":none:" to empty the set (notice '
|
| 508 |
+
"the colons), or one or more package names with commas between "
|
| 509 |
+
"them (no colons). Note that some packages are tricky to compile "
|
| 510 |
+
"and may fail to install when this option is used on them.",
|
| 511 |
+
)
|
| 512 |
+
|
| 513 |
+
|
| 514 |
+
def only_binary() -> Option:
|
| 515 |
+
format_control = FormatControl(set(), set())
|
| 516 |
+
return Option(
|
| 517 |
+
"--only-binary",
|
| 518 |
+
dest="format_control",
|
| 519 |
+
action="callback",
|
| 520 |
+
callback=_handle_only_binary,
|
| 521 |
+
type="str",
|
| 522 |
+
default=format_control,
|
| 523 |
+
help="Do not use source packages. Can be supplied multiple times, and "
|
| 524 |
+
'each time adds to the existing value. Accepts either ":all:" to '
|
| 525 |
+
'disable all source packages, ":none:" to empty the set, or one '
|
| 526 |
+
"or more package names with commas between them. Packages "
|
| 527 |
+
"without binary distributions will fail to install when this "
|
| 528 |
+
"option is used on them.",
|
| 529 |
+
)
|
| 530 |
+
|
| 531 |
+
|
| 532 |
+
platforms: Callable[..., Option] = partial(
|
| 533 |
+
Option,
|
| 534 |
+
"--platform",
|
| 535 |
+
dest="platforms",
|
| 536 |
+
metavar="platform",
|
| 537 |
+
action="append",
|
| 538 |
+
default=None,
|
| 539 |
+
help=(
|
| 540 |
+
"Only use wheels compatible with <platform>. Defaults to the "
|
| 541 |
+
"platform of the running system. Use this option multiple times to "
|
| 542 |
+
"specify multiple platforms supported by the target interpreter."
|
| 543 |
+
),
|
| 544 |
+
)
|
| 545 |
+
|
| 546 |
+
|
| 547 |
+
# This was made a separate function for unit-testing purposes.
|
| 548 |
+
def _convert_python_version(value: str) -> Tuple[Tuple[int, ...], Optional[str]]:
|
| 549 |
+
"""
|
| 550 |
+
Convert a version string like "3", "37", or "3.7.3" into a tuple of ints.
|
| 551 |
+
|
| 552 |
+
:return: A 2-tuple (version_info, error_msg), where `error_msg` is
|
| 553 |
+
non-None if and only if there was a parsing error.
|
| 554 |
+
"""
|
| 555 |
+
if not value:
|
| 556 |
+
# The empty string is the same as not providing a value.
|
| 557 |
+
return (None, None)
|
| 558 |
+
|
| 559 |
+
parts = value.split(".")
|
| 560 |
+
if len(parts) > 3:
|
| 561 |
+
return ((), "at most three version parts are allowed")
|
| 562 |
+
|
| 563 |
+
if len(parts) == 1:
|
| 564 |
+
# Then we are in the case of "3" or "37".
|
| 565 |
+
value = parts[0]
|
| 566 |
+
if len(value) > 1:
|
| 567 |
+
parts = [value[0], value[1:]]
|
| 568 |
+
|
| 569 |
+
try:
|
| 570 |
+
version_info = tuple(int(part) for part in parts)
|
| 571 |
+
except ValueError:
|
| 572 |
+
return ((), "each version part must be an integer")
|
| 573 |
+
|
| 574 |
+
return (version_info, None)
|
| 575 |
+
|
| 576 |
+
|
| 577 |
+
def _handle_python_version(
|
| 578 |
+
option: Option, opt_str: str, value: str, parser: OptionParser
|
| 579 |
+
) -> None:
|
| 580 |
+
"""
|
| 581 |
+
Handle a provided --python-version value.
|
| 582 |
+
"""
|
| 583 |
+
version_info, error_msg = _convert_python_version(value)
|
| 584 |
+
if error_msg is not None:
|
| 585 |
+
msg = f"invalid --python-version value: {value!r}: {error_msg}"
|
| 586 |
+
raise_option_error(parser, option=option, msg=msg)
|
| 587 |
+
|
| 588 |
+
parser.values.python_version = version_info
|
| 589 |
+
|
| 590 |
+
|
| 591 |
+
python_version: Callable[..., Option] = partial(
|
| 592 |
+
Option,
|
| 593 |
+
"--python-version",
|
| 594 |
+
dest="python_version",
|
| 595 |
+
metavar="python_version",
|
| 596 |
+
action="callback",
|
| 597 |
+
callback=_handle_python_version,
|
| 598 |
+
type="str",
|
| 599 |
+
default=None,
|
| 600 |
+
help=dedent(
|
| 601 |
+
"""\
|
| 602 |
+
The Python interpreter version to use for wheel and "Requires-Python"
|
| 603 |
+
compatibility checks. Defaults to a version derived from the running
|
| 604 |
+
interpreter. The version can be specified using up to three dot-separated
|
| 605 |
+
integers (e.g. "3" for 3.0.0, "3.7" for 3.7.0, or "3.7.3"). A major-minor
|
| 606 |
+
version can also be given as a string without dots (e.g. "37" for 3.7.0).
|
| 607 |
+
"""
|
| 608 |
+
),
|
| 609 |
+
)
|
| 610 |
+
|
| 611 |
+
|
| 612 |
+
implementation: Callable[..., Option] = partial(
|
| 613 |
+
Option,
|
| 614 |
+
"--implementation",
|
| 615 |
+
dest="implementation",
|
| 616 |
+
metavar="implementation",
|
| 617 |
+
default=None,
|
| 618 |
+
help=(
|
| 619 |
+
"Only use wheels compatible with Python "
|
| 620 |
+
"implementation <implementation>, e.g. 'pp', 'jy', 'cp', "
|
| 621 |
+
" or 'ip'. If not specified, then the current "
|
| 622 |
+
"interpreter implementation is used. Use 'py' to force "
|
| 623 |
+
"implementation-agnostic wheels."
|
| 624 |
+
),
|
| 625 |
+
)
|
| 626 |
+
|
| 627 |
+
|
| 628 |
+
abis: Callable[..., Option] = partial(
|
| 629 |
+
Option,
|
| 630 |
+
"--abi",
|
| 631 |
+
dest="abis",
|
| 632 |
+
metavar="abi",
|
| 633 |
+
action="append",
|
| 634 |
+
default=None,
|
| 635 |
+
help=(
|
| 636 |
+
"Only use wheels compatible with Python abi <abi>, e.g. 'pypy_41'. "
|
| 637 |
+
"If not specified, then the current interpreter abi tag is used. "
|
| 638 |
+
"Use this option multiple times to specify multiple abis supported "
|
| 639 |
+
"by the target interpreter. Generally you will need to specify "
|
| 640 |
+
"--implementation, --platform, and --python-version when using this "
|
| 641 |
+
"option."
|
| 642 |
+
),
|
| 643 |
+
)
|
| 644 |
+
|
| 645 |
+
|
| 646 |
+
def add_target_python_options(cmd_opts: OptionGroup) -> None:
|
| 647 |
+
cmd_opts.add_option(platforms())
|
| 648 |
+
cmd_opts.add_option(python_version())
|
| 649 |
+
cmd_opts.add_option(implementation())
|
| 650 |
+
cmd_opts.add_option(abis())
|
| 651 |
+
|
| 652 |
+
|
| 653 |
+
def make_target_python(options: Values) -> TargetPython:
|
| 654 |
+
target_python = TargetPython(
|
| 655 |
+
platforms=options.platforms,
|
| 656 |
+
py_version_info=options.python_version,
|
| 657 |
+
abis=options.abis,
|
| 658 |
+
implementation=options.implementation,
|
| 659 |
+
)
|
| 660 |
+
|
| 661 |
+
return target_python
|
| 662 |
+
|
| 663 |
+
|
| 664 |
+
def prefer_binary() -> Option:
|
| 665 |
+
return Option(
|
| 666 |
+
"--prefer-binary",
|
| 667 |
+
dest="prefer_binary",
|
| 668 |
+
action="store_true",
|
| 669 |
+
default=False,
|
| 670 |
+
help=(
|
| 671 |
+
"Prefer binary packages over source packages, even if the "
|
| 672 |
+
"source packages are newer."
|
| 673 |
+
),
|
| 674 |
+
)
|
| 675 |
+
|
| 676 |
+
|
| 677 |
+
cache_dir: Callable[..., Option] = partial(
|
| 678 |
+
PipOption,
|
| 679 |
+
"--cache-dir",
|
| 680 |
+
dest="cache_dir",
|
| 681 |
+
default=USER_CACHE_DIR,
|
| 682 |
+
metavar="dir",
|
| 683 |
+
type="path",
|
| 684 |
+
help="Store the cache data in <dir>.",
|
| 685 |
+
)
|
| 686 |
+
|
| 687 |
+
|
| 688 |
+
def _handle_no_cache_dir(
|
| 689 |
+
option: Option, opt: str, value: str, parser: OptionParser
|
| 690 |
+
) -> None:
|
| 691 |
+
"""
|
| 692 |
+
Process a value provided for the --no-cache-dir option.
|
| 693 |
+
|
| 694 |
+
This is an optparse.Option callback for the --no-cache-dir option.
|
| 695 |
+
"""
|
| 696 |
+
# The value argument will be None if --no-cache-dir is passed via the
|
| 697 |
+
# command-line, since the option doesn't accept arguments. However,
|
| 698 |
+
# the value can be non-None if the option is triggered e.g. by an
|
| 699 |
+
# environment variable, like PIP_NO_CACHE_DIR=true.
|
| 700 |
+
if value is not None:
|
| 701 |
+
# Then parse the string value to get argument error-checking.
|
| 702 |
+
try:
|
| 703 |
+
strtobool(value)
|
| 704 |
+
except ValueError as exc:
|
| 705 |
+
raise_option_error(parser, option=option, msg=str(exc))
|
| 706 |
+
|
| 707 |
+
# Originally, setting PIP_NO_CACHE_DIR to a value that strtobool()
|
| 708 |
+
# converted to 0 (like "false" or "no") caused cache_dir to be disabled
|
| 709 |
+
# rather than enabled (logic would say the latter). Thus, we disable
|
| 710 |
+
# the cache directory not just on values that parse to True, but (for
|
| 711 |
+
# backwards compatibility reasons) also on values that parse to False.
|
| 712 |
+
# In other words, always set it to False if the option is provided in
|
| 713 |
+
# some (valid) form.
|
| 714 |
+
parser.values.cache_dir = False
|
| 715 |
+
|
| 716 |
+
|
| 717 |
+
no_cache: Callable[..., Option] = partial(
|
| 718 |
+
Option,
|
| 719 |
+
"--no-cache-dir",
|
| 720 |
+
dest="cache_dir",
|
| 721 |
+
action="callback",
|
| 722 |
+
callback=_handle_no_cache_dir,
|
| 723 |
+
help="Disable the cache.",
|
| 724 |
+
)
|
| 725 |
+
|
| 726 |
+
no_deps: Callable[..., Option] = partial(
|
| 727 |
+
Option,
|
| 728 |
+
"--no-deps",
|
| 729 |
+
"--no-dependencies",
|
| 730 |
+
dest="ignore_dependencies",
|
| 731 |
+
action="store_true",
|
| 732 |
+
default=False,
|
| 733 |
+
help="Don't install package dependencies.",
|
| 734 |
+
)
|
| 735 |
+
|
| 736 |
+
ignore_requires_python: Callable[..., Option] = partial(
|
| 737 |
+
Option,
|
| 738 |
+
"--ignore-requires-python",
|
| 739 |
+
dest="ignore_requires_python",
|
| 740 |
+
action="store_true",
|
| 741 |
+
help="Ignore the Requires-Python information.",
|
| 742 |
+
)
|
| 743 |
+
|
| 744 |
+
no_build_isolation: Callable[..., Option] = partial(
|
| 745 |
+
Option,
|
| 746 |
+
"--no-build-isolation",
|
| 747 |
+
dest="build_isolation",
|
| 748 |
+
action="store_false",
|
| 749 |
+
default=True,
|
| 750 |
+
help="Disable isolation when building a modern source distribution. "
|
| 751 |
+
"Build dependencies specified by PEP 518 must be already installed "
|
| 752 |
+
"if this option is used.",
|
| 753 |
+
)
|
| 754 |
+
|
| 755 |
+
check_build_deps: Callable[..., Option] = partial(
|
| 756 |
+
Option,
|
| 757 |
+
"--check-build-dependencies",
|
| 758 |
+
dest="check_build_deps",
|
| 759 |
+
action="store_true",
|
| 760 |
+
default=False,
|
| 761 |
+
help="Check the build dependencies when PEP517 is used.",
|
| 762 |
+
)
|
| 763 |
+
|
| 764 |
+
|
| 765 |
+
def _handle_no_use_pep517(
|
| 766 |
+
option: Option, opt: str, value: str, parser: OptionParser
|
| 767 |
+
) -> None:
|
| 768 |
+
"""
|
| 769 |
+
Process a value provided for the --no-use-pep517 option.
|
| 770 |
+
|
| 771 |
+
This is an optparse.Option callback for the no_use_pep517 option.
|
| 772 |
+
"""
|
| 773 |
+
# Since --no-use-pep517 doesn't accept arguments, the value argument
|
| 774 |
+
# will be None if --no-use-pep517 is passed via the command-line.
|
| 775 |
+
# However, the value can be non-None if the option is triggered e.g.
|
| 776 |
+
# by an environment variable, for example "PIP_NO_USE_PEP517=true".
|
| 777 |
+
if value is not None:
|
| 778 |
+
msg = """A value was passed for --no-use-pep517,
|
| 779 |
+
probably using either the PIP_NO_USE_PEP517 environment variable
|
| 780 |
+
or the "no-use-pep517" config file option. Use an appropriate value
|
| 781 |
+
of the PIP_USE_PEP517 environment variable or the "use-pep517"
|
| 782 |
+
config file option instead.
|
| 783 |
+
"""
|
| 784 |
+
raise_option_error(parser, option=option, msg=msg)
|
| 785 |
+
|
| 786 |
+
# If user doesn't wish to use pep517, we check if setuptools and wheel are installed
|
| 787 |
+
# and raise error if it is not.
|
| 788 |
+
packages = ("setuptools", "wheel")
|
| 789 |
+
if not all(importlib.util.find_spec(package) for package in packages):
|
| 790 |
+
msg = (
|
| 791 |
+
f"It is not possible to use --no-use-pep517 "
|
| 792 |
+
f"without {' and '.join(packages)} installed."
|
| 793 |
+
)
|
| 794 |
+
raise_option_error(parser, option=option, msg=msg)
|
| 795 |
+
|
| 796 |
+
# Otherwise, --no-use-pep517 was passed via the command-line.
|
| 797 |
+
parser.values.use_pep517 = False
|
| 798 |
+
|
| 799 |
+
|
| 800 |
+
use_pep517: Any = partial(
|
| 801 |
+
Option,
|
| 802 |
+
"--use-pep517",
|
| 803 |
+
dest="use_pep517",
|
| 804 |
+
action="store_true",
|
| 805 |
+
default=None,
|
| 806 |
+
help="Use PEP 517 for building source distributions "
|
| 807 |
+
"(use --no-use-pep517 to force legacy behaviour).",
|
| 808 |
+
)
|
| 809 |
+
|
| 810 |
+
no_use_pep517: Any = partial(
|
| 811 |
+
Option,
|
| 812 |
+
"--no-use-pep517",
|
| 813 |
+
dest="use_pep517",
|
| 814 |
+
action="callback",
|
| 815 |
+
callback=_handle_no_use_pep517,
|
| 816 |
+
default=None,
|
| 817 |
+
help=SUPPRESS_HELP,
|
| 818 |
+
)
|
| 819 |
+
|
| 820 |
+
|
| 821 |
+
def _handle_config_settings(
|
| 822 |
+
option: Option, opt_str: str, value: str, parser: OptionParser
|
| 823 |
+
) -> None:
|
| 824 |
+
key, sep, val = value.partition("=")
|
| 825 |
+
if sep != "=":
|
| 826 |
+
parser.error(f"Arguments to {opt_str} must be of the form KEY=VAL")
|
| 827 |
+
dest = getattr(parser.values, option.dest)
|
| 828 |
+
if dest is None:
|
| 829 |
+
dest = {}
|
| 830 |
+
setattr(parser.values, option.dest, dest)
|
| 831 |
+
if key in dest:
|
| 832 |
+
if isinstance(dest[key], list):
|
| 833 |
+
dest[key].append(val)
|
| 834 |
+
else:
|
| 835 |
+
dest[key] = [dest[key], val]
|
| 836 |
+
else:
|
| 837 |
+
dest[key] = val
|
| 838 |
+
|
| 839 |
+
|
| 840 |
+
config_settings: Callable[..., Option] = partial(
|
| 841 |
+
Option,
|
| 842 |
+
"-C",
|
| 843 |
+
"--config-settings",
|
| 844 |
+
dest="config_settings",
|
| 845 |
+
type=str,
|
| 846 |
+
action="callback",
|
| 847 |
+
callback=_handle_config_settings,
|
| 848 |
+
metavar="settings",
|
| 849 |
+
help="Configuration settings to be passed to the PEP 517 build backend. "
|
| 850 |
+
"Settings take the form KEY=VALUE. Use multiple --config-settings options "
|
| 851 |
+
"to pass multiple keys to the backend.",
|
| 852 |
+
)
|
| 853 |
+
|
| 854 |
+
build_options: Callable[..., Option] = partial(
|
| 855 |
+
Option,
|
| 856 |
+
"--build-option",
|
| 857 |
+
dest="build_options",
|
| 858 |
+
metavar="options",
|
| 859 |
+
action="append",
|
| 860 |
+
help="Extra arguments to be supplied to 'setup.py bdist_wheel'.",
|
| 861 |
+
)
|
| 862 |
+
|
| 863 |
+
global_options: Callable[..., Option] = partial(
|
| 864 |
+
Option,
|
| 865 |
+
"--global-option",
|
| 866 |
+
dest="global_options",
|
| 867 |
+
action="append",
|
| 868 |
+
metavar="options",
|
| 869 |
+
help="Extra global options to be supplied to the setup.py "
|
| 870 |
+
"call before the install or bdist_wheel command.",
|
| 871 |
+
)
|
| 872 |
+
|
| 873 |
+
no_clean: Callable[..., Option] = partial(
|
| 874 |
+
Option,
|
| 875 |
+
"--no-clean",
|
| 876 |
+
action="store_true",
|
| 877 |
+
default=False,
|
| 878 |
+
help="Don't clean up build directories.",
|
| 879 |
+
)
|
| 880 |
+
|
| 881 |
+
pre: Callable[..., Option] = partial(
|
| 882 |
+
Option,
|
| 883 |
+
"--pre",
|
| 884 |
+
action="store_true",
|
| 885 |
+
default=False,
|
| 886 |
+
help="Include pre-release and development versions. By default, "
|
| 887 |
+
"pip only finds stable versions.",
|
| 888 |
+
)
|
| 889 |
+
|
| 890 |
+
disable_pip_version_check: Callable[..., Option] = partial(
|
| 891 |
+
Option,
|
| 892 |
+
"--disable-pip-version-check",
|
| 893 |
+
dest="disable_pip_version_check",
|
| 894 |
+
action="store_true",
|
| 895 |
+
default=False,
|
| 896 |
+
help="Don't periodically check PyPI to determine whether a new version "
|
| 897 |
+
"of pip is available for download. Implied with --no-index.",
|
| 898 |
+
)
|
| 899 |
+
|
| 900 |
+
root_user_action: Callable[..., Option] = partial(
|
| 901 |
+
Option,
|
| 902 |
+
"--root-user-action",
|
| 903 |
+
dest="root_user_action",
|
| 904 |
+
default="warn",
|
| 905 |
+
choices=["warn", "ignore"],
|
| 906 |
+
help="Action if pip is run as a root user. By default, a warning message is shown.",
|
| 907 |
+
)
|
| 908 |
+
|
| 909 |
+
|
| 910 |
+
def _handle_merge_hash(
|
| 911 |
+
option: Option, opt_str: str, value: str, parser: OptionParser
|
| 912 |
+
) -> None:
|
| 913 |
+
"""Given a value spelled "algo:digest", append the digest to a list
|
| 914 |
+
pointed to in a dict by the algo name."""
|
| 915 |
+
if not parser.values.hashes:
|
| 916 |
+
parser.values.hashes = {}
|
| 917 |
+
try:
|
| 918 |
+
algo, digest = value.split(":", 1)
|
| 919 |
+
except ValueError:
|
| 920 |
+
parser.error(
|
| 921 |
+
f"Arguments to {opt_str} must be a hash name "
|
| 922 |
+
"followed by a value, like --hash=sha256:"
|
| 923 |
+
"abcde..."
|
| 924 |
+
)
|
| 925 |
+
if algo not in STRONG_HASHES:
|
| 926 |
+
parser.error(
|
| 927 |
+
"Allowed hash algorithms for {} are {}.".format(
|
| 928 |
+
opt_str, ", ".join(STRONG_HASHES)
|
| 929 |
+
)
|
| 930 |
+
)
|
| 931 |
+
parser.values.hashes.setdefault(algo, []).append(digest)
|
| 932 |
+
|
| 933 |
+
|
| 934 |
+
hash: Callable[..., Option] = partial(
|
| 935 |
+
Option,
|
| 936 |
+
"--hash",
|
| 937 |
+
# Hash values eventually end up in InstallRequirement.hashes due to
|
| 938 |
+
# __dict__ copying in process_line().
|
| 939 |
+
dest="hashes",
|
| 940 |
+
action="callback",
|
| 941 |
+
callback=_handle_merge_hash,
|
| 942 |
+
type="string",
|
| 943 |
+
help="Verify that the package's archive matches this "
|
| 944 |
+
"hash before installing. Example: --hash=sha256:abcdef...",
|
| 945 |
+
)
|
| 946 |
+
|
| 947 |
+
|
| 948 |
+
require_hashes: Callable[..., Option] = partial(
|
| 949 |
+
Option,
|
| 950 |
+
"--require-hashes",
|
| 951 |
+
dest="require_hashes",
|
| 952 |
+
action="store_true",
|
| 953 |
+
default=False,
|
| 954 |
+
help="Require a hash to check each requirement against, for "
|
| 955 |
+
"repeatable installs. This option is implied when any package in a "
|
| 956 |
+
"requirements file has a --hash option.",
|
| 957 |
+
)
|
| 958 |
+
|
| 959 |
+
|
| 960 |
+
list_path: Callable[..., Option] = partial(
|
| 961 |
+
PipOption,
|
| 962 |
+
"--path",
|
| 963 |
+
dest="path",
|
| 964 |
+
type="path",
|
| 965 |
+
action="append",
|
| 966 |
+
help="Restrict to the specified installation path for listing "
|
| 967 |
+
"packages (can be used multiple times).",
|
| 968 |
+
)
|
| 969 |
+
|
| 970 |
+
|
| 971 |
+
def check_list_path_option(options: Values) -> None:
|
| 972 |
+
if options.path and (options.user or options.local):
|
| 973 |
+
raise CommandError("Cannot combine '--path' with '--user' or '--local'")
|
| 974 |
+
|
| 975 |
+
|
| 976 |
+
list_exclude: Callable[..., Option] = partial(
|
| 977 |
+
PipOption,
|
| 978 |
+
"--exclude",
|
| 979 |
+
dest="excludes",
|
| 980 |
+
action="append",
|
| 981 |
+
metavar="package",
|
| 982 |
+
type="package_name",
|
| 983 |
+
help="Exclude specified package from the output",
|
| 984 |
+
)
|
| 985 |
+
|
| 986 |
+
|
| 987 |
+
no_python_version_warning: Callable[..., Option] = partial(
|
| 988 |
+
Option,
|
| 989 |
+
"--no-python-version-warning",
|
| 990 |
+
dest="no_python_version_warning",
|
| 991 |
+
action="store_true",
|
| 992 |
+
default=False,
|
| 993 |
+
help="Silence deprecation warnings for upcoming unsupported Pythons.",
|
| 994 |
+
)
|
| 995 |
+
|
| 996 |
+
|
| 997 |
+
# Features that are now always on. A warning is printed if they are used.
|
| 998 |
+
ALWAYS_ENABLED_FEATURES = [
|
| 999 |
+
"no-binary-enable-wheel-cache", # always on since 23.1
|
| 1000 |
+
]
|
| 1001 |
+
|
| 1002 |
+
use_new_feature: Callable[..., Option] = partial(
|
| 1003 |
+
Option,
|
| 1004 |
+
"--use-feature",
|
| 1005 |
+
dest="features_enabled",
|
| 1006 |
+
metavar="feature",
|
| 1007 |
+
action="append",
|
| 1008 |
+
default=[],
|
| 1009 |
+
choices=[
|
| 1010 |
+
"fast-deps",
|
| 1011 |
+
"truststore",
|
| 1012 |
+
]
|
| 1013 |
+
+ ALWAYS_ENABLED_FEATURES,
|
| 1014 |
+
help="Enable new functionality, that may be backward incompatible.",
|
| 1015 |
+
)
|
| 1016 |
+
|
| 1017 |
+
use_deprecated_feature: Callable[..., Option] = partial(
|
| 1018 |
+
Option,
|
| 1019 |
+
"--use-deprecated",
|
| 1020 |
+
dest="deprecated_features_enabled",
|
| 1021 |
+
metavar="feature",
|
| 1022 |
+
action="append",
|
| 1023 |
+
default=[],
|
| 1024 |
+
choices=[
|
| 1025 |
+
"legacy-resolver",
|
| 1026 |
+
],
|
| 1027 |
+
help=("Enable deprecated functionality, that will be removed in the future."),
|
| 1028 |
+
)
|
| 1029 |
+
|
| 1030 |
+
|
| 1031 |
+
##########
|
| 1032 |
+
# groups #
|
| 1033 |
+
##########
|
| 1034 |
+
|
| 1035 |
+
general_group: Dict[str, Any] = {
|
| 1036 |
+
"name": "General Options",
|
| 1037 |
+
"options": [
|
| 1038 |
+
help_,
|
| 1039 |
+
debug_mode,
|
| 1040 |
+
isolated_mode,
|
| 1041 |
+
require_virtualenv,
|
| 1042 |
+
python,
|
| 1043 |
+
verbose,
|
| 1044 |
+
version,
|
| 1045 |
+
quiet,
|
| 1046 |
+
log,
|
| 1047 |
+
no_input,
|
| 1048 |
+
keyring_provider,
|
| 1049 |
+
proxy,
|
| 1050 |
+
retries,
|
| 1051 |
+
timeout,
|
| 1052 |
+
exists_action,
|
| 1053 |
+
trusted_host,
|
| 1054 |
+
cert,
|
| 1055 |
+
client_cert,
|
| 1056 |
+
cache_dir,
|
| 1057 |
+
no_cache,
|
| 1058 |
+
disable_pip_version_check,
|
| 1059 |
+
no_color,
|
| 1060 |
+
no_python_version_warning,
|
| 1061 |
+
use_new_feature,
|
| 1062 |
+
use_deprecated_feature,
|
| 1063 |
+
],
|
| 1064 |
+
}
|
| 1065 |
+
|
| 1066 |
+
index_group: Dict[str, Any] = {
|
| 1067 |
+
"name": "Package Index Options",
|
| 1068 |
+
"options": [
|
| 1069 |
+
index_url,
|
| 1070 |
+
extra_index_url,
|
| 1071 |
+
no_index,
|
| 1072 |
+
find_links,
|
| 1073 |
+
],
|
| 1074 |
+
}
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/cli/command_context.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from contextlib import ExitStack, contextmanager
|
| 2 |
+
from typing import ContextManager, Generator, TypeVar
|
| 3 |
+
|
| 4 |
+
_T = TypeVar("_T", covariant=True)
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
class CommandContextMixIn:
|
| 8 |
+
def __init__(self) -> None:
|
| 9 |
+
super().__init__()
|
| 10 |
+
self._in_main_context = False
|
| 11 |
+
self._main_context = ExitStack()
|
| 12 |
+
|
| 13 |
+
@contextmanager
|
| 14 |
+
def main_context(self) -> Generator[None, None, None]:
|
| 15 |
+
assert not self._in_main_context
|
| 16 |
+
|
| 17 |
+
self._in_main_context = True
|
| 18 |
+
try:
|
| 19 |
+
with self._main_context:
|
| 20 |
+
yield
|
| 21 |
+
finally:
|
| 22 |
+
self._in_main_context = False
|
| 23 |
+
|
| 24 |
+
def enter_context(self, context_provider: ContextManager[_T]) -> _T:
|
| 25 |
+
assert self._in_main_context
|
| 26 |
+
|
| 27 |
+
return self._main_context.enter_context(context_provider)
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/cli/main.py
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Primary application entrypoint.
|
| 2 |
+
"""
|
| 3 |
+
import locale
|
| 4 |
+
import logging
|
| 5 |
+
import os
|
| 6 |
+
import sys
|
| 7 |
+
import warnings
|
| 8 |
+
from typing import List, Optional
|
| 9 |
+
|
| 10 |
+
from pip._internal.cli.autocompletion import autocomplete
|
| 11 |
+
from pip._internal.cli.main_parser import parse_command
|
| 12 |
+
from pip._internal.commands import create_command
|
| 13 |
+
from pip._internal.exceptions import PipError
|
| 14 |
+
from pip._internal.utils import deprecation
|
| 15 |
+
|
| 16 |
+
logger = logging.getLogger(__name__)
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
# Do not import and use main() directly! Using it directly is actively
|
| 20 |
+
# discouraged by pip's maintainers. The name, location and behavior of
|
| 21 |
+
# this function is subject to change, so calling it directly is not
|
| 22 |
+
# portable across different pip versions.
|
| 23 |
+
|
| 24 |
+
# In addition, running pip in-process is unsupported and unsafe. This is
|
| 25 |
+
# elaborated in detail at
|
| 26 |
+
# https://pip.pypa.io/en/stable/user_guide/#using-pip-from-your-program.
|
| 27 |
+
# That document also provides suggestions that should work for nearly
|
| 28 |
+
# all users that are considering importing and using main() directly.
|
| 29 |
+
|
| 30 |
+
# However, we know that certain users will still want to invoke pip
|
| 31 |
+
# in-process. If you understand and accept the implications of using pip
|
| 32 |
+
# in an unsupported manner, the best approach is to use runpy to avoid
|
| 33 |
+
# depending on the exact location of this entry point.
|
| 34 |
+
|
| 35 |
+
# The following example shows how to use runpy to invoke pip in that
|
| 36 |
+
# case:
|
| 37 |
+
#
|
| 38 |
+
# sys.argv = ["pip", your, args, here]
|
| 39 |
+
# runpy.run_module("pip", run_name="__main__")
|
| 40 |
+
#
|
| 41 |
+
# Note that this will exit the process after running, unlike a direct
|
| 42 |
+
# call to main. As it is not safe to do any processing after calling
|
| 43 |
+
# main, this should not be an issue in practice.
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
def main(args: Optional[List[str]] = None) -> int:
|
| 47 |
+
if args is None:
|
| 48 |
+
args = sys.argv[1:]
|
| 49 |
+
|
| 50 |
+
# Suppress the pkg_resources deprecation warning
|
| 51 |
+
# Note - we use a module of .*pkg_resources to cover
|
| 52 |
+
# the normal case (pip._vendor.pkg_resources) and the
|
| 53 |
+
# devendored case (a bare pkg_resources)
|
| 54 |
+
warnings.filterwarnings(
|
| 55 |
+
action="ignore", category=DeprecationWarning, module=".*pkg_resources"
|
| 56 |
+
)
|
| 57 |
+
|
| 58 |
+
# Configure our deprecation warnings to be sent through loggers
|
| 59 |
+
deprecation.install_warning_logger()
|
| 60 |
+
|
| 61 |
+
autocomplete()
|
| 62 |
+
|
| 63 |
+
try:
|
| 64 |
+
cmd_name, cmd_args = parse_command(args)
|
| 65 |
+
except PipError as exc:
|
| 66 |
+
sys.stderr.write(f"ERROR: {exc}")
|
| 67 |
+
sys.stderr.write(os.linesep)
|
| 68 |
+
sys.exit(1)
|
| 69 |
+
|
| 70 |
+
# Needed for locale.getpreferredencoding(False) to work
|
| 71 |
+
# in pip._internal.utils.encoding.auto_decode
|
| 72 |
+
try:
|
| 73 |
+
locale.setlocale(locale.LC_ALL, "")
|
| 74 |
+
except locale.Error as e:
|
| 75 |
+
# setlocale can apparently crash if locale are uninitialized
|
| 76 |
+
logger.debug("Ignoring error %s when setting locale", e)
|
| 77 |
+
command = create_command(cmd_name, isolated=("--isolated" in cmd_args))
|
| 78 |
+
|
| 79 |
+
return command.main(cmd_args)
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/cli/main_parser.py
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""A single place for constructing and exposing the main parser
|
| 2 |
+
"""
|
| 3 |
+
|
| 4 |
+
import os
|
| 5 |
+
import subprocess
|
| 6 |
+
import sys
|
| 7 |
+
from typing import List, Optional, Tuple
|
| 8 |
+
|
| 9 |
+
from pip._internal.build_env import get_runnable_pip
|
| 10 |
+
from pip._internal.cli import cmdoptions
|
| 11 |
+
from pip._internal.cli.parser import ConfigOptionParser, UpdatingDefaultsHelpFormatter
|
| 12 |
+
from pip._internal.commands import commands_dict, get_similar_commands
|
| 13 |
+
from pip._internal.exceptions import CommandError
|
| 14 |
+
from pip._internal.utils.misc import get_pip_version, get_prog
|
| 15 |
+
|
| 16 |
+
__all__ = ["create_main_parser", "parse_command"]
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
def create_main_parser() -> ConfigOptionParser:
|
| 20 |
+
"""Creates and returns the main parser for pip's CLI"""
|
| 21 |
+
|
| 22 |
+
parser = ConfigOptionParser(
|
| 23 |
+
usage="\n%prog <command> [options]",
|
| 24 |
+
add_help_option=False,
|
| 25 |
+
formatter=UpdatingDefaultsHelpFormatter(),
|
| 26 |
+
name="global",
|
| 27 |
+
prog=get_prog(),
|
| 28 |
+
)
|
| 29 |
+
parser.disable_interspersed_args()
|
| 30 |
+
|
| 31 |
+
parser.version = get_pip_version()
|
| 32 |
+
|
| 33 |
+
# add the general options
|
| 34 |
+
gen_opts = cmdoptions.make_option_group(cmdoptions.general_group, parser)
|
| 35 |
+
parser.add_option_group(gen_opts)
|
| 36 |
+
|
| 37 |
+
# so the help formatter knows
|
| 38 |
+
parser.main = True # type: ignore
|
| 39 |
+
|
| 40 |
+
# create command listing for description
|
| 41 |
+
description = [""] + [
|
| 42 |
+
f"{name:27} {command_info.summary}"
|
| 43 |
+
for name, command_info in commands_dict.items()
|
| 44 |
+
]
|
| 45 |
+
parser.description = "\n".join(description)
|
| 46 |
+
|
| 47 |
+
return parser
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def identify_python_interpreter(python: str) -> Optional[str]:
|
| 51 |
+
# If the named file exists, use it.
|
| 52 |
+
# If it's a directory, assume it's a virtual environment and
|
| 53 |
+
# look for the environment's Python executable.
|
| 54 |
+
if os.path.exists(python):
|
| 55 |
+
if os.path.isdir(python):
|
| 56 |
+
# bin/python for Unix, Scripts/python.exe for Windows
|
| 57 |
+
# Try both in case of odd cases like cygwin.
|
| 58 |
+
for exe in ("bin/python", "Scripts/python.exe"):
|
| 59 |
+
py = os.path.join(python, exe)
|
| 60 |
+
if os.path.exists(py):
|
| 61 |
+
return py
|
| 62 |
+
else:
|
| 63 |
+
return python
|
| 64 |
+
|
| 65 |
+
# Could not find the interpreter specified
|
| 66 |
+
return None
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
def parse_command(args: List[str]) -> Tuple[str, List[str]]:
|
| 70 |
+
parser = create_main_parser()
|
| 71 |
+
|
| 72 |
+
# Note: parser calls disable_interspersed_args(), so the result of this
|
| 73 |
+
# call is to split the initial args into the general options before the
|
| 74 |
+
# subcommand and everything else.
|
| 75 |
+
# For example:
|
| 76 |
+
# args: ['--timeout=5', 'install', '--user', 'INITools']
|
| 77 |
+
# general_options: ['--timeout==5']
|
| 78 |
+
# args_else: ['install', '--user', 'INITools']
|
| 79 |
+
general_options, args_else = parser.parse_args(args)
|
| 80 |
+
|
| 81 |
+
# --python
|
| 82 |
+
if general_options.python and "_PIP_RUNNING_IN_SUBPROCESS" not in os.environ:
|
| 83 |
+
# Re-invoke pip using the specified Python interpreter
|
| 84 |
+
interpreter = identify_python_interpreter(general_options.python)
|
| 85 |
+
if interpreter is None:
|
| 86 |
+
raise CommandError(
|
| 87 |
+
f"Could not locate Python interpreter {general_options.python}"
|
| 88 |
+
)
|
| 89 |
+
|
| 90 |
+
pip_cmd = [
|
| 91 |
+
interpreter,
|
| 92 |
+
get_runnable_pip(),
|
| 93 |
+
]
|
| 94 |
+
pip_cmd.extend(args)
|
| 95 |
+
|
| 96 |
+
# Set a flag so the child doesn't re-invoke itself, causing
|
| 97 |
+
# an infinite loop.
|
| 98 |
+
os.environ["_PIP_RUNNING_IN_SUBPROCESS"] = "1"
|
| 99 |
+
returncode = 0
|
| 100 |
+
try:
|
| 101 |
+
proc = subprocess.run(pip_cmd)
|
| 102 |
+
returncode = proc.returncode
|
| 103 |
+
except (subprocess.SubprocessError, OSError) as exc:
|
| 104 |
+
raise CommandError(f"Failed to run pip under {interpreter}: {exc}")
|
| 105 |
+
sys.exit(returncode)
|
| 106 |
+
|
| 107 |
+
# --version
|
| 108 |
+
if general_options.version:
|
| 109 |
+
sys.stdout.write(parser.version)
|
| 110 |
+
sys.stdout.write(os.linesep)
|
| 111 |
+
sys.exit()
|
| 112 |
+
|
| 113 |
+
# pip || pip help -> print_help()
|
| 114 |
+
if not args_else or (args_else[0] == "help" and len(args_else) == 1):
|
| 115 |
+
parser.print_help()
|
| 116 |
+
sys.exit()
|
| 117 |
+
|
| 118 |
+
# the subcommand name
|
| 119 |
+
cmd_name = args_else[0]
|
| 120 |
+
|
| 121 |
+
if cmd_name not in commands_dict:
|
| 122 |
+
guess = get_similar_commands(cmd_name)
|
| 123 |
+
|
| 124 |
+
msg = [f'unknown command "{cmd_name}"']
|
| 125 |
+
if guess:
|
| 126 |
+
msg.append(f'maybe you meant "{guess}"')
|
| 127 |
+
|
| 128 |
+
raise CommandError(" - ".join(msg))
|
| 129 |
+
|
| 130 |
+
# all the args without the subcommand
|
| 131 |
+
cmd_args = args[:]
|
| 132 |
+
cmd_args.remove(cmd_name)
|
| 133 |
+
|
| 134 |
+
return cmd_name, cmd_args
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/cli/parser.py
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Base option parser setup"""
|
| 2 |
+
|
| 3 |
+
import logging
|
| 4 |
+
import optparse
|
| 5 |
+
import shutil
|
| 6 |
+
import sys
|
| 7 |
+
import textwrap
|
| 8 |
+
from contextlib import suppress
|
| 9 |
+
from typing import Any, Dict, Generator, List, Tuple
|
| 10 |
+
|
| 11 |
+
from pip._internal.cli.status_codes import UNKNOWN_ERROR
|
| 12 |
+
from pip._internal.configuration import Configuration, ConfigurationError
|
| 13 |
+
from pip._internal.utils.misc import redact_auth_from_url, strtobool
|
| 14 |
+
|
| 15 |
+
logger = logging.getLogger(__name__)
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
class PrettyHelpFormatter(optparse.IndentedHelpFormatter):
|
| 19 |
+
"""A prettier/less verbose help formatter for optparse."""
|
| 20 |
+
|
| 21 |
+
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
| 22 |
+
# help position must be aligned with __init__.parseopts.description
|
| 23 |
+
kwargs["max_help_position"] = 30
|
| 24 |
+
kwargs["indent_increment"] = 1
|
| 25 |
+
kwargs["width"] = shutil.get_terminal_size()[0] - 2
|
| 26 |
+
super().__init__(*args, **kwargs)
|
| 27 |
+
|
| 28 |
+
def format_option_strings(self, option: optparse.Option) -> str:
|
| 29 |
+
return self._format_option_strings(option)
|
| 30 |
+
|
| 31 |
+
def _format_option_strings(
|
| 32 |
+
self, option: optparse.Option, mvarfmt: str = " <{}>", optsep: str = ", "
|
| 33 |
+
) -> str:
|
| 34 |
+
"""
|
| 35 |
+
Return a comma-separated list of option strings and metavars.
|
| 36 |
+
|
| 37 |
+
:param option: tuple of (short opt, long opt), e.g: ('-f', '--format')
|
| 38 |
+
:param mvarfmt: metavar format string
|
| 39 |
+
:param optsep: separator
|
| 40 |
+
"""
|
| 41 |
+
opts = []
|
| 42 |
+
|
| 43 |
+
if option._short_opts:
|
| 44 |
+
opts.append(option._short_opts[0])
|
| 45 |
+
if option._long_opts:
|
| 46 |
+
opts.append(option._long_opts[0])
|
| 47 |
+
if len(opts) > 1:
|
| 48 |
+
opts.insert(1, optsep)
|
| 49 |
+
|
| 50 |
+
if option.takes_value():
|
| 51 |
+
assert option.dest is not None
|
| 52 |
+
metavar = option.metavar or option.dest.lower()
|
| 53 |
+
opts.append(mvarfmt.format(metavar.lower()))
|
| 54 |
+
|
| 55 |
+
return "".join(opts)
|
| 56 |
+
|
| 57 |
+
def format_heading(self, heading: str) -> str:
|
| 58 |
+
if heading == "Options":
|
| 59 |
+
return ""
|
| 60 |
+
return heading + ":\n"
|
| 61 |
+
|
| 62 |
+
def format_usage(self, usage: str) -> str:
|
| 63 |
+
"""
|
| 64 |
+
Ensure there is only one newline between usage and the first heading
|
| 65 |
+
if there is no description.
|
| 66 |
+
"""
|
| 67 |
+
msg = "\nUsage: {}\n".format(self.indent_lines(textwrap.dedent(usage), " "))
|
| 68 |
+
return msg
|
| 69 |
+
|
| 70 |
+
def format_description(self, description: str) -> str:
|
| 71 |
+
# leave full control over description to us
|
| 72 |
+
if description:
|
| 73 |
+
if hasattr(self.parser, "main"):
|
| 74 |
+
label = "Commands"
|
| 75 |
+
else:
|
| 76 |
+
label = "Description"
|
| 77 |
+
# some doc strings have initial newlines, some don't
|
| 78 |
+
description = description.lstrip("\n")
|
| 79 |
+
# some doc strings have final newlines and spaces, some don't
|
| 80 |
+
description = description.rstrip()
|
| 81 |
+
# dedent, then reindent
|
| 82 |
+
description = self.indent_lines(textwrap.dedent(description), " ")
|
| 83 |
+
description = f"{label}:\n{description}\n"
|
| 84 |
+
return description
|
| 85 |
+
else:
|
| 86 |
+
return ""
|
| 87 |
+
|
| 88 |
+
def format_epilog(self, epilog: str) -> str:
|
| 89 |
+
# leave full control over epilog to us
|
| 90 |
+
if epilog:
|
| 91 |
+
return epilog
|
| 92 |
+
else:
|
| 93 |
+
return ""
|
| 94 |
+
|
| 95 |
+
def indent_lines(self, text: str, indent: str) -> str:
|
| 96 |
+
new_lines = [indent + line for line in text.split("\n")]
|
| 97 |
+
return "\n".join(new_lines)
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
class UpdatingDefaultsHelpFormatter(PrettyHelpFormatter):
|
| 101 |
+
"""Custom help formatter for use in ConfigOptionParser.
|
| 102 |
+
|
| 103 |
+
This is updates the defaults before expanding them, allowing
|
| 104 |
+
them to show up correctly in the help listing.
|
| 105 |
+
|
| 106 |
+
Also redact auth from url type options
|
| 107 |
+
"""
|
| 108 |
+
|
| 109 |
+
def expand_default(self, option: optparse.Option) -> str:
|
| 110 |
+
default_values = None
|
| 111 |
+
if self.parser is not None:
|
| 112 |
+
assert isinstance(self.parser, ConfigOptionParser)
|
| 113 |
+
self.parser._update_defaults(self.parser.defaults)
|
| 114 |
+
assert option.dest is not None
|
| 115 |
+
default_values = self.parser.defaults.get(option.dest)
|
| 116 |
+
help_text = super().expand_default(option)
|
| 117 |
+
|
| 118 |
+
if default_values and option.metavar == "URL":
|
| 119 |
+
if isinstance(default_values, str):
|
| 120 |
+
default_values = [default_values]
|
| 121 |
+
|
| 122 |
+
# If its not a list, we should abort and just return the help text
|
| 123 |
+
if not isinstance(default_values, list):
|
| 124 |
+
default_values = []
|
| 125 |
+
|
| 126 |
+
for val in default_values:
|
| 127 |
+
help_text = help_text.replace(val, redact_auth_from_url(val))
|
| 128 |
+
|
| 129 |
+
return help_text
|
| 130 |
+
|
| 131 |
+
|
| 132 |
+
class CustomOptionParser(optparse.OptionParser):
|
| 133 |
+
def insert_option_group(
|
| 134 |
+
self, idx: int, *args: Any, **kwargs: Any
|
| 135 |
+
) -> optparse.OptionGroup:
|
| 136 |
+
"""Insert an OptionGroup at a given position."""
|
| 137 |
+
group = self.add_option_group(*args, **kwargs)
|
| 138 |
+
|
| 139 |
+
self.option_groups.pop()
|
| 140 |
+
self.option_groups.insert(idx, group)
|
| 141 |
+
|
| 142 |
+
return group
|
| 143 |
+
|
| 144 |
+
@property
|
| 145 |
+
def option_list_all(self) -> List[optparse.Option]:
|
| 146 |
+
"""Get a list of all options, including those in option groups."""
|
| 147 |
+
res = self.option_list[:]
|
| 148 |
+
for i in self.option_groups:
|
| 149 |
+
res.extend(i.option_list)
|
| 150 |
+
|
| 151 |
+
return res
|
| 152 |
+
|
| 153 |
+
|
| 154 |
+
class ConfigOptionParser(CustomOptionParser):
|
| 155 |
+
"""Custom option parser which updates its defaults by checking the
|
| 156 |
+
configuration files and environmental variables"""
|
| 157 |
+
|
| 158 |
+
def __init__(
|
| 159 |
+
self,
|
| 160 |
+
*args: Any,
|
| 161 |
+
name: str,
|
| 162 |
+
isolated: bool = False,
|
| 163 |
+
**kwargs: Any,
|
| 164 |
+
) -> None:
|
| 165 |
+
self.name = name
|
| 166 |
+
self.config = Configuration(isolated)
|
| 167 |
+
|
| 168 |
+
assert self.name
|
| 169 |
+
super().__init__(*args, **kwargs)
|
| 170 |
+
|
| 171 |
+
def check_default(self, option: optparse.Option, key: str, val: Any) -> Any:
|
| 172 |
+
try:
|
| 173 |
+
return option.check_value(key, val)
|
| 174 |
+
except optparse.OptionValueError as exc:
|
| 175 |
+
print(f"An error occurred during configuration: {exc}")
|
| 176 |
+
sys.exit(3)
|
| 177 |
+
|
| 178 |
+
def _get_ordered_configuration_items(
|
| 179 |
+
self,
|
| 180 |
+
) -> Generator[Tuple[str, Any], None, None]:
|
| 181 |
+
# Configuration gives keys in an unordered manner. Order them.
|
| 182 |
+
override_order = ["global", self.name, ":env:"]
|
| 183 |
+
|
| 184 |
+
# Pool the options into different groups
|
| 185 |
+
section_items: Dict[str, List[Tuple[str, Any]]] = {
|
| 186 |
+
name: [] for name in override_order
|
| 187 |
+
}
|
| 188 |
+
for section_key, val in self.config.items():
|
| 189 |
+
# ignore empty values
|
| 190 |
+
if not val:
|
| 191 |
+
logger.debug(
|
| 192 |
+
"Ignoring configuration key '%s' as it's value is empty.",
|
| 193 |
+
section_key,
|
| 194 |
+
)
|
| 195 |
+
continue
|
| 196 |
+
|
| 197 |
+
section, key = section_key.split(".", 1)
|
| 198 |
+
if section in override_order:
|
| 199 |
+
section_items[section].append((key, val))
|
| 200 |
+
|
| 201 |
+
# Yield each group in their override order
|
| 202 |
+
for section in override_order:
|
| 203 |
+
for key, val in section_items[section]:
|
| 204 |
+
yield key, val
|
| 205 |
+
|
| 206 |
+
def _update_defaults(self, defaults: Dict[str, Any]) -> Dict[str, Any]:
|
| 207 |
+
"""Updates the given defaults with values from the config files and
|
| 208 |
+
the environ. Does a little special handling for certain types of
|
| 209 |
+
options (lists)."""
|
| 210 |
+
|
| 211 |
+
# Accumulate complex default state.
|
| 212 |
+
self.values = optparse.Values(self.defaults)
|
| 213 |
+
late_eval = set()
|
| 214 |
+
# Then set the options with those values
|
| 215 |
+
for key, val in self._get_ordered_configuration_items():
|
| 216 |
+
# '--' because configuration supports only long names
|
| 217 |
+
option = self.get_option("--" + key)
|
| 218 |
+
|
| 219 |
+
# Ignore options not present in this parser. E.g. non-globals put
|
| 220 |
+
# in [global] by users that want them to apply to all applicable
|
| 221 |
+
# commands.
|
| 222 |
+
if option is None:
|
| 223 |
+
continue
|
| 224 |
+
|
| 225 |
+
assert option.dest is not None
|
| 226 |
+
|
| 227 |
+
if option.action in ("store_true", "store_false"):
|
| 228 |
+
try:
|
| 229 |
+
val = strtobool(val)
|
| 230 |
+
except ValueError:
|
| 231 |
+
self.error(
|
| 232 |
+
f"{val} is not a valid value for {key} option, "
|
| 233 |
+
"please specify a boolean value like yes/no, "
|
| 234 |
+
"true/false or 1/0 instead."
|
| 235 |
+
)
|
| 236 |
+
elif option.action == "count":
|
| 237 |
+
with suppress(ValueError):
|
| 238 |
+
val = strtobool(val)
|
| 239 |
+
with suppress(ValueError):
|
| 240 |
+
val = int(val)
|
| 241 |
+
if not isinstance(val, int) or val < 0:
|
| 242 |
+
self.error(
|
| 243 |
+
f"{val} is not a valid value for {key} option, "
|
| 244 |
+
"please instead specify either a non-negative integer "
|
| 245 |
+
"or a boolean value like yes/no or false/true "
|
| 246 |
+
"which is equivalent to 1/0."
|
| 247 |
+
)
|
| 248 |
+
elif option.action == "append":
|
| 249 |
+
val = val.split()
|
| 250 |
+
val = [self.check_default(option, key, v) for v in val]
|
| 251 |
+
elif option.action == "callback":
|
| 252 |
+
assert option.callback is not None
|
| 253 |
+
late_eval.add(option.dest)
|
| 254 |
+
opt_str = option.get_opt_string()
|
| 255 |
+
val = option.convert_value(opt_str, val)
|
| 256 |
+
# From take_action
|
| 257 |
+
args = option.callback_args or ()
|
| 258 |
+
kwargs = option.callback_kwargs or {}
|
| 259 |
+
option.callback(option, opt_str, val, self, *args, **kwargs)
|
| 260 |
+
else:
|
| 261 |
+
val = self.check_default(option, key, val)
|
| 262 |
+
|
| 263 |
+
defaults[option.dest] = val
|
| 264 |
+
|
| 265 |
+
for key in late_eval:
|
| 266 |
+
defaults[key] = getattr(self.values, key)
|
| 267 |
+
self.values = None
|
| 268 |
+
return defaults
|
| 269 |
+
|
| 270 |
+
def get_default_values(self) -> optparse.Values:
|
| 271 |
+
"""Overriding to make updating the defaults after instantiation of
|
| 272 |
+
the option parser possible, _update_defaults() does the dirty work."""
|
| 273 |
+
if not self.process_default_values:
|
| 274 |
+
# Old, pre-Optik 1.5 behaviour.
|
| 275 |
+
return optparse.Values(self.defaults)
|
| 276 |
+
|
| 277 |
+
# Load the configuration, or error out in case of an error
|
| 278 |
+
try:
|
| 279 |
+
self.config.load()
|
| 280 |
+
except ConfigurationError as err:
|
| 281 |
+
self.exit(UNKNOWN_ERROR, str(err))
|
| 282 |
+
|
| 283 |
+
defaults = self._update_defaults(self.defaults.copy()) # ours
|
| 284 |
+
for option in self._get_all_options():
|
| 285 |
+
assert option.dest is not None
|
| 286 |
+
default = defaults.get(option.dest)
|
| 287 |
+
if isinstance(default, str):
|
| 288 |
+
opt_str = option.get_opt_string()
|
| 289 |
+
defaults[option.dest] = option.check_value(opt_str, default)
|
| 290 |
+
return optparse.Values(defaults)
|
| 291 |
+
|
| 292 |
+
def error(self, msg: str) -> None:
|
| 293 |
+
self.print_usage(sys.stderr)
|
| 294 |
+
self.exit(UNKNOWN_ERROR, f"{msg}\n")
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/cli/progress_bars.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import functools
|
| 2 |
+
from typing import Callable, Generator, Iterable, Iterator, Optional, Tuple
|
| 3 |
+
|
| 4 |
+
from pip._vendor.rich.progress import (
|
| 5 |
+
BarColumn,
|
| 6 |
+
DownloadColumn,
|
| 7 |
+
FileSizeColumn,
|
| 8 |
+
Progress,
|
| 9 |
+
ProgressColumn,
|
| 10 |
+
SpinnerColumn,
|
| 11 |
+
TextColumn,
|
| 12 |
+
TimeElapsedColumn,
|
| 13 |
+
TimeRemainingColumn,
|
| 14 |
+
TransferSpeedColumn,
|
| 15 |
+
)
|
| 16 |
+
|
| 17 |
+
from pip._internal.utils.logging import get_indentation
|
| 18 |
+
|
| 19 |
+
DownloadProgressRenderer = Callable[[Iterable[bytes]], Iterator[bytes]]
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def _rich_progress_bar(
|
| 23 |
+
iterable: Iterable[bytes],
|
| 24 |
+
*,
|
| 25 |
+
bar_type: str,
|
| 26 |
+
size: int,
|
| 27 |
+
) -> Generator[bytes, None, None]:
|
| 28 |
+
assert bar_type == "on", "This should only be used in the default mode."
|
| 29 |
+
|
| 30 |
+
if not size:
|
| 31 |
+
total = float("inf")
|
| 32 |
+
columns: Tuple[ProgressColumn, ...] = (
|
| 33 |
+
TextColumn("[progress.description]{task.description}"),
|
| 34 |
+
SpinnerColumn("line", speed=1.5),
|
| 35 |
+
FileSizeColumn(),
|
| 36 |
+
TransferSpeedColumn(),
|
| 37 |
+
TimeElapsedColumn(),
|
| 38 |
+
)
|
| 39 |
+
else:
|
| 40 |
+
total = size
|
| 41 |
+
columns = (
|
| 42 |
+
TextColumn("[progress.description]{task.description}"),
|
| 43 |
+
BarColumn(),
|
| 44 |
+
DownloadColumn(),
|
| 45 |
+
TransferSpeedColumn(),
|
| 46 |
+
TextColumn("eta"),
|
| 47 |
+
TimeRemainingColumn(),
|
| 48 |
+
)
|
| 49 |
+
|
| 50 |
+
progress = Progress(*columns, refresh_per_second=30)
|
| 51 |
+
task_id = progress.add_task(" " * (get_indentation() + 2), total=total)
|
| 52 |
+
with progress:
|
| 53 |
+
for chunk in iterable:
|
| 54 |
+
yield chunk
|
| 55 |
+
progress.update(task_id, advance=len(chunk))
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
def get_download_progress_renderer(
|
| 59 |
+
*, bar_type: str, size: Optional[int] = None
|
| 60 |
+
) -> DownloadProgressRenderer:
|
| 61 |
+
"""Get an object that can be used to render the download progress.
|
| 62 |
+
|
| 63 |
+
Returns a callable, that takes an iterable to "wrap".
|
| 64 |
+
"""
|
| 65 |
+
if bar_type == "on":
|
| 66 |
+
return functools.partial(_rich_progress_bar, bar_type=bar_type, size=size)
|
| 67 |
+
else:
|
| 68 |
+
return iter # no-op, when passed an iterator
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/cli/status_codes.py
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
SUCCESS = 0
|
| 2 |
+
ERROR = 1
|
| 3 |
+
UNKNOWN_ERROR = 2
|
| 4 |
+
VIRTUALENV_NOT_FOUND = 3
|
| 5 |
+
PREVIOUS_BUILD_DIR_ERROR = 4
|
| 6 |
+
NO_MATCHES_FOUND = 23
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/locations/_distutils.py
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Locations where we look for configs, install stuff, etc"""
|
| 2 |
+
|
| 3 |
+
# The following comment should be removed at some point in the future.
|
| 4 |
+
# mypy: strict-optional=False
|
| 5 |
+
|
| 6 |
+
# If pip's going to use distutils, it should not be using the copy that setuptools
|
| 7 |
+
# might have injected into the environment. This is done by removing the injected
|
| 8 |
+
# shim, if it's injected.
|
| 9 |
+
#
|
| 10 |
+
# See https://github.com/pypa/pip/issues/8761 for the original discussion and
|
| 11 |
+
# rationale for why this is done within pip.
|
| 12 |
+
try:
|
| 13 |
+
__import__("_distutils_hack").remove_shim()
|
| 14 |
+
except (ImportError, AttributeError):
|
| 15 |
+
pass
|
| 16 |
+
|
| 17 |
+
import logging
|
| 18 |
+
import os
|
| 19 |
+
import sys
|
| 20 |
+
from distutils.cmd import Command as DistutilsCommand
|
| 21 |
+
from distutils.command.install import SCHEME_KEYS
|
| 22 |
+
from distutils.command.install import install as distutils_install_command
|
| 23 |
+
from distutils.sysconfig import get_python_lib
|
| 24 |
+
from typing import Dict, List, Optional, Union, cast
|
| 25 |
+
|
| 26 |
+
from pip._internal.models.scheme import Scheme
|
| 27 |
+
from pip._internal.utils.compat import WINDOWS
|
| 28 |
+
from pip._internal.utils.virtualenv import running_under_virtualenv
|
| 29 |
+
|
| 30 |
+
from .base import get_major_minor_version
|
| 31 |
+
|
| 32 |
+
logger = logging.getLogger(__name__)
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def distutils_scheme(
|
| 36 |
+
dist_name: str,
|
| 37 |
+
user: bool = False,
|
| 38 |
+
home: Optional[str] = None,
|
| 39 |
+
root: Optional[str] = None,
|
| 40 |
+
isolated: bool = False,
|
| 41 |
+
prefix: Optional[str] = None,
|
| 42 |
+
*,
|
| 43 |
+
ignore_config_files: bool = False,
|
| 44 |
+
) -> Dict[str, str]:
|
| 45 |
+
"""
|
| 46 |
+
Return a distutils install scheme
|
| 47 |
+
"""
|
| 48 |
+
from distutils.dist import Distribution
|
| 49 |
+
|
| 50 |
+
dist_args: Dict[str, Union[str, List[str]]] = {"name": dist_name}
|
| 51 |
+
if isolated:
|
| 52 |
+
dist_args["script_args"] = ["--no-user-cfg"]
|
| 53 |
+
|
| 54 |
+
d = Distribution(dist_args)
|
| 55 |
+
if not ignore_config_files:
|
| 56 |
+
try:
|
| 57 |
+
d.parse_config_files()
|
| 58 |
+
except UnicodeDecodeError:
|
| 59 |
+
paths = d.find_config_files()
|
| 60 |
+
logger.warning(
|
| 61 |
+
"Ignore distutils configs in %s due to encoding errors.",
|
| 62 |
+
", ".join(os.path.basename(p) for p in paths),
|
| 63 |
+
)
|
| 64 |
+
obj: Optional[DistutilsCommand] = None
|
| 65 |
+
obj = d.get_command_obj("install", create=True)
|
| 66 |
+
assert obj is not None
|
| 67 |
+
i = cast(distutils_install_command, obj)
|
| 68 |
+
# NOTE: setting user or home has the side-effect of creating the home dir
|
| 69 |
+
# or user base for installations during finalize_options()
|
| 70 |
+
# ideally, we'd prefer a scheme class that has no side-effects.
|
| 71 |
+
assert not (user and prefix), f"user={user} prefix={prefix}"
|
| 72 |
+
assert not (home and prefix), f"home={home} prefix={prefix}"
|
| 73 |
+
i.user = user or i.user
|
| 74 |
+
if user or home:
|
| 75 |
+
i.prefix = ""
|
| 76 |
+
i.prefix = prefix or i.prefix
|
| 77 |
+
i.home = home or i.home
|
| 78 |
+
i.root = root or i.root
|
| 79 |
+
i.finalize_options()
|
| 80 |
+
|
| 81 |
+
scheme = {}
|
| 82 |
+
for key in SCHEME_KEYS:
|
| 83 |
+
scheme[key] = getattr(i, "install_" + key)
|
| 84 |
+
|
| 85 |
+
# install_lib specified in setup.cfg should install *everything*
|
| 86 |
+
# into there (i.e. it takes precedence over both purelib and
|
| 87 |
+
# platlib). Note, i.install_lib is *always* set after
|
| 88 |
+
# finalize_options(); we only want to override here if the user
|
| 89 |
+
# has explicitly requested it hence going back to the config
|
| 90 |
+
if "install_lib" in d.get_option_dict("install"):
|
| 91 |
+
scheme.update({"purelib": i.install_lib, "platlib": i.install_lib})
|
| 92 |
+
|
| 93 |
+
if running_under_virtualenv():
|
| 94 |
+
if home:
|
| 95 |
+
prefix = home
|
| 96 |
+
elif user:
|
| 97 |
+
prefix = i.install_userbase
|
| 98 |
+
else:
|
| 99 |
+
prefix = i.prefix
|
| 100 |
+
scheme["headers"] = os.path.join(
|
| 101 |
+
prefix,
|
| 102 |
+
"include",
|
| 103 |
+
"site",
|
| 104 |
+
f"python{get_major_minor_version()}",
|
| 105 |
+
dist_name,
|
| 106 |
+
)
|
| 107 |
+
|
| 108 |
+
if root is not None:
|
| 109 |
+
path_no_drive = os.path.splitdrive(os.path.abspath(scheme["headers"]))[1]
|
| 110 |
+
scheme["headers"] = os.path.join(root, path_no_drive[1:])
|
| 111 |
+
|
| 112 |
+
return scheme
|
| 113 |
+
|
| 114 |
+
|
| 115 |
+
def get_scheme(
|
| 116 |
+
dist_name: str,
|
| 117 |
+
user: bool = False,
|
| 118 |
+
home: Optional[str] = None,
|
| 119 |
+
root: Optional[str] = None,
|
| 120 |
+
isolated: bool = False,
|
| 121 |
+
prefix: Optional[str] = None,
|
| 122 |
+
) -> Scheme:
|
| 123 |
+
"""
|
| 124 |
+
Get the "scheme" corresponding to the input parameters. The distutils
|
| 125 |
+
documentation provides the context for the available schemes:
|
| 126 |
+
https://docs.python.org/3/install/index.html#alternate-installation
|
| 127 |
+
|
| 128 |
+
:param dist_name: the name of the package to retrieve the scheme for, used
|
| 129 |
+
in the headers scheme path
|
| 130 |
+
:param user: indicates to use the "user" scheme
|
| 131 |
+
:param home: indicates to use the "home" scheme and provides the base
|
| 132 |
+
directory for the same
|
| 133 |
+
:param root: root under which other directories are re-based
|
| 134 |
+
:param isolated: equivalent to --no-user-cfg, i.e. do not consider
|
| 135 |
+
~/.pydistutils.cfg (posix) or ~/pydistutils.cfg (non-posix) for
|
| 136 |
+
scheme paths
|
| 137 |
+
:param prefix: indicates to use the "prefix" scheme and provides the
|
| 138 |
+
base directory for the same
|
| 139 |
+
"""
|
| 140 |
+
scheme = distutils_scheme(dist_name, user, home, root, isolated, prefix)
|
| 141 |
+
return Scheme(
|
| 142 |
+
platlib=scheme["platlib"],
|
| 143 |
+
purelib=scheme["purelib"],
|
| 144 |
+
headers=scheme["headers"],
|
| 145 |
+
scripts=scheme["scripts"],
|
| 146 |
+
data=scheme["data"],
|
| 147 |
+
)
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
def get_bin_prefix() -> str:
|
| 151 |
+
# XXX: In old virtualenv versions, sys.prefix can contain '..' components,
|
| 152 |
+
# so we need to call normpath to eliminate them.
|
| 153 |
+
prefix = os.path.normpath(sys.prefix)
|
| 154 |
+
if WINDOWS:
|
| 155 |
+
bin_py = os.path.join(prefix, "Scripts")
|
| 156 |
+
# buildout uses 'bin' on Windows too?
|
| 157 |
+
if not os.path.exists(bin_py):
|
| 158 |
+
bin_py = os.path.join(prefix, "bin")
|
| 159 |
+
return bin_py
|
| 160 |
+
# Forcing to use /usr/local/bin for standard macOS framework installs
|
| 161 |
+
# Also log to ~/Library/Logs/ for use with the Console.app log viewer
|
| 162 |
+
if sys.platform[:6] == "darwin" and prefix[:16] == "/System/Library/":
|
| 163 |
+
return "/usr/local/bin"
|
| 164 |
+
return os.path.join(prefix, "bin")
|
| 165 |
+
|
| 166 |
+
|
| 167 |
+
def get_purelib() -> str:
|
| 168 |
+
return get_python_lib(plat_specific=False)
|
| 169 |
+
|
| 170 |
+
|
| 171 |
+
def get_platlib() -> str:
|
| 172 |
+
return get_python_lib(plat_specific=True)
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/locations/base.py
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import functools
|
| 2 |
+
import os
|
| 3 |
+
import site
|
| 4 |
+
import sys
|
| 5 |
+
import sysconfig
|
| 6 |
+
import typing
|
| 7 |
+
|
| 8 |
+
from pip._internal.exceptions import InstallationError
|
| 9 |
+
from pip._internal.utils import appdirs
|
| 10 |
+
from pip._internal.utils.virtualenv import running_under_virtualenv
|
| 11 |
+
|
| 12 |
+
# Application Directories
|
| 13 |
+
USER_CACHE_DIR = appdirs.user_cache_dir("pip")
|
| 14 |
+
|
| 15 |
+
# FIXME doesn't account for venv linked to global site-packages
|
| 16 |
+
site_packages: str = sysconfig.get_path("purelib")
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
def get_major_minor_version() -> str:
|
| 20 |
+
"""
|
| 21 |
+
Return the major-minor version of the current Python as a string, e.g.
|
| 22 |
+
"3.7" or "3.10".
|
| 23 |
+
"""
|
| 24 |
+
return "{}.{}".format(*sys.version_info)
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def change_root(new_root: str, pathname: str) -> str:
|
| 28 |
+
"""Return 'pathname' with 'new_root' prepended.
|
| 29 |
+
|
| 30 |
+
If 'pathname' is relative, this is equivalent to os.path.join(new_root, pathname).
|
| 31 |
+
Otherwise, it requires making 'pathname' relative and then joining the
|
| 32 |
+
two, which is tricky on DOS/Windows and Mac OS.
|
| 33 |
+
|
| 34 |
+
This is borrowed from Python's standard library's distutils module.
|
| 35 |
+
"""
|
| 36 |
+
if os.name == "posix":
|
| 37 |
+
if not os.path.isabs(pathname):
|
| 38 |
+
return os.path.join(new_root, pathname)
|
| 39 |
+
else:
|
| 40 |
+
return os.path.join(new_root, pathname[1:])
|
| 41 |
+
|
| 42 |
+
elif os.name == "nt":
|
| 43 |
+
(drive, path) = os.path.splitdrive(pathname)
|
| 44 |
+
if path[0] == "\\":
|
| 45 |
+
path = path[1:]
|
| 46 |
+
return os.path.join(new_root, path)
|
| 47 |
+
|
| 48 |
+
else:
|
| 49 |
+
raise InstallationError(
|
| 50 |
+
f"Unknown platform: {os.name}\n"
|
| 51 |
+
"Can not change root path prefix on unknown platform."
|
| 52 |
+
)
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
def get_src_prefix() -> str:
|
| 56 |
+
if running_under_virtualenv():
|
| 57 |
+
src_prefix = os.path.join(sys.prefix, "src")
|
| 58 |
+
else:
|
| 59 |
+
# FIXME: keep src in cwd for now (it is not a temporary folder)
|
| 60 |
+
try:
|
| 61 |
+
src_prefix = os.path.join(os.getcwd(), "src")
|
| 62 |
+
except OSError:
|
| 63 |
+
# In case the current working directory has been renamed or deleted
|
| 64 |
+
sys.exit("The folder you are executing pip from can no longer be found.")
|
| 65 |
+
|
| 66 |
+
# under macOS + virtualenv sys.prefix is not properly resolved
|
| 67 |
+
# it is something like /path/to/python/bin/..
|
| 68 |
+
return os.path.abspath(src_prefix)
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
try:
|
| 72 |
+
# Use getusersitepackages if this is present, as it ensures that the
|
| 73 |
+
# value is initialised properly.
|
| 74 |
+
user_site: typing.Optional[str] = site.getusersitepackages()
|
| 75 |
+
except AttributeError:
|
| 76 |
+
user_site = site.USER_SITE
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
@functools.lru_cache(maxsize=None)
|
| 80 |
+
def is_osx_framework() -> bool:
|
| 81 |
+
return bool(sysconfig.get_config_var("PYTHONFRAMEWORK"))
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/models/index.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import urllib.parse
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
class PackageIndex:
|
| 5 |
+
"""Represents a Package Index and provides easier access to endpoints"""
|
| 6 |
+
|
| 7 |
+
__slots__ = ["url", "netloc", "simple_url", "pypi_url", "file_storage_domain"]
|
| 8 |
+
|
| 9 |
+
def __init__(self, url: str, file_storage_domain: str) -> None:
|
| 10 |
+
super().__init__()
|
| 11 |
+
self.url = url
|
| 12 |
+
self.netloc = urllib.parse.urlsplit(url).netloc
|
| 13 |
+
self.simple_url = self._url_for_path("simple")
|
| 14 |
+
self.pypi_url = self._url_for_path("pypi")
|
| 15 |
+
|
| 16 |
+
# This is part of a temporary hack used to block installs of PyPI
|
| 17 |
+
# packages which depend on external urls only necessary until PyPI can
|
| 18 |
+
# block such packages themselves
|
| 19 |
+
self.file_storage_domain = file_storage_domain
|
| 20 |
+
|
| 21 |
+
def _url_for_path(self, path: str) -> str:
|
| 22 |
+
return urllib.parse.urljoin(self.url, path)
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
PyPI = PackageIndex("https://pypi.org/", file_storage_domain="files.pythonhosted.org")
|
| 26 |
+
TestPyPI = PackageIndex(
|
| 27 |
+
"https://test.pypi.org/", file_storage_domain="test-files.pythonhosted.org"
|
| 28 |
+
)
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/models/installation_report.py
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import Any, Dict, Sequence
|
| 2 |
+
|
| 3 |
+
from pip._vendor.packaging.markers import default_environment
|
| 4 |
+
|
| 5 |
+
from pip import __version__
|
| 6 |
+
from pip._internal.req.req_install import InstallRequirement
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
class InstallationReport:
|
| 10 |
+
def __init__(self, install_requirements: Sequence[InstallRequirement]):
|
| 11 |
+
self._install_requirements = install_requirements
|
| 12 |
+
|
| 13 |
+
@classmethod
|
| 14 |
+
def _install_req_to_dict(cls, ireq: InstallRequirement) -> Dict[str, Any]:
|
| 15 |
+
assert ireq.download_info, f"No download_info for {ireq}"
|
| 16 |
+
res = {
|
| 17 |
+
# PEP 610 json for the download URL. download_info.archive_info.hashes may
|
| 18 |
+
# be absent when the requirement was installed from the wheel cache
|
| 19 |
+
# and the cache entry was populated by an older pip version that did not
|
| 20 |
+
# record origin.json.
|
| 21 |
+
"download_info": ireq.download_info.to_dict(),
|
| 22 |
+
# is_direct is true if the requirement was a direct URL reference (which
|
| 23 |
+
# includes editable requirements), and false if the requirement was
|
| 24 |
+
# downloaded from a PEP 503 index or --find-links.
|
| 25 |
+
"is_direct": ireq.is_direct,
|
| 26 |
+
# is_yanked is true if the requirement was yanked from the index, but
|
| 27 |
+
# was still selected by pip to conform to PEP 592.
|
| 28 |
+
"is_yanked": ireq.link.is_yanked if ireq.link else False,
|
| 29 |
+
# requested is true if the requirement was specified by the user (aka
|
| 30 |
+
# top level requirement), and false if it was installed as a dependency of a
|
| 31 |
+
# requirement. https://peps.python.org/pep-0376/#requested
|
| 32 |
+
"requested": ireq.user_supplied,
|
| 33 |
+
# PEP 566 json encoding for metadata
|
| 34 |
+
# https://www.python.org/dev/peps/pep-0566/#json-compatible-metadata
|
| 35 |
+
"metadata": ireq.get_dist().metadata_dict,
|
| 36 |
+
}
|
| 37 |
+
if ireq.user_supplied and ireq.extras:
|
| 38 |
+
# For top level requirements, the list of requested extras, if any.
|
| 39 |
+
res["requested_extras"] = sorted(ireq.extras)
|
| 40 |
+
return res
|
| 41 |
+
|
| 42 |
+
def to_dict(self) -> Dict[str, Any]:
|
| 43 |
+
return {
|
| 44 |
+
"version": "1",
|
| 45 |
+
"pip_version": __version__,
|
| 46 |
+
"install": [
|
| 47 |
+
self._install_req_to_dict(ireq) for ireq in self._install_requirements
|
| 48 |
+
],
|
| 49 |
+
# https://peps.python.org/pep-0508/#environment-markers
|
| 50 |
+
# TODO: currently, the resolver uses the default environment to evaluate
|
| 51 |
+
# environment markers, so that is what we report here. In the future, it
|
| 52 |
+
# should also take into account options such as --python-version or
|
| 53 |
+
# --platform, perhaps under the form of an environment_override field?
|
| 54 |
+
# https://github.com/pypa/pip/issues/11198
|
| 55 |
+
"environment": default_environment(),
|
| 56 |
+
}
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/__init__.py
ADDED
|
File without changes
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/_jaraco_text.py
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Functions brought over from jaraco.text.
|
| 2 |
+
|
| 3 |
+
These functions are not supposed to be used within `pip._internal`. These are
|
| 4 |
+
helper functions brought over from `jaraco.text` to enable vendoring newer
|
| 5 |
+
copies of `pkg_resources` without having to vendor `jaraco.text` and its entire
|
| 6 |
+
dependency cone; something that our vendoring setup is not currently capable of
|
| 7 |
+
handling.
|
| 8 |
+
|
| 9 |
+
License reproduced from original source below:
|
| 10 |
+
|
| 11 |
+
Copyright Jason R. Coombs
|
| 12 |
+
|
| 13 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 14 |
+
of this software and associated documentation files (the "Software"), to
|
| 15 |
+
deal in the Software without restriction, including without limitation the
|
| 16 |
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
| 17 |
+
sell copies of the Software, and to permit persons to whom the Software is
|
| 18 |
+
furnished to do so, subject to the following conditions:
|
| 19 |
+
|
| 20 |
+
The above copyright notice and this permission notice shall be included in
|
| 21 |
+
all copies or substantial portions of the Software.
|
| 22 |
+
|
| 23 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 24 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 25 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 26 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 27 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
| 28 |
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
| 29 |
+
IN THE SOFTWARE.
|
| 30 |
+
"""
|
| 31 |
+
|
| 32 |
+
import functools
|
| 33 |
+
import itertools
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def _nonblank(str):
|
| 37 |
+
return str and not str.startswith("#")
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
@functools.singledispatch
|
| 41 |
+
def yield_lines(iterable):
|
| 42 |
+
r"""
|
| 43 |
+
Yield valid lines of a string or iterable.
|
| 44 |
+
|
| 45 |
+
>>> list(yield_lines(''))
|
| 46 |
+
[]
|
| 47 |
+
>>> list(yield_lines(['foo', 'bar']))
|
| 48 |
+
['foo', 'bar']
|
| 49 |
+
>>> list(yield_lines('foo\nbar'))
|
| 50 |
+
['foo', 'bar']
|
| 51 |
+
>>> list(yield_lines('\nfoo\n#bar\nbaz #comment'))
|
| 52 |
+
['foo', 'baz #comment']
|
| 53 |
+
>>> list(yield_lines(['foo\nbar', 'baz', 'bing\n\n\n']))
|
| 54 |
+
['foo', 'bar', 'baz', 'bing']
|
| 55 |
+
"""
|
| 56 |
+
return itertools.chain.from_iterable(map(yield_lines, iterable))
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
@yield_lines.register(str)
|
| 60 |
+
def _(text):
|
| 61 |
+
return filter(_nonblank, map(str.strip, text.splitlines()))
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
def drop_comment(line):
|
| 65 |
+
"""
|
| 66 |
+
Drop comments.
|
| 67 |
+
|
| 68 |
+
>>> drop_comment('foo # bar')
|
| 69 |
+
'foo'
|
| 70 |
+
|
| 71 |
+
A hash without a space may be in a URL.
|
| 72 |
+
|
| 73 |
+
>>> drop_comment('http://example.com/foo#bar')
|
| 74 |
+
'http://example.com/foo#bar'
|
| 75 |
+
"""
|
| 76 |
+
return line.partition(" #")[0]
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
def join_continuation(lines):
|
| 80 |
+
r"""
|
| 81 |
+
Join lines continued by a trailing backslash.
|
| 82 |
+
|
| 83 |
+
>>> list(join_continuation(['foo \\', 'bar', 'baz']))
|
| 84 |
+
['foobar', 'baz']
|
| 85 |
+
>>> list(join_continuation(['foo \\', 'bar', 'baz']))
|
| 86 |
+
['foobar', 'baz']
|
| 87 |
+
>>> list(join_continuation(['foo \\', 'bar \\', 'baz']))
|
| 88 |
+
['foobarbaz']
|
| 89 |
+
|
| 90 |
+
Not sure why, but...
|
| 91 |
+
The character preceeding the backslash is also elided.
|
| 92 |
+
|
| 93 |
+
>>> list(join_continuation(['goo\\', 'dly']))
|
| 94 |
+
['godly']
|
| 95 |
+
|
| 96 |
+
A terrible idea, but...
|
| 97 |
+
If no line is available to continue, suppress the lines.
|
| 98 |
+
|
| 99 |
+
>>> list(join_continuation(['foo', 'bar\\', 'baz\\']))
|
| 100 |
+
['foo']
|
| 101 |
+
"""
|
| 102 |
+
lines = iter(lines)
|
| 103 |
+
for item in lines:
|
| 104 |
+
while item.endswith("\\"):
|
| 105 |
+
try:
|
| 106 |
+
item = item[:-2].strip() + next(lines)
|
| 107 |
+
except StopIteration:
|
| 108 |
+
return
|
| 109 |
+
yield item
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/_log.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Customize logging
|
| 2 |
+
|
| 3 |
+
Defines custom logger class for the `logger.verbose(...)` method.
|
| 4 |
+
|
| 5 |
+
init_logging() must be called before any other modules that call logging.getLogger.
|
| 6 |
+
"""
|
| 7 |
+
|
| 8 |
+
import logging
|
| 9 |
+
from typing import Any, cast
|
| 10 |
+
|
| 11 |
+
# custom log level for `--verbose` output
|
| 12 |
+
# between DEBUG and INFO
|
| 13 |
+
VERBOSE = 15
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
class VerboseLogger(logging.Logger):
|
| 17 |
+
"""Custom Logger, defining a verbose log-level
|
| 18 |
+
|
| 19 |
+
VERBOSE is between INFO and DEBUG.
|
| 20 |
+
"""
|
| 21 |
+
|
| 22 |
+
def verbose(self, msg: str, *args: Any, **kwargs: Any) -> None:
|
| 23 |
+
return self.log(VERBOSE, msg, *args, **kwargs)
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def getLogger(name: str) -> VerboseLogger:
|
| 27 |
+
"""logging.getLogger, but ensures our VerboseLogger class is returned"""
|
| 28 |
+
return cast(VerboseLogger, logging.getLogger(name))
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
def init_logging() -> None:
|
| 32 |
+
"""Register our VerboseLogger and VERBOSE log level.
|
| 33 |
+
|
| 34 |
+
Should be called before any calls to getLogger(),
|
| 35 |
+
i.e. in pip._internal.__init__
|
| 36 |
+
"""
|
| 37 |
+
logging.setLoggerClass(VerboseLogger)
|
| 38 |
+
logging.addLevelName(VERBOSE, "VERBOSE")
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/appdirs.py
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
This code wraps the vendored appdirs module to so the return values are
|
| 3 |
+
compatible for the current pip code base.
|
| 4 |
+
|
| 5 |
+
The intention is to rewrite current usages gradually, keeping the tests pass,
|
| 6 |
+
and eventually drop this after all usages are changed.
|
| 7 |
+
"""
|
| 8 |
+
|
| 9 |
+
import os
|
| 10 |
+
import sys
|
| 11 |
+
from typing import List
|
| 12 |
+
|
| 13 |
+
from pip._vendor import platformdirs as _appdirs
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def user_cache_dir(appname: str) -> str:
|
| 17 |
+
return _appdirs.user_cache_dir(appname, appauthor=False)
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def _macos_user_config_dir(appname: str, roaming: bool = True) -> str:
|
| 21 |
+
# Use ~/Application Support/pip, if the directory exists.
|
| 22 |
+
path = _appdirs.user_data_dir(appname, appauthor=False, roaming=roaming)
|
| 23 |
+
if os.path.isdir(path):
|
| 24 |
+
return path
|
| 25 |
+
|
| 26 |
+
# Use a Linux-like ~/.config/pip, by default.
|
| 27 |
+
linux_like_path = "~/.config/"
|
| 28 |
+
if appname:
|
| 29 |
+
linux_like_path = os.path.join(linux_like_path, appname)
|
| 30 |
+
|
| 31 |
+
return os.path.expanduser(linux_like_path)
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def user_config_dir(appname: str, roaming: bool = True) -> str:
|
| 35 |
+
if sys.platform == "darwin":
|
| 36 |
+
return _macos_user_config_dir(appname, roaming)
|
| 37 |
+
|
| 38 |
+
return _appdirs.user_config_dir(appname, appauthor=False, roaming=roaming)
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
# for the discussion regarding site_config_dir locations
|
| 42 |
+
# see <https://github.com/pypa/pip/issues/1733>
|
| 43 |
+
def site_config_dirs(appname: str) -> List[str]:
|
| 44 |
+
if sys.platform == "darwin":
|
| 45 |
+
return [_appdirs.site_data_dir(appname, appauthor=False, multipath=True)]
|
| 46 |
+
|
| 47 |
+
dirval = _appdirs.site_config_dir(appname, appauthor=False, multipath=True)
|
| 48 |
+
if sys.platform == "win32":
|
| 49 |
+
return [dirval]
|
| 50 |
+
|
| 51 |
+
# Unix-y system. Look in /etc as well.
|
| 52 |
+
return dirval.split(os.pathsep) + ["/etc"]
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/compatibility_tags.py
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Generate and work with PEP 425 Compatibility Tags.
|
| 2 |
+
"""
|
| 3 |
+
|
| 4 |
+
import re
|
| 5 |
+
from typing import List, Optional, Tuple
|
| 6 |
+
|
| 7 |
+
from pip._vendor.packaging.tags import (
|
| 8 |
+
PythonVersion,
|
| 9 |
+
Tag,
|
| 10 |
+
compatible_tags,
|
| 11 |
+
cpython_tags,
|
| 12 |
+
generic_tags,
|
| 13 |
+
interpreter_name,
|
| 14 |
+
interpreter_version,
|
| 15 |
+
mac_platforms,
|
| 16 |
+
)
|
| 17 |
+
|
| 18 |
+
_osx_arch_pat = re.compile(r"(.+)_(\d+)_(\d+)_(.+)")
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def version_info_to_nodot(version_info: Tuple[int, ...]) -> str:
|
| 22 |
+
# Only use up to the first two numbers.
|
| 23 |
+
return "".join(map(str, version_info[:2]))
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def _mac_platforms(arch: str) -> List[str]:
|
| 27 |
+
match = _osx_arch_pat.match(arch)
|
| 28 |
+
if match:
|
| 29 |
+
name, major, minor, actual_arch = match.groups()
|
| 30 |
+
mac_version = (int(major), int(minor))
|
| 31 |
+
arches = [
|
| 32 |
+
# Since we have always only checked that the platform starts
|
| 33 |
+
# with "macosx", for backwards-compatibility we extract the
|
| 34 |
+
# actual prefix provided by the user in case they provided
|
| 35 |
+
# something like "macosxcustom_". It may be good to remove
|
| 36 |
+
# this as undocumented or deprecate it in the future.
|
| 37 |
+
"{}_{}".format(name, arch[len("macosx_") :])
|
| 38 |
+
for arch in mac_platforms(mac_version, actual_arch)
|
| 39 |
+
]
|
| 40 |
+
else:
|
| 41 |
+
# arch pattern didn't match (?!)
|
| 42 |
+
arches = [arch]
|
| 43 |
+
return arches
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
def _custom_manylinux_platforms(arch: str) -> List[str]:
|
| 47 |
+
arches = [arch]
|
| 48 |
+
arch_prefix, arch_sep, arch_suffix = arch.partition("_")
|
| 49 |
+
if arch_prefix == "manylinux2014":
|
| 50 |
+
# manylinux1/manylinux2010 wheels run on most manylinux2014 systems
|
| 51 |
+
# with the exception of wheels depending on ncurses. PEP 599 states
|
| 52 |
+
# manylinux1/manylinux2010 wheels should be considered
|
| 53 |
+
# manylinux2014 wheels:
|
| 54 |
+
# https://www.python.org/dev/peps/pep-0599/#backwards-compatibility-with-manylinux2010-wheels
|
| 55 |
+
if arch_suffix in {"i686", "x86_64"}:
|
| 56 |
+
arches.append("manylinux2010" + arch_sep + arch_suffix)
|
| 57 |
+
arches.append("manylinux1" + arch_sep + arch_suffix)
|
| 58 |
+
elif arch_prefix == "manylinux2010":
|
| 59 |
+
# manylinux1 wheels run on most manylinux2010 systems with the
|
| 60 |
+
# exception of wheels depending on ncurses. PEP 571 states
|
| 61 |
+
# manylinux1 wheels should be considered manylinux2010 wheels:
|
| 62 |
+
# https://www.python.org/dev/peps/pep-0571/#backwards-compatibility-with-manylinux1-wheels
|
| 63 |
+
arches.append("manylinux1" + arch_sep + arch_suffix)
|
| 64 |
+
return arches
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
def _get_custom_platforms(arch: str) -> List[str]:
|
| 68 |
+
arch_prefix, arch_sep, arch_suffix = arch.partition("_")
|
| 69 |
+
if arch.startswith("macosx"):
|
| 70 |
+
arches = _mac_platforms(arch)
|
| 71 |
+
elif arch_prefix in ["manylinux2014", "manylinux2010"]:
|
| 72 |
+
arches = _custom_manylinux_platforms(arch)
|
| 73 |
+
else:
|
| 74 |
+
arches = [arch]
|
| 75 |
+
return arches
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
def _expand_allowed_platforms(platforms: Optional[List[str]]) -> Optional[List[str]]:
|
| 79 |
+
if not platforms:
|
| 80 |
+
return None
|
| 81 |
+
|
| 82 |
+
seen = set()
|
| 83 |
+
result = []
|
| 84 |
+
|
| 85 |
+
for p in platforms:
|
| 86 |
+
if p in seen:
|
| 87 |
+
continue
|
| 88 |
+
additions = [c for c in _get_custom_platforms(p) if c not in seen]
|
| 89 |
+
seen.update(additions)
|
| 90 |
+
result.extend(additions)
|
| 91 |
+
|
| 92 |
+
return result
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
def _get_python_version(version: str) -> PythonVersion:
|
| 96 |
+
if len(version) > 1:
|
| 97 |
+
return int(version[0]), int(version[1:])
|
| 98 |
+
else:
|
| 99 |
+
return (int(version[0]),)
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
def _get_custom_interpreter(
|
| 103 |
+
implementation: Optional[str] = None, version: Optional[str] = None
|
| 104 |
+
) -> str:
|
| 105 |
+
if implementation is None:
|
| 106 |
+
implementation = interpreter_name()
|
| 107 |
+
if version is None:
|
| 108 |
+
version = interpreter_version()
|
| 109 |
+
return f"{implementation}{version}"
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
def get_supported(
|
| 113 |
+
version: Optional[str] = None,
|
| 114 |
+
platforms: Optional[List[str]] = None,
|
| 115 |
+
impl: Optional[str] = None,
|
| 116 |
+
abis: Optional[List[str]] = None,
|
| 117 |
+
) -> List[Tag]:
|
| 118 |
+
"""Return a list of supported tags for each version specified in
|
| 119 |
+
`versions`.
|
| 120 |
+
|
| 121 |
+
:param version: a string version, of the form "33" or "32",
|
| 122 |
+
or None. The version will be assumed to support our ABI.
|
| 123 |
+
:param platform: specify a list of platforms you want valid
|
| 124 |
+
tags for, or None. If None, use the local system platform.
|
| 125 |
+
:param impl: specify the exact implementation you want valid
|
| 126 |
+
tags for, or None. If None, use the local interpreter impl.
|
| 127 |
+
:param abis: specify a list of abis you want valid
|
| 128 |
+
tags for, or None. If None, use the local interpreter abi.
|
| 129 |
+
"""
|
| 130 |
+
supported: List[Tag] = []
|
| 131 |
+
|
| 132 |
+
python_version: Optional[PythonVersion] = None
|
| 133 |
+
if version is not None:
|
| 134 |
+
python_version = _get_python_version(version)
|
| 135 |
+
|
| 136 |
+
interpreter = _get_custom_interpreter(impl, version)
|
| 137 |
+
|
| 138 |
+
platforms = _expand_allowed_platforms(platforms)
|
| 139 |
+
|
| 140 |
+
is_cpython = (impl or interpreter_name()) == "cp"
|
| 141 |
+
if is_cpython:
|
| 142 |
+
supported.extend(
|
| 143 |
+
cpython_tags(
|
| 144 |
+
python_version=python_version,
|
| 145 |
+
abis=abis,
|
| 146 |
+
platforms=platforms,
|
| 147 |
+
)
|
| 148 |
+
)
|
| 149 |
+
else:
|
| 150 |
+
supported.extend(
|
| 151 |
+
generic_tags(
|
| 152 |
+
interpreter=interpreter,
|
| 153 |
+
abis=abis,
|
| 154 |
+
platforms=platforms,
|
| 155 |
+
)
|
| 156 |
+
)
|
| 157 |
+
supported.extend(
|
| 158 |
+
compatible_tags(
|
| 159 |
+
python_version=python_version,
|
| 160 |
+
interpreter=interpreter,
|
| 161 |
+
platforms=platforms,
|
| 162 |
+
)
|
| 163 |
+
)
|
| 164 |
+
|
| 165 |
+
return supported
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/encoding.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import codecs
|
| 2 |
+
import locale
|
| 3 |
+
import re
|
| 4 |
+
import sys
|
| 5 |
+
from typing import List, Tuple
|
| 6 |
+
|
| 7 |
+
BOMS: List[Tuple[bytes, str]] = [
|
| 8 |
+
(codecs.BOM_UTF8, "utf-8"),
|
| 9 |
+
(codecs.BOM_UTF16, "utf-16"),
|
| 10 |
+
(codecs.BOM_UTF16_BE, "utf-16-be"),
|
| 11 |
+
(codecs.BOM_UTF16_LE, "utf-16-le"),
|
| 12 |
+
(codecs.BOM_UTF32, "utf-32"),
|
| 13 |
+
(codecs.BOM_UTF32_BE, "utf-32-be"),
|
| 14 |
+
(codecs.BOM_UTF32_LE, "utf-32-le"),
|
| 15 |
+
]
|
| 16 |
+
|
| 17 |
+
ENCODING_RE = re.compile(rb"coding[:=]\s*([-\w.]+)")
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def auto_decode(data: bytes) -> str:
|
| 21 |
+
"""Check a bytes string for a BOM to correctly detect the encoding
|
| 22 |
+
|
| 23 |
+
Fallback to locale.getpreferredencoding(False) like open() on Python3"""
|
| 24 |
+
for bom, encoding in BOMS:
|
| 25 |
+
if data.startswith(bom):
|
| 26 |
+
return data[len(bom) :].decode(encoding)
|
| 27 |
+
# Lets check the first two lines as in PEP263
|
| 28 |
+
for line in data.split(b"\n")[:2]:
|
| 29 |
+
if line[0:1] == b"#" and ENCODING_RE.search(line):
|
| 30 |
+
result = ENCODING_RE.search(line)
|
| 31 |
+
assert result is not None
|
| 32 |
+
encoding = result.groups()[0].decode("ascii")
|
| 33 |
+
return data.decode(encoding)
|
| 34 |
+
return data.decode(
|
| 35 |
+
locale.getpreferredencoding(False) or sys.getdefaultencoding(),
|
| 36 |
+
)
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/entrypoints.py
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import itertools
|
| 2 |
+
import os
|
| 3 |
+
import shutil
|
| 4 |
+
import sys
|
| 5 |
+
from typing import List, Optional
|
| 6 |
+
|
| 7 |
+
from pip._internal.cli.main import main
|
| 8 |
+
from pip._internal.utils.compat import WINDOWS
|
| 9 |
+
|
| 10 |
+
_EXECUTABLE_NAMES = [
|
| 11 |
+
"pip",
|
| 12 |
+
f"pip{sys.version_info.major}",
|
| 13 |
+
f"pip{sys.version_info.major}.{sys.version_info.minor}",
|
| 14 |
+
]
|
| 15 |
+
if WINDOWS:
|
| 16 |
+
_allowed_extensions = {"", ".exe"}
|
| 17 |
+
_EXECUTABLE_NAMES = [
|
| 18 |
+
"".join(parts)
|
| 19 |
+
for parts in itertools.product(_EXECUTABLE_NAMES, _allowed_extensions)
|
| 20 |
+
]
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def _wrapper(args: Optional[List[str]] = None) -> int:
|
| 24 |
+
"""Central wrapper for all old entrypoints.
|
| 25 |
+
|
| 26 |
+
Historically pip has had several entrypoints defined. Because of issues
|
| 27 |
+
arising from PATH, sys.path, multiple Pythons, their interactions, and most
|
| 28 |
+
of them having a pip installed, users suffer every time an entrypoint gets
|
| 29 |
+
moved.
|
| 30 |
+
|
| 31 |
+
To alleviate this pain, and provide a mechanism for warning users and
|
| 32 |
+
directing them to an appropriate place for help, we now define all of
|
| 33 |
+
our old entrypoints as wrappers for the current one.
|
| 34 |
+
"""
|
| 35 |
+
sys.stderr.write(
|
| 36 |
+
"WARNING: pip is being invoked by an old script wrapper. This will "
|
| 37 |
+
"fail in a future version of pip.\n"
|
| 38 |
+
"Please see https://github.com/pypa/pip/issues/5599 for advice on "
|
| 39 |
+
"fixing the underlying issue.\n"
|
| 40 |
+
"To avoid this problem you can invoke Python with '-m pip' instead of "
|
| 41 |
+
"running pip directly.\n"
|
| 42 |
+
)
|
| 43 |
+
return main(args)
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
def get_best_invocation_for_this_pip() -> str:
|
| 47 |
+
"""Try to figure out the best way to invoke pip in the current environment."""
|
| 48 |
+
binary_directory = "Scripts" if WINDOWS else "bin"
|
| 49 |
+
binary_prefix = os.path.join(sys.prefix, binary_directory)
|
| 50 |
+
|
| 51 |
+
# Try to use pip[X[.Y]] names, if those executables for this environment are
|
| 52 |
+
# the first on PATH with that name.
|
| 53 |
+
path_parts = os.path.normcase(os.environ.get("PATH", "")).split(os.pathsep)
|
| 54 |
+
exe_are_in_PATH = os.path.normcase(binary_prefix) in path_parts
|
| 55 |
+
if exe_are_in_PATH:
|
| 56 |
+
for exe_name in _EXECUTABLE_NAMES:
|
| 57 |
+
found_executable = shutil.which(exe_name)
|
| 58 |
+
binary_executable = os.path.join(binary_prefix, exe_name)
|
| 59 |
+
if (
|
| 60 |
+
found_executable
|
| 61 |
+
and os.path.exists(binary_executable)
|
| 62 |
+
and os.path.samefile(
|
| 63 |
+
found_executable,
|
| 64 |
+
binary_executable,
|
| 65 |
+
)
|
| 66 |
+
):
|
| 67 |
+
return exe_name
|
| 68 |
+
|
| 69 |
+
# Use the `-m` invocation, if there's no "nice" invocation.
|
| 70 |
+
return f"{get_best_invocation_for_this_python()} -m pip"
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
def get_best_invocation_for_this_python() -> str:
|
| 74 |
+
"""Try to figure out the best way to invoke the current Python."""
|
| 75 |
+
exe = sys.executable
|
| 76 |
+
exe_name = os.path.basename(exe)
|
| 77 |
+
|
| 78 |
+
# Try to use the basename, if it's the first executable.
|
| 79 |
+
found_executable = shutil.which(exe_name)
|
| 80 |
+
if found_executable and os.path.samefile(found_executable, exe):
|
| 81 |
+
return exe_name
|
| 82 |
+
|
| 83 |
+
# Use the full executable name, because we couldn't find something simpler.
|
| 84 |
+
return exe
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/filesystem.py
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import fnmatch
|
| 2 |
+
import os
|
| 3 |
+
import os.path
|
| 4 |
+
import random
|
| 5 |
+
import sys
|
| 6 |
+
from contextlib import contextmanager
|
| 7 |
+
from tempfile import NamedTemporaryFile
|
| 8 |
+
from typing import Any, BinaryIO, Generator, List, Union, cast
|
| 9 |
+
|
| 10 |
+
from pip._vendor.tenacity import retry, stop_after_delay, wait_fixed
|
| 11 |
+
|
| 12 |
+
from pip._internal.utils.compat import get_path_uid
|
| 13 |
+
from pip._internal.utils.misc import format_size
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def check_path_owner(path: str) -> bool:
|
| 17 |
+
# If we don't have a way to check the effective uid of this process, then
|
| 18 |
+
# we'll just assume that we own the directory.
|
| 19 |
+
if sys.platform == "win32" or not hasattr(os, "geteuid"):
|
| 20 |
+
return True
|
| 21 |
+
|
| 22 |
+
assert os.path.isabs(path)
|
| 23 |
+
|
| 24 |
+
previous = None
|
| 25 |
+
while path != previous:
|
| 26 |
+
if os.path.lexists(path):
|
| 27 |
+
# Check if path is writable by current user.
|
| 28 |
+
if os.geteuid() == 0:
|
| 29 |
+
# Special handling for root user in order to handle properly
|
| 30 |
+
# cases where users use sudo without -H flag.
|
| 31 |
+
try:
|
| 32 |
+
path_uid = get_path_uid(path)
|
| 33 |
+
except OSError:
|
| 34 |
+
return False
|
| 35 |
+
return path_uid == 0
|
| 36 |
+
else:
|
| 37 |
+
return os.access(path, os.W_OK)
|
| 38 |
+
else:
|
| 39 |
+
previous, path = path, os.path.dirname(path)
|
| 40 |
+
return False # assume we don't own the path
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
@contextmanager
|
| 44 |
+
def adjacent_tmp_file(path: str, **kwargs: Any) -> Generator[BinaryIO, None, None]:
|
| 45 |
+
"""Return a file-like object pointing to a tmp file next to path.
|
| 46 |
+
|
| 47 |
+
The file is created securely and is ensured to be written to disk
|
| 48 |
+
after the context reaches its end.
|
| 49 |
+
|
| 50 |
+
kwargs will be passed to tempfile.NamedTemporaryFile to control
|
| 51 |
+
the way the temporary file will be opened.
|
| 52 |
+
"""
|
| 53 |
+
with NamedTemporaryFile(
|
| 54 |
+
delete=False,
|
| 55 |
+
dir=os.path.dirname(path),
|
| 56 |
+
prefix=os.path.basename(path),
|
| 57 |
+
suffix=".tmp",
|
| 58 |
+
**kwargs,
|
| 59 |
+
) as f:
|
| 60 |
+
result = cast(BinaryIO, f)
|
| 61 |
+
try:
|
| 62 |
+
yield result
|
| 63 |
+
finally:
|
| 64 |
+
result.flush()
|
| 65 |
+
os.fsync(result.fileno())
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
# Tenacity raises RetryError by default, explicitly raise the original exception
|
| 69 |
+
_replace_retry = retry(reraise=True, stop=stop_after_delay(1), wait=wait_fixed(0.25))
|
| 70 |
+
|
| 71 |
+
replace = _replace_retry(os.replace)
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
# test_writable_dir and _test_writable_dir_win are copied from Flit,
|
| 75 |
+
# with the author's agreement to also place them under pip's license.
|
| 76 |
+
def test_writable_dir(path: str) -> bool:
|
| 77 |
+
"""Check if a directory is writable.
|
| 78 |
+
|
| 79 |
+
Uses os.access() on POSIX, tries creating files on Windows.
|
| 80 |
+
"""
|
| 81 |
+
# If the directory doesn't exist, find the closest parent that does.
|
| 82 |
+
while not os.path.isdir(path):
|
| 83 |
+
parent = os.path.dirname(path)
|
| 84 |
+
if parent == path:
|
| 85 |
+
break # Should never get here, but infinite loops are bad
|
| 86 |
+
path = parent
|
| 87 |
+
|
| 88 |
+
if os.name == "posix":
|
| 89 |
+
return os.access(path, os.W_OK)
|
| 90 |
+
|
| 91 |
+
return _test_writable_dir_win(path)
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
def _test_writable_dir_win(path: str) -> bool:
|
| 95 |
+
# os.access doesn't work on Windows: http://bugs.python.org/issue2528
|
| 96 |
+
# and we can't use tempfile: http://bugs.python.org/issue22107
|
| 97 |
+
basename = "accesstest_deleteme_fishfingers_custard_"
|
| 98 |
+
alphabet = "abcdefghijklmnopqrstuvwxyz0123456789"
|
| 99 |
+
for _ in range(10):
|
| 100 |
+
name = basename + "".join(random.choice(alphabet) for _ in range(6))
|
| 101 |
+
file = os.path.join(path, name)
|
| 102 |
+
try:
|
| 103 |
+
fd = os.open(file, os.O_RDWR | os.O_CREAT | os.O_EXCL)
|
| 104 |
+
except FileExistsError:
|
| 105 |
+
pass
|
| 106 |
+
except PermissionError:
|
| 107 |
+
# This could be because there's a directory with the same name.
|
| 108 |
+
# But it's highly unlikely there's a directory called that,
|
| 109 |
+
# so we'll assume it's because the parent dir is not writable.
|
| 110 |
+
# This could as well be because the parent dir is not readable,
|
| 111 |
+
# due to non-privileged user access.
|
| 112 |
+
return False
|
| 113 |
+
else:
|
| 114 |
+
os.close(fd)
|
| 115 |
+
os.unlink(file)
|
| 116 |
+
return True
|
| 117 |
+
|
| 118 |
+
# This should never be reached
|
| 119 |
+
raise OSError("Unexpected condition testing for writable directory")
|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
def find_files(path: str, pattern: str) -> List[str]:
|
| 123 |
+
"""Returns a list of absolute paths of files beneath path, recursively,
|
| 124 |
+
with filenames which match the UNIX-style shell glob pattern."""
|
| 125 |
+
result: List[str] = []
|
| 126 |
+
for root, _, files in os.walk(path):
|
| 127 |
+
matches = fnmatch.filter(files, pattern)
|
| 128 |
+
result.extend(os.path.join(root, f) for f in matches)
|
| 129 |
+
return result
|
| 130 |
+
|
| 131 |
+
|
| 132 |
+
def file_size(path: str) -> Union[int, float]:
|
| 133 |
+
# If it's a symlink, return 0.
|
| 134 |
+
if os.path.islink(path):
|
| 135 |
+
return 0
|
| 136 |
+
return os.path.getsize(path)
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
def format_file_size(path: str) -> str:
|
| 140 |
+
return format_size(file_size(path))
|
| 141 |
+
|
| 142 |
+
|
| 143 |
+
def directory_size(path: str) -> Union[int, float]:
|
| 144 |
+
size = 0.0
|
| 145 |
+
for root, _dirs, files in os.walk(path):
|
| 146 |
+
for filename in files:
|
| 147 |
+
file_path = os.path.join(root, filename)
|
| 148 |
+
size += file_size(file_path)
|
| 149 |
+
return size
|
| 150 |
+
|
| 151 |
+
|
| 152 |
+
def format_directory_size(path: str) -> str:
|
| 153 |
+
return format_size(directory_size(path))
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/filetypes.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Filetype information.
|
| 2 |
+
"""
|
| 3 |
+
|
| 4 |
+
from typing import Tuple
|
| 5 |
+
|
| 6 |
+
from pip._internal.utils.misc import splitext
|
| 7 |
+
|
| 8 |
+
WHEEL_EXTENSION = ".whl"
|
| 9 |
+
BZ2_EXTENSIONS: Tuple[str, ...] = (".tar.bz2", ".tbz")
|
| 10 |
+
XZ_EXTENSIONS: Tuple[str, ...] = (
|
| 11 |
+
".tar.xz",
|
| 12 |
+
".txz",
|
| 13 |
+
".tlz",
|
| 14 |
+
".tar.lz",
|
| 15 |
+
".tar.lzma",
|
| 16 |
+
)
|
| 17 |
+
ZIP_EXTENSIONS: Tuple[str, ...] = (".zip", WHEEL_EXTENSION)
|
| 18 |
+
TAR_EXTENSIONS: Tuple[str, ...] = (".tar.gz", ".tgz", ".tar")
|
| 19 |
+
ARCHIVE_EXTENSIONS = ZIP_EXTENSIONS + BZ2_EXTENSIONS + TAR_EXTENSIONS + XZ_EXTENSIONS
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def is_archive_file(name: str) -> bool:
|
| 23 |
+
"""Return True if `name` is a considered as an archive file."""
|
| 24 |
+
ext = splitext(name)[1].lower()
|
| 25 |
+
if ext in ARCHIVE_EXTENSIONS:
|
| 26 |
+
return True
|
| 27 |
+
return False
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/glibc.py
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import sys
|
| 3 |
+
from typing import Optional, Tuple
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
def glibc_version_string() -> Optional[str]:
|
| 7 |
+
"Returns glibc version string, or None if not using glibc."
|
| 8 |
+
return glibc_version_string_confstr() or glibc_version_string_ctypes()
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
def glibc_version_string_confstr() -> Optional[str]:
|
| 12 |
+
"Primary implementation of glibc_version_string using os.confstr."
|
| 13 |
+
# os.confstr is quite a bit faster than ctypes.DLL. It's also less likely
|
| 14 |
+
# to be broken or missing. This strategy is used in the standard library
|
| 15 |
+
# platform module:
|
| 16 |
+
# https://github.com/python/cpython/blob/fcf1d003bf4f0100c9d0921ff3d70e1127ca1b71/Lib/platform.py#L175-L183
|
| 17 |
+
if sys.platform == "win32":
|
| 18 |
+
return None
|
| 19 |
+
try:
|
| 20 |
+
gnu_libc_version = os.confstr("CS_GNU_LIBC_VERSION")
|
| 21 |
+
if gnu_libc_version is None:
|
| 22 |
+
return None
|
| 23 |
+
# os.confstr("CS_GNU_LIBC_VERSION") returns a string like "glibc 2.17":
|
| 24 |
+
_, version = gnu_libc_version.split()
|
| 25 |
+
except (AttributeError, OSError, ValueError):
|
| 26 |
+
# os.confstr() or CS_GNU_LIBC_VERSION not available (or a bad value)...
|
| 27 |
+
return None
|
| 28 |
+
return version
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
def glibc_version_string_ctypes() -> Optional[str]:
|
| 32 |
+
"Fallback implementation of glibc_version_string using ctypes."
|
| 33 |
+
|
| 34 |
+
try:
|
| 35 |
+
import ctypes
|
| 36 |
+
except ImportError:
|
| 37 |
+
return None
|
| 38 |
+
|
| 39 |
+
# ctypes.CDLL(None) internally calls dlopen(NULL), and as the dlopen
|
| 40 |
+
# manpage says, "If filename is NULL, then the returned handle is for the
|
| 41 |
+
# main program". This way we can let the linker do the work to figure out
|
| 42 |
+
# which libc our process is actually using.
|
| 43 |
+
process_namespace = ctypes.CDLL(None)
|
| 44 |
+
try:
|
| 45 |
+
gnu_get_libc_version = process_namespace.gnu_get_libc_version
|
| 46 |
+
except AttributeError:
|
| 47 |
+
# Symbol doesn't exist -> therefore, we are not linked to
|
| 48 |
+
# glibc.
|
| 49 |
+
return None
|
| 50 |
+
|
| 51 |
+
# Call gnu_get_libc_version, which returns a string like "2.5"
|
| 52 |
+
gnu_get_libc_version.restype = ctypes.c_char_p
|
| 53 |
+
version_str = gnu_get_libc_version()
|
| 54 |
+
# py2 / py3 compatibility:
|
| 55 |
+
if not isinstance(version_str, str):
|
| 56 |
+
version_str = version_str.decode("ascii")
|
| 57 |
+
|
| 58 |
+
return version_str
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
# platform.libc_ver regularly returns completely nonsensical glibc
|
| 62 |
+
# versions. E.g. on my computer, platform says:
|
| 63 |
+
#
|
| 64 |
+
# ~$ python2.7 -c 'import platform; print(platform.libc_ver())'
|
| 65 |
+
# ('glibc', '2.7')
|
| 66 |
+
# ~$ python3.5 -c 'import platform; print(platform.libc_ver())'
|
| 67 |
+
# ('glibc', '2.9')
|
| 68 |
+
#
|
| 69 |
+
# But the truth is:
|
| 70 |
+
#
|
| 71 |
+
# ~$ ldd --version
|
| 72 |
+
# ldd (Debian GLIBC 2.22-11) 2.22
|
| 73 |
+
#
|
| 74 |
+
# This is unfortunate, because it means that the linehaul data on libc
|
| 75 |
+
# versions that was generated by pip 8.1.2 and earlier is useless and
|
| 76 |
+
# misleading. Solution: instead of using platform, use our code that actually
|
| 77 |
+
# works.
|
| 78 |
+
def libc_ver() -> Tuple[str, str]:
|
| 79 |
+
"""Try to determine the glibc version
|
| 80 |
+
|
| 81 |
+
Returns a tuple of strings (lib, version) which default to empty strings
|
| 82 |
+
in case the lookup fails.
|
| 83 |
+
"""
|
| 84 |
+
glibc_version = glibc_version_string()
|
| 85 |
+
if glibc_version is None:
|
| 86 |
+
return ("", "")
|
| 87 |
+
else:
|
| 88 |
+
return ("glibc", glibc_version)
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/misc.py
ADDED
|
@@ -0,0 +1,783 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import contextlib
|
| 2 |
+
import errno
|
| 3 |
+
import getpass
|
| 4 |
+
import hashlib
|
| 5 |
+
import io
|
| 6 |
+
import logging
|
| 7 |
+
import os
|
| 8 |
+
import posixpath
|
| 9 |
+
import shutil
|
| 10 |
+
import stat
|
| 11 |
+
import sys
|
| 12 |
+
import sysconfig
|
| 13 |
+
import urllib.parse
|
| 14 |
+
from functools import partial
|
| 15 |
+
from io import StringIO
|
| 16 |
+
from itertools import filterfalse, tee, zip_longest
|
| 17 |
+
from pathlib import Path
|
| 18 |
+
from types import FunctionType, TracebackType
|
| 19 |
+
from typing import (
|
| 20 |
+
Any,
|
| 21 |
+
BinaryIO,
|
| 22 |
+
Callable,
|
| 23 |
+
ContextManager,
|
| 24 |
+
Dict,
|
| 25 |
+
Generator,
|
| 26 |
+
Iterable,
|
| 27 |
+
Iterator,
|
| 28 |
+
List,
|
| 29 |
+
Optional,
|
| 30 |
+
TextIO,
|
| 31 |
+
Tuple,
|
| 32 |
+
Type,
|
| 33 |
+
TypeVar,
|
| 34 |
+
Union,
|
| 35 |
+
cast,
|
| 36 |
+
)
|
| 37 |
+
|
| 38 |
+
from pip._vendor.packaging.requirements import Requirement
|
| 39 |
+
from pip._vendor.pyproject_hooks import BuildBackendHookCaller
|
| 40 |
+
from pip._vendor.tenacity import retry, stop_after_delay, wait_fixed
|
| 41 |
+
|
| 42 |
+
from pip import __version__
|
| 43 |
+
from pip._internal.exceptions import CommandError, ExternallyManagedEnvironment
|
| 44 |
+
from pip._internal.locations import get_major_minor_version
|
| 45 |
+
from pip._internal.utils.compat import WINDOWS
|
| 46 |
+
from pip._internal.utils.virtualenv import running_under_virtualenv
|
| 47 |
+
|
| 48 |
+
__all__ = [
|
| 49 |
+
"rmtree",
|
| 50 |
+
"display_path",
|
| 51 |
+
"backup_dir",
|
| 52 |
+
"ask",
|
| 53 |
+
"splitext",
|
| 54 |
+
"format_size",
|
| 55 |
+
"is_installable_dir",
|
| 56 |
+
"normalize_path",
|
| 57 |
+
"renames",
|
| 58 |
+
"get_prog",
|
| 59 |
+
"captured_stdout",
|
| 60 |
+
"ensure_dir",
|
| 61 |
+
"remove_auth_from_url",
|
| 62 |
+
"check_externally_managed",
|
| 63 |
+
"ConfiguredBuildBackendHookCaller",
|
| 64 |
+
]
|
| 65 |
+
|
| 66 |
+
logger = logging.getLogger(__name__)
|
| 67 |
+
|
| 68 |
+
T = TypeVar("T")
|
| 69 |
+
ExcInfo = Tuple[Type[BaseException], BaseException, TracebackType]
|
| 70 |
+
VersionInfo = Tuple[int, int, int]
|
| 71 |
+
NetlocTuple = Tuple[str, Tuple[Optional[str], Optional[str]]]
|
| 72 |
+
OnExc = Callable[[FunctionType, Path, BaseException], Any]
|
| 73 |
+
OnErr = Callable[[FunctionType, Path, ExcInfo], Any]
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
def get_pip_version() -> str:
|
| 77 |
+
pip_pkg_dir = os.path.join(os.path.dirname(__file__), "..", "..")
|
| 78 |
+
pip_pkg_dir = os.path.abspath(pip_pkg_dir)
|
| 79 |
+
|
| 80 |
+
return f"pip {__version__} from {pip_pkg_dir} (python {get_major_minor_version()})"
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
def normalize_version_info(py_version_info: Tuple[int, ...]) -> Tuple[int, int, int]:
|
| 84 |
+
"""
|
| 85 |
+
Convert a tuple of ints representing a Python version to one of length
|
| 86 |
+
three.
|
| 87 |
+
|
| 88 |
+
:param py_version_info: a tuple of ints representing a Python version,
|
| 89 |
+
or None to specify no version. The tuple can have any length.
|
| 90 |
+
|
| 91 |
+
:return: a tuple of length three if `py_version_info` is non-None.
|
| 92 |
+
Otherwise, return `py_version_info` unchanged (i.e. None).
|
| 93 |
+
"""
|
| 94 |
+
if len(py_version_info) < 3:
|
| 95 |
+
py_version_info += (3 - len(py_version_info)) * (0,)
|
| 96 |
+
elif len(py_version_info) > 3:
|
| 97 |
+
py_version_info = py_version_info[:3]
|
| 98 |
+
|
| 99 |
+
return cast("VersionInfo", py_version_info)
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
def ensure_dir(path: str) -> None:
|
| 103 |
+
"""os.path.makedirs without EEXIST."""
|
| 104 |
+
try:
|
| 105 |
+
os.makedirs(path)
|
| 106 |
+
except OSError as e:
|
| 107 |
+
# Windows can raise spurious ENOTEMPTY errors. See #6426.
|
| 108 |
+
if e.errno != errno.EEXIST and e.errno != errno.ENOTEMPTY:
|
| 109 |
+
raise
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
def get_prog() -> str:
|
| 113 |
+
try:
|
| 114 |
+
prog = os.path.basename(sys.argv[0])
|
| 115 |
+
if prog in ("__main__.py", "-c"):
|
| 116 |
+
return f"{sys.executable} -m pip"
|
| 117 |
+
else:
|
| 118 |
+
return prog
|
| 119 |
+
except (AttributeError, TypeError, IndexError):
|
| 120 |
+
pass
|
| 121 |
+
return "pip"
|
| 122 |
+
|
| 123 |
+
|
| 124 |
+
# Retry every half second for up to 3 seconds
|
| 125 |
+
# Tenacity raises RetryError by default, explicitly raise the original exception
|
| 126 |
+
@retry(reraise=True, stop=stop_after_delay(3), wait=wait_fixed(0.5))
|
| 127 |
+
def rmtree(
|
| 128 |
+
dir: str,
|
| 129 |
+
ignore_errors: bool = False,
|
| 130 |
+
onexc: Optional[OnExc] = None,
|
| 131 |
+
) -> None:
|
| 132 |
+
if ignore_errors:
|
| 133 |
+
onexc = _onerror_ignore
|
| 134 |
+
if onexc is None:
|
| 135 |
+
onexc = _onerror_reraise
|
| 136 |
+
handler: OnErr = partial(
|
| 137 |
+
# `[func, path, Union[ExcInfo, BaseException]] -> Any` is equivalent to
|
| 138 |
+
# `Union[([func, path, ExcInfo] -> Any), ([func, path, BaseException] -> Any)]`.
|
| 139 |
+
cast(Union[OnExc, OnErr], rmtree_errorhandler),
|
| 140 |
+
onexc=onexc,
|
| 141 |
+
)
|
| 142 |
+
if sys.version_info >= (3, 12):
|
| 143 |
+
# See https://docs.python.org/3.12/whatsnew/3.12.html#shutil.
|
| 144 |
+
shutil.rmtree(dir, onexc=handler) # type: ignore
|
| 145 |
+
else:
|
| 146 |
+
shutil.rmtree(dir, onerror=handler) # type: ignore
|
| 147 |
+
|
| 148 |
+
|
| 149 |
+
def _onerror_ignore(*_args: Any) -> None:
|
| 150 |
+
pass
|
| 151 |
+
|
| 152 |
+
|
| 153 |
+
def _onerror_reraise(*_args: Any) -> None:
|
| 154 |
+
raise
|
| 155 |
+
|
| 156 |
+
|
| 157 |
+
def rmtree_errorhandler(
|
| 158 |
+
func: FunctionType,
|
| 159 |
+
path: Path,
|
| 160 |
+
exc_info: Union[ExcInfo, BaseException],
|
| 161 |
+
*,
|
| 162 |
+
onexc: OnExc = _onerror_reraise,
|
| 163 |
+
) -> None:
|
| 164 |
+
"""
|
| 165 |
+
`rmtree` error handler to 'force' a file remove (i.e. like `rm -f`).
|
| 166 |
+
|
| 167 |
+
* If a file is readonly then it's write flag is set and operation is
|
| 168 |
+
retried.
|
| 169 |
+
|
| 170 |
+
* `onerror` is the original callback from `rmtree(... onerror=onerror)`
|
| 171 |
+
that is chained at the end if the "rm -f" still fails.
|
| 172 |
+
"""
|
| 173 |
+
try:
|
| 174 |
+
st_mode = os.stat(path).st_mode
|
| 175 |
+
except OSError:
|
| 176 |
+
# it's equivalent to os.path.exists
|
| 177 |
+
return
|
| 178 |
+
|
| 179 |
+
if not st_mode & stat.S_IWRITE:
|
| 180 |
+
# convert to read/write
|
| 181 |
+
try:
|
| 182 |
+
os.chmod(path, st_mode | stat.S_IWRITE)
|
| 183 |
+
except OSError:
|
| 184 |
+
pass
|
| 185 |
+
else:
|
| 186 |
+
# use the original function to repeat the operation
|
| 187 |
+
try:
|
| 188 |
+
func(path)
|
| 189 |
+
return
|
| 190 |
+
except OSError:
|
| 191 |
+
pass
|
| 192 |
+
|
| 193 |
+
if not isinstance(exc_info, BaseException):
|
| 194 |
+
_, exc_info, _ = exc_info
|
| 195 |
+
onexc(func, path, exc_info)
|
| 196 |
+
|
| 197 |
+
|
| 198 |
+
def display_path(path: str) -> str:
|
| 199 |
+
"""Gives the display value for a given path, making it relative to cwd
|
| 200 |
+
if possible."""
|
| 201 |
+
path = os.path.normcase(os.path.abspath(path))
|
| 202 |
+
if path.startswith(os.getcwd() + os.path.sep):
|
| 203 |
+
path = "." + path[len(os.getcwd()) :]
|
| 204 |
+
return path
|
| 205 |
+
|
| 206 |
+
|
| 207 |
+
def backup_dir(dir: str, ext: str = ".bak") -> str:
|
| 208 |
+
"""Figure out the name of a directory to back up the given dir to
|
| 209 |
+
(adding .bak, .bak2, etc)"""
|
| 210 |
+
n = 1
|
| 211 |
+
extension = ext
|
| 212 |
+
while os.path.exists(dir + extension):
|
| 213 |
+
n += 1
|
| 214 |
+
extension = ext + str(n)
|
| 215 |
+
return dir + extension
|
| 216 |
+
|
| 217 |
+
|
| 218 |
+
def ask_path_exists(message: str, options: Iterable[str]) -> str:
|
| 219 |
+
for action in os.environ.get("PIP_EXISTS_ACTION", "").split():
|
| 220 |
+
if action in options:
|
| 221 |
+
return action
|
| 222 |
+
return ask(message, options)
|
| 223 |
+
|
| 224 |
+
|
| 225 |
+
def _check_no_input(message: str) -> None:
|
| 226 |
+
"""Raise an error if no input is allowed."""
|
| 227 |
+
if os.environ.get("PIP_NO_INPUT"):
|
| 228 |
+
raise Exception(
|
| 229 |
+
f"No input was expected ($PIP_NO_INPUT set); question: {message}"
|
| 230 |
+
)
|
| 231 |
+
|
| 232 |
+
|
| 233 |
+
def ask(message: str, options: Iterable[str]) -> str:
|
| 234 |
+
"""Ask the message interactively, with the given possible responses"""
|
| 235 |
+
while 1:
|
| 236 |
+
_check_no_input(message)
|
| 237 |
+
response = input(message)
|
| 238 |
+
response = response.strip().lower()
|
| 239 |
+
if response not in options:
|
| 240 |
+
print(
|
| 241 |
+
"Your response ({!r}) was not one of the expected responses: "
|
| 242 |
+
"{}".format(response, ", ".join(options))
|
| 243 |
+
)
|
| 244 |
+
else:
|
| 245 |
+
return response
|
| 246 |
+
|
| 247 |
+
|
| 248 |
+
def ask_input(message: str) -> str:
|
| 249 |
+
"""Ask for input interactively."""
|
| 250 |
+
_check_no_input(message)
|
| 251 |
+
return input(message)
|
| 252 |
+
|
| 253 |
+
|
| 254 |
+
def ask_password(message: str) -> str:
|
| 255 |
+
"""Ask for a password interactively."""
|
| 256 |
+
_check_no_input(message)
|
| 257 |
+
return getpass.getpass(message)
|
| 258 |
+
|
| 259 |
+
|
| 260 |
+
def strtobool(val: str) -> int:
|
| 261 |
+
"""Convert a string representation of truth to true (1) or false (0).
|
| 262 |
+
|
| 263 |
+
True values are 'y', 'yes', 't', 'true', 'on', and '1'; false values
|
| 264 |
+
are 'n', 'no', 'f', 'false', 'off', and '0'. Raises ValueError if
|
| 265 |
+
'val' is anything else.
|
| 266 |
+
"""
|
| 267 |
+
val = val.lower()
|
| 268 |
+
if val in ("y", "yes", "t", "true", "on", "1"):
|
| 269 |
+
return 1
|
| 270 |
+
elif val in ("n", "no", "f", "false", "off", "0"):
|
| 271 |
+
return 0
|
| 272 |
+
else:
|
| 273 |
+
raise ValueError(f"invalid truth value {val!r}")
|
| 274 |
+
|
| 275 |
+
|
| 276 |
+
def format_size(bytes: float) -> str:
|
| 277 |
+
if bytes > 1000 * 1000:
|
| 278 |
+
return f"{bytes / 1000.0 / 1000:.1f} MB"
|
| 279 |
+
elif bytes > 10 * 1000:
|
| 280 |
+
return f"{int(bytes / 1000)} kB"
|
| 281 |
+
elif bytes > 1000:
|
| 282 |
+
return f"{bytes / 1000.0:.1f} kB"
|
| 283 |
+
else:
|
| 284 |
+
return f"{int(bytes)} bytes"
|
| 285 |
+
|
| 286 |
+
|
| 287 |
+
def tabulate(rows: Iterable[Iterable[Any]]) -> Tuple[List[str], List[int]]:
|
| 288 |
+
"""Return a list of formatted rows and a list of column sizes.
|
| 289 |
+
|
| 290 |
+
For example::
|
| 291 |
+
|
| 292 |
+
>>> tabulate([['foobar', 2000], [0xdeadbeef]])
|
| 293 |
+
(['foobar 2000', '3735928559'], [10, 4])
|
| 294 |
+
"""
|
| 295 |
+
rows = [tuple(map(str, row)) for row in rows]
|
| 296 |
+
sizes = [max(map(len, col)) for col in zip_longest(*rows, fillvalue="")]
|
| 297 |
+
table = [" ".join(map(str.ljust, row, sizes)).rstrip() for row in rows]
|
| 298 |
+
return table, sizes
|
| 299 |
+
|
| 300 |
+
|
| 301 |
+
def is_installable_dir(path: str) -> bool:
|
| 302 |
+
"""Is path is a directory containing pyproject.toml or setup.py?
|
| 303 |
+
|
| 304 |
+
If pyproject.toml exists, this is a PEP 517 project. Otherwise we look for
|
| 305 |
+
a legacy setuptools layout by identifying setup.py. We don't check for the
|
| 306 |
+
setup.cfg because using it without setup.py is only available for PEP 517
|
| 307 |
+
projects, which are already covered by the pyproject.toml check.
|
| 308 |
+
"""
|
| 309 |
+
if not os.path.isdir(path):
|
| 310 |
+
return False
|
| 311 |
+
if os.path.isfile(os.path.join(path, "pyproject.toml")):
|
| 312 |
+
return True
|
| 313 |
+
if os.path.isfile(os.path.join(path, "setup.py")):
|
| 314 |
+
return True
|
| 315 |
+
return False
|
| 316 |
+
|
| 317 |
+
|
| 318 |
+
def read_chunks(
|
| 319 |
+
file: BinaryIO, size: int = io.DEFAULT_BUFFER_SIZE
|
| 320 |
+
) -> Generator[bytes, None, None]:
|
| 321 |
+
"""Yield pieces of data from a file-like object until EOF."""
|
| 322 |
+
while True:
|
| 323 |
+
chunk = file.read(size)
|
| 324 |
+
if not chunk:
|
| 325 |
+
break
|
| 326 |
+
yield chunk
|
| 327 |
+
|
| 328 |
+
|
| 329 |
+
def normalize_path(path: str, resolve_symlinks: bool = True) -> str:
|
| 330 |
+
"""
|
| 331 |
+
Convert a path to its canonical, case-normalized, absolute version.
|
| 332 |
+
|
| 333 |
+
"""
|
| 334 |
+
path = os.path.expanduser(path)
|
| 335 |
+
if resolve_symlinks:
|
| 336 |
+
path = os.path.realpath(path)
|
| 337 |
+
else:
|
| 338 |
+
path = os.path.abspath(path)
|
| 339 |
+
return os.path.normcase(path)
|
| 340 |
+
|
| 341 |
+
|
| 342 |
+
def splitext(path: str) -> Tuple[str, str]:
|
| 343 |
+
"""Like os.path.splitext, but take off .tar too"""
|
| 344 |
+
base, ext = posixpath.splitext(path)
|
| 345 |
+
if base.lower().endswith(".tar"):
|
| 346 |
+
ext = base[-4:] + ext
|
| 347 |
+
base = base[:-4]
|
| 348 |
+
return base, ext
|
| 349 |
+
|
| 350 |
+
|
| 351 |
+
def renames(old: str, new: str) -> None:
|
| 352 |
+
"""Like os.renames(), but handles renaming across devices."""
|
| 353 |
+
# Implementation borrowed from os.renames().
|
| 354 |
+
head, tail = os.path.split(new)
|
| 355 |
+
if head and tail and not os.path.exists(head):
|
| 356 |
+
os.makedirs(head)
|
| 357 |
+
|
| 358 |
+
shutil.move(old, new)
|
| 359 |
+
|
| 360 |
+
head, tail = os.path.split(old)
|
| 361 |
+
if head and tail:
|
| 362 |
+
try:
|
| 363 |
+
os.removedirs(head)
|
| 364 |
+
except OSError:
|
| 365 |
+
pass
|
| 366 |
+
|
| 367 |
+
|
| 368 |
+
def is_local(path: str) -> bool:
|
| 369 |
+
"""
|
| 370 |
+
Return True if path is within sys.prefix, if we're running in a virtualenv.
|
| 371 |
+
|
| 372 |
+
If we're not in a virtualenv, all paths are considered "local."
|
| 373 |
+
|
| 374 |
+
Caution: this function assumes the head of path has been normalized
|
| 375 |
+
with normalize_path.
|
| 376 |
+
"""
|
| 377 |
+
if not running_under_virtualenv():
|
| 378 |
+
return True
|
| 379 |
+
return path.startswith(normalize_path(sys.prefix))
|
| 380 |
+
|
| 381 |
+
|
| 382 |
+
def write_output(msg: Any, *args: Any) -> None:
|
| 383 |
+
logger.info(msg, *args)
|
| 384 |
+
|
| 385 |
+
|
| 386 |
+
class StreamWrapper(StringIO):
|
| 387 |
+
orig_stream: TextIO
|
| 388 |
+
|
| 389 |
+
@classmethod
|
| 390 |
+
def from_stream(cls, orig_stream: TextIO) -> "StreamWrapper":
|
| 391 |
+
ret = cls()
|
| 392 |
+
ret.orig_stream = orig_stream
|
| 393 |
+
return ret
|
| 394 |
+
|
| 395 |
+
# compileall.compile_dir() needs stdout.encoding to print to stdout
|
| 396 |
+
# type ignore is because TextIOBase.encoding is writeable
|
| 397 |
+
@property
|
| 398 |
+
def encoding(self) -> str: # type: ignore
|
| 399 |
+
return self.orig_stream.encoding
|
| 400 |
+
|
| 401 |
+
|
| 402 |
+
@contextlib.contextmanager
|
| 403 |
+
def captured_output(stream_name: str) -> Generator[StreamWrapper, None, None]:
|
| 404 |
+
"""Return a context manager used by captured_stdout/stdin/stderr
|
| 405 |
+
that temporarily replaces the sys stream *stream_name* with a StringIO.
|
| 406 |
+
|
| 407 |
+
Taken from Lib/support/__init__.py in the CPython repo.
|
| 408 |
+
"""
|
| 409 |
+
orig_stdout = getattr(sys, stream_name)
|
| 410 |
+
setattr(sys, stream_name, StreamWrapper.from_stream(orig_stdout))
|
| 411 |
+
try:
|
| 412 |
+
yield getattr(sys, stream_name)
|
| 413 |
+
finally:
|
| 414 |
+
setattr(sys, stream_name, orig_stdout)
|
| 415 |
+
|
| 416 |
+
|
| 417 |
+
def captured_stdout() -> ContextManager[StreamWrapper]:
|
| 418 |
+
"""Capture the output of sys.stdout:
|
| 419 |
+
|
| 420 |
+
with captured_stdout() as stdout:
|
| 421 |
+
print('hello')
|
| 422 |
+
self.assertEqual(stdout.getvalue(), 'hello\n')
|
| 423 |
+
|
| 424 |
+
Taken from Lib/support/__init__.py in the CPython repo.
|
| 425 |
+
"""
|
| 426 |
+
return captured_output("stdout")
|
| 427 |
+
|
| 428 |
+
|
| 429 |
+
def captured_stderr() -> ContextManager[StreamWrapper]:
|
| 430 |
+
"""
|
| 431 |
+
See captured_stdout().
|
| 432 |
+
"""
|
| 433 |
+
return captured_output("stderr")
|
| 434 |
+
|
| 435 |
+
|
| 436 |
+
# Simulates an enum
|
| 437 |
+
def enum(*sequential: Any, **named: Any) -> Type[Any]:
|
| 438 |
+
enums = dict(zip(sequential, range(len(sequential))), **named)
|
| 439 |
+
reverse = {value: key for key, value in enums.items()}
|
| 440 |
+
enums["reverse_mapping"] = reverse
|
| 441 |
+
return type("Enum", (), enums)
|
| 442 |
+
|
| 443 |
+
|
| 444 |
+
def build_netloc(host: str, port: Optional[int]) -> str:
|
| 445 |
+
"""
|
| 446 |
+
Build a netloc from a host-port pair
|
| 447 |
+
"""
|
| 448 |
+
if port is None:
|
| 449 |
+
return host
|
| 450 |
+
if ":" in host:
|
| 451 |
+
# Only wrap host with square brackets when it is IPv6
|
| 452 |
+
host = f"[{host}]"
|
| 453 |
+
return f"{host}:{port}"
|
| 454 |
+
|
| 455 |
+
|
| 456 |
+
def build_url_from_netloc(netloc: str, scheme: str = "https") -> str:
|
| 457 |
+
"""
|
| 458 |
+
Build a full URL from a netloc.
|
| 459 |
+
"""
|
| 460 |
+
if netloc.count(":") >= 2 and "@" not in netloc and "[" not in netloc:
|
| 461 |
+
# It must be a bare IPv6 address, so wrap it with brackets.
|
| 462 |
+
netloc = f"[{netloc}]"
|
| 463 |
+
return f"{scheme}://{netloc}"
|
| 464 |
+
|
| 465 |
+
|
| 466 |
+
def parse_netloc(netloc: str) -> Tuple[Optional[str], Optional[int]]:
|
| 467 |
+
"""
|
| 468 |
+
Return the host-port pair from a netloc.
|
| 469 |
+
"""
|
| 470 |
+
url = build_url_from_netloc(netloc)
|
| 471 |
+
parsed = urllib.parse.urlparse(url)
|
| 472 |
+
return parsed.hostname, parsed.port
|
| 473 |
+
|
| 474 |
+
|
| 475 |
+
def split_auth_from_netloc(netloc: str) -> NetlocTuple:
|
| 476 |
+
"""
|
| 477 |
+
Parse out and remove the auth information from a netloc.
|
| 478 |
+
|
| 479 |
+
Returns: (netloc, (username, password)).
|
| 480 |
+
"""
|
| 481 |
+
if "@" not in netloc:
|
| 482 |
+
return netloc, (None, None)
|
| 483 |
+
|
| 484 |
+
# Split from the right because that's how urllib.parse.urlsplit()
|
| 485 |
+
# behaves if more than one @ is present (which can be checked using
|
| 486 |
+
# the password attribute of urlsplit()'s return value).
|
| 487 |
+
auth, netloc = netloc.rsplit("@", 1)
|
| 488 |
+
pw: Optional[str] = None
|
| 489 |
+
if ":" in auth:
|
| 490 |
+
# Split from the left because that's how urllib.parse.urlsplit()
|
| 491 |
+
# behaves if more than one : is present (which again can be checked
|
| 492 |
+
# using the password attribute of the return value)
|
| 493 |
+
user, pw = auth.split(":", 1)
|
| 494 |
+
else:
|
| 495 |
+
user, pw = auth, None
|
| 496 |
+
|
| 497 |
+
user = urllib.parse.unquote(user)
|
| 498 |
+
if pw is not None:
|
| 499 |
+
pw = urllib.parse.unquote(pw)
|
| 500 |
+
|
| 501 |
+
return netloc, (user, pw)
|
| 502 |
+
|
| 503 |
+
|
| 504 |
+
def redact_netloc(netloc: str) -> str:
|
| 505 |
+
"""
|
| 506 |
+
Replace the sensitive data in a netloc with "****", if it exists.
|
| 507 |
+
|
| 508 |
+
For example:
|
| 509 |
+
- "user:pass@example.com" returns "user:****@example.com"
|
| 510 |
+
- "accesstoken@example.com" returns "****@example.com"
|
| 511 |
+
"""
|
| 512 |
+
netloc, (user, password) = split_auth_from_netloc(netloc)
|
| 513 |
+
if user is None:
|
| 514 |
+
return netloc
|
| 515 |
+
if password is None:
|
| 516 |
+
user = "****"
|
| 517 |
+
password = ""
|
| 518 |
+
else:
|
| 519 |
+
user = urllib.parse.quote(user)
|
| 520 |
+
password = ":****"
|
| 521 |
+
return f"{user}{password}@{netloc}"
|
| 522 |
+
|
| 523 |
+
|
| 524 |
+
def _transform_url(
|
| 525 |
+
url: str, transform_netloc: Callable[[str], Tuple[Any, ...]]
|
| 526 |
+
) -> Tuple[str, NetlocTuple]:
|
| 527 |
+
"""Transform and replace netloc in a url.
|
| 528 |
+
|
| 529 |
+
transform_netloc is a function taking the netloc and returning a
|
| 530 |
+
tuple. The first element of this tuple is the new netloc. The
|
| 531 |
+
entire tuple is returned.
|
| 532 |
+
|
| 533 |
+
Returns a tuple containing the transformed url as item 0 and the
|
| 534 |
+
original tuple returned by transform_netloc as item 1.
|
| 535 |
+
"""
|
| 536 |
+
purl = urllib.parse.urlsplit(url)
|
| 537 |
+
netloc_tuple = transform_netloc(purl.netloc)
|
| 538 |
+
# stripped url
|
| 539 |
+
url_pieces = (purl.scheme, netloc_tuple[0], purl.path, purl.query, purl.fragment)
|
| 540 |
+
surl = urllib.parse.urlunsplit(url_pieces)
|
| 541 |
+
return surl, cast("NetlocTuple", netloc_tuple)
|
| 542 |
+
|
| 543 |
+
|
| 544 |
+
def _get_netloc(netloc: str) -> NetlocTuple:
|
| 545 |
+
return split_auth_from_netloc(netloc)
|
| 546 |
+
|
| 547 |
+
|
| 548 |
+
def _redact_netloc(netloc: str) -> Tuple[str]:
|
| 549 |
+
return (redact_netloc(netloc),)
|
| 550 |
+
|
| 551 |
+
|
| 552 |
+
def split_auth_netloc_from_url(
|
| 553 |
+
url: str,
|
| 554 |
+
) -> Tuple[str, str, Tuple[Optional[str], Optional[str]]]:
|
| 555 |
+
"""
|
| 556 |
+
Parse a url into separate netloc, auth, and url with no auth.
|
| 557 |
+
|
| 558 |
+
Returns: (url_without_auth, netloc, (username, password))
|
| 559 |
+
"""
|
| 560 |
+
url_without_auth, (netloc, auth) = _transform_url(url, _get_netloc)
|
| 561 |
+
return url_without_auth, netloc, auth
|
| 562 |
+
|
| 563 |
+
|
| 564 |
+
def remove_auth_from_url(url: str) -> str:
|
| 565 |
+
"""Return a copy of url with 'username:password@' removed."""
|
| 566 |
+
# username/pass params are passed to subversion through flags
|
| 567 |
+
# and are not recognized in the url.
|
| 568 |
+
return _transform_url(url, _get_netloc)[0]
|
| 569 |
+
|
| 570 |
+
|
| 571 |
+
def redact_auth_from_url(url: str) -> str:
|
| 572 |
+
"""Replace the password in a given url with ****."""
|
| 573 |
+
return _transform_url(url, _redact_netloc)[0]
|
| 574 |
+
|
| 575 |
+
|
| 576 |
+
def redact_auth_from_requirement(req: Requirement) -> str:
|
| 577 |
+
"""Replace the password in a given requirement url with ****."""
|
| 578 |
+
if not req.url:
|
| 579 |
+
return str(req)
|
| 580 |
+
return str(req).replace(req.url, redact_auth_from_url(req.url))
|
| 581 |
+
|
| 582 |
+
|
| 583 |
+
class HiddenText:
|
| 584 |
+
def __init__(self, secret: str, redacted: str) -> None:
|
| 585 |
+
self.secret = secret
|
| 586 |
+
self.redacted = redacted
|
| 587 |
+
|
| 588 |
+
def __repr__(self) -> str:
|
| 589 |
+
return f"<HiddenText {str(self)!r}>"
|
| 590 |
+
|
| 591 |
+
def __str__(self) -> str:
|
| 592 |
+
return self.redacted
|
| 593 |
+
|
| 594 |
+
# This is useful for testing.
|
| 595 |
+
def __eq__(self, other: Any) -> bool:
|
| 596 |
+
if type(self) != type(other):
|
| 597 |
+
return False
|
| 598 |
+
|
| 599 |
+
# The string being used for redaction doesn't also have to match,
|
| 600 |
+
# just the raw, original string.
|
| 601 |
+
return self.secret == other.secret
|
| 602 |
+
|
| 603 |
+
|
| 604 |
+
def hide_value(value: str) -> HiddenText:
|
| 605 |
+
return HiddenText(value, redacted="****")
|
| 606 |
+
|
| 607 |
+
|
| 608 |
+
def hide_url(url: str) -> HiddenText:
|
| 609 |
+
redacted = redact_auth_from_url(url)
|
| 610 |
+
return HiddenText(url, redacted=redacted)
|
| 611 |
+
|
| 612 |
+
|
| 613 |
+
def protect_pip_from_modification_on_windows(modifying_pip: bool) -> None:
|
| 614 |
+
"""Protection of pip.exe from modification on Windows
|
| 615 |
+
|
| 616 |
+
On Windows, any operation modifying pip should be run as:
|
| 617 |
+
python -m pip ...
|
| 618 |
+
"""
|
| 619 |
+
pip_names = [
|
| 620 |
+
"pip",
|
| 621 |
+
f"pip{sys.version_info.major}",
|
| 622 |
+
f"pip{sys.version_info.major}.{sys.version_info.minor}",
|
| 623 |
+
]
|
| 624 |
+
|
| 625 |
+
# See https://github.com/pypa/pip/issues/1299 for more discussion
|
| 626 |
+
should_show_use_python_msg = (
|
| 627 |
+
modifying_pip and WINDOWS and os.path.basename(sys.argv[0]) in pip_names
|
| 628 |
+
)
|
| 629 |
+
|
| 630 |
+
if should_show_use_python_msg:
|
| 631 |
+
new_command = [sys.executable, "-m", "pip"] + sys.argv[1:]
|
| 632 |
+
raise CommandError(
|
| 633 |
+
"To modify pip, please run the following command:\n{}".format(
|
| 634 |
+
" ".join(new_command)
|
| 635 |
+
)
|
| 636 |
+
)
|
| 637 |
+
|
| 638 |
+
|
| 639 |
+
def check_externally_managed() -> None:
|
| 640 |
+
"""Check whether the current environment is externally managed.
|
| 641 |
+
|
| 642 |
+
If the ``EXTERNALLY-MANAGED`` config file is found, the current environment
|
| 643 |
+
is considered externally managed, and an ExternallyManagedEnvironment is
|
| 644 |
+
raised.
|
| 645 |
+
"""
|
| 646 |
+
if running_under_virtualenv():
|
| 647 |
+
return
|
| 648 |
+
marker = os.path.join(sysconfig.get_path("stdlib"), "EXTERNALLY-MANAGED")
|
| 649 |
+
if not os.path.isfile(marker):
|
| 650 |
+
return
|
| 651 |
+
raise ExternallyManagedEnvironment.from_config(marker)
|
| 652 |
+
|
| 653 |
+
|
| 654 |
+
def is_console_interactive() -> bool:
|
| 655 |
+
"""Is this console interactive?"""
|
| 656 |
+
return sys.stdin is not None and sys.stdin.isatty()
|
| 657 |
+
|
| 658 |
+
|
| 659 |
+
def hash_file(path: str, blocksize: int = 1 << 20) -> Tuple[Any, int]:
|
| 660 |
+
"""Return (hash, length) for path using hashlib.sha256()"""
|
| 661 |
+
|
| 662 |
+
h = hashlib.sha256()
|
| 663 |
+
length = 0
|
| 664 |
+
with open(path, "rb") as f:
|
| 665 |
+
for block in read_chunks(f, size=blocksize):
|
| 666 |
+
length += len(block)
|
| 667 |
+
h.update(block)
|
| 668 |
+
return h, length
|
| 669 |
+
|
| 670 |
+
|
| 671 |
+
def pairwise(iterable: Iterable[Any]) -> Iterator[Tuple[Any, Any]]:
|
| 672 |
+
"""
|
| 673 |
+
Return paired elements.
|
| 674 |
+
|
| 675 |
+
For example:
|
| 676 |
+
s -> (s0, s1), (s2, s3), (s4, s5), ...
|
| 677 |
+
"""
|
| 678 |
+
iterable = iter(iterable)
|
| 679 |
+
return zip_longest(iterable, iterable)
|
| 680 |
+
|
| 681 |
+
|
| 682 |
+
def partition(
|
| 683 |
+
pred: Callable[[T], bool],
|
| 684 |
+
iterable: Iterable[T],
|
| 685 |
+
) -> Tuple[Iterable[T], Iterable[T]]:
|
| 686 |
+
"""
|
| 687 |
+
Use a predicate to partition entries into false entries and true entries,
|
| 688 |
+
like
|
| 689 |
+
|
| 690 |
+
partition(is_odd, range(10)) --> 0 2 4 6 8 and 1 3 5 7 9
|
| 691 |
+
"""
|
| 692 |
+
t1, t2 = tee(iterable)
|
| 693 |
+
return filterfalse(pred, t1), filter(pred, t2)
|
| 694 |
+
|
| 695 |
+
|
| 696 |
+
class ConfiguredBuildBackendHookCaller(BuildBackendHookCaller):
|
| 697 |
+
def __init__(
|
| 698 |
+
self,
|
| 699 |
+
config_holder: Any,
|
| 700 |
+
source_dir: str,
|
| 701 |
+
build_backend: str,
|
| 702 |
+
backend_path: Optional[str] = None,
|
| 703 |
+
runner: Optional[Callable[..., None]] = None,
|
| 704 |
+
python_executable: Optional[str] = None,
|
| 705 |
+
):
|
| 706 |
+
super().__init__(
|
| 707 |
+
source_dir, build_backend, backend_path, runner, python_executable
|
| 708 |
+
)
|
| 709 |
+
self.config_holder = config_holder
|
| 710 |
+
|
| 711 |
+
def build_wheel(
|
| 712 |
+
self,
|
| 713 |
+
wheel_directory: str,
|
| 714 |
+
config_settings: Optional[Dict[str, Union[str, List[str]]]] = None,
|
| 715 |
+
metadata_directory: Optional[str] = None,
|
| 716 |
+
) -> str:
|
| 717 |
+
cs = self.config_holder.config_settings
|
| 718 |
+
return super().build_wheel(
|
| 719 |
+
wheel_directory, config_settings=cs, metadata_directory=metadata_directory
|
| 720 |
+
)
|
| 721 |
+
|
| 722 |
+
def build_sdist(
|
| 723 |
+
self,
|
| 724 |
+
sdist_directory: str,
|
| 725 |
+
config_settings: Optional[Dict[str, Union[str, List[str]]]] = None,
|
| 726 |
+
) -> str:
|
| 727 |
+
cs = self.config_holder.config_settings
|
| 728 |
+
return super().build_sdist(sdist_directory, config_settings=cs)
|
| 729 |
+
|
| 730 |
+
def build_editable(
|
| 731 |
+
self,
|
| 732 |
+
wheel_directory: str,
|
| 733 |
+
config_settings: Optional[Dict[str, Union[str, List[str]]]] = None,
|
| 734 |
+
metadata_directory: Optional[str] = None,
|
| 735 |
+
) -> str:
|
| 736 |
+
cs = self.config_holder.config_settings
|
| 737 |
+
return super().build_editable(
|
| 738 |
+
wheel_directory, config_settings=cs, metadata_directory=metadata_directory
|
| 739 |
+
)
|
| 740 |
+
|
| 741 |
+
def get_requires_for_build_wheel(
|
| 742 |
+
self, config_settings: Optional[Dict[str, Union[str, List[str]]]] = None
|
| 743 |
+
) -> List[str]:
|
| 744 |
+
cs = self.config_holder.config_settings
|
| 745 |
+
return super().get_requires_for_build_wheel(config_settings=cs)
|
| 746 |
+
|
| 747 |
+
def get_requires_for_build_sdist(
|
| 748 |
+
self, config_settings: Optional[Dict[str, Union[str, List[str]]]] = None
|
| 749 |
+
) -> List[str]:
|
| 750 |
+
cs = self.config_holder.config_settings
|
| 751 |
+
return super().get_requires_for_build_sdist(config_settings=cs)
|
| 752 |
+
|
| 753 |
+
def get_requires_for_build_editable(
|
| 754 |
+
self, config_settings: Optional[Dict[str, Union[str, List[str]]]] = None
|
| 755 |
+
) -> List[str]:
|
| 756 |
+
cs = self.config_holder.config_settings
|
| 757 |
+
return super().get_requires_for_build_editable(config_settings=cs)
|
| 758 |
+
|
| 759 |
+
def prepare_metadata_for_build_wheel(
|
| 760 |
+
self,
|
| 761 |
+
metadata_directory: str,
|
| 762 |
+
config_settings: Optional[Dict[str, Union[str, List[str]]]] = None,
|
| 763 |
+
_allow_fallback: bool = True,
|
| 764 |
+
) -> str:
|
| 765 |
+
cs = self.config_holder.config_settings
|
| 766 |
+
return super().prepare_metadata_for_build_wheel(
|
| 767 |
+
metadata_directory=metadata_directory,
|
| 768 |
+
config_settings=cs,
|
| 769 |
+
_allow_fallback=_allow_fallback,
|
| 770 |
+
)
|
| 771 |
+
|
| 772 |
+
def prepare_metadata_for_build_editable(
|
| 773 |
+
self,
|
| 774 |
+
metadata_directory: str,
|
| 775 |
+
config_settings: Optional[Dict[str, Union[str, List[str]]]] = None,
|
| 776 |
+
_allow_fallback: bool = True,
|
| 777 |
+
) -> str:
|
| 778 |
+
cs = self.config_holder.config_settings
|
| 779 |
+
return super().prepare_metadata_for_build_editable(
|
| 780 |
+
metadata_directory=metadata_directory,
|
| 781 |
+
config_settings=cs,
|
| 782 |
+
_allow_fallback=_allow_fallback,
|
| 783 |
+
)
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/models.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Utilities for defining models
|
| 2 |
+
"""
|
| 3 |
+
|
| 4 |
+
import operator
|
| 5 |
+
from typing import Any, Callable, Type
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
class KeyBasedCompareMixin:
|
| 9 |
+
"""Provides comparison capabilities that is based on a key"""
|
| 10 |
+
|
| 11 |
+
__slots__ = ["_compare_key", "_defining_class"]
|
| 12 |
+
|
| 13 |
+
def __init__(self, key: Any, defining_class: Type["KeyBasedCompareMixin"]) -> None:
|
| 14 |
+
self._compare_key = key
|
| 15 |
+
self._defining_class = defining_class
|
| 16 |
+
|
| 17 |
+
def __hash__(self) -> int:
|
| 18 |
+
return hash(self._compare_key)
|
| 19 |
+
|
| 20 |
+
def __lt__(self, other: Any) -> bool:
|
| 21 |
+
return self._compare(other, operator.__lt__)
|
| 22 |
+
|
| 23 |
+
def __le__(self, other: Any) -> bool:
|
| 24 |
+
return self._compare(other, operator.__le__)
|
| 25 |
+
|
| 26 |
+
def __gt__(self, other: Any) -> bool:
|
| 27 |
+
return self._compare(other, operator.__gt__)
|
| 28 |
+
|
| 29 |
+
def __ge__(self, other: Any) -> bool:
|
| 30 |
+
return self._compare(other, operator.__ge__)
|
| 31 |
+
|
| 32 |
+
def __eq__(self, other: Any) -> bool:
|
| 33 |
+
return self._compare(other, operator.__eq__)
|
| 34 |
+
|
| 35 |
+
def _compare(self, other: Any, method: Callable[[Any, Any], bool]) -> bool:
|
| 36 |
+
if not isinstance(other, self._defining_class):
|
| 37 |
+
return NotImplemented
|
| 38 |
+
|
| 39 |
+
return method(self._compare_key, other._compare_key)
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/packaging.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import functools
|
| 2 |
+
import logging
|
| 3 |
+
import re
|
| 4 |
+
from typing import NewType, Optional, Tuple, cast
|
| 5 |
+
|
| 6 |
+
from pip._vendor.packaging import specifiers, version
|
| 7 |
+
from pip._vendor.packaging.requirements import Requirement
|
| 8 |
+
|
| 9 |
+
NormalizedExtra = NewType("NormalizedExtra", str)
|
| 10 |
+
|
| 11 |
+
logger = logging.getLogger(__name__)
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
def check_requires_python(
|
| 15 |
+
requires_python: Optional[str], version_info: Tuple[int, ...]
|
| 16 |
+
) -> bool:
|
| 17 |
+
"""
|
| 18 |
+
Check if the given Python version matches a "Requires-Python" specifier.
|
| 19 |
+
|
| 20 |
+
:param version_info: A 3-tuple of ints representing a Python
|
| 21 |
+
major-minor-micro version to check (e.g. `sys.version_info[:3]`).
|
| 22 |
+
|
| 23 |
+
:return: `True` if the given Python version satisfies the requirement.
|
| 24 |
+
Otherwise, return `False`.
|
| 25 |
+
|
| 26 |
+
:raises InvalidSpecifier: If `requires_python` has an invalid format.
|
| 27 |
+
"""
|
| 28 |
+
if requires_python is None:
|
| 29 |
+
# The package provides no information
|
| 30 |
+
return True
|
| 31 |
+
requires_python_specifier = specifiers.SpecifierSet(requires_python)
|
| 32 |
+
|
| 33 |
+
python_version = version.parse(".".join(map(str, version_info)))
|
| 34 |
+
return python_version in requires_python_specifier
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
@functools.lru_cache(maxsize=512)
|
| 38 |
+
def get_requirement(req_string: str) -> Requirement:
|
| 39 |
+
"""Construct a packaging.Requirement object with caching"""
|
| 40 |
+
# Parsing requirement strings is expensive, and is also expected to happen
|
| 41 |
+
# with a low diversity of different arguments (at least relative the number
|
| 42 |
+
# constructed). This method adds a cache to requirement object creation to
|
| 43 |
+
# minimize repeated parsing of the same string to construct equivalent
|
| 44 |
+
# Requirement objects.
|
| 45 |
+
return Requirement(req_string)
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
def safe_extra(extra: str) -> NormalizedExtra:
|
| 49 |
+
"""Convert an arbitrary string to a standard 'extra' name
|
| 50 |
+
|
| 51 |
+
Any runs of non-alphanumeric characters are replaced with a single '_',
|
| 52 |
+
and the result is always lowercased.
|
| 53 |
+
|
| 54 |
+
This function is duplicated from ``pkg_resources``. Note that this is not
|
| 55 |
+
the same to either ``canonicalize_name`` or ``_egg_link_name``.
|
| 56 |
+
"""
|
| 57 |
+
return cast(NormalizedExtra, re.sub("[^A-Za-z0-9.-]+", "_", extra).lower())
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/setuptools_build.py
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import sys
|
| 2 |
+
import textwrap
|
| 3 |
+
from typing import List, Optional, Sequence
|
| 4 |
+
|
| 5 |
+
# Shim to wrap setup.py invocation with setuptools
|
| 6 |
+
# Note that __file__ is handled via two {!r} *and* %r, to ensure that paths on
|
| 7 |
+
# Windows are correctly handled (it should be "C:\\Users" not "C:\Users").
|
| 8 |
+
_SETUPTOOLS_SHIM = textwrap.dedent(
|
| 9 |
+
"""
|
| 10 |
+
exec(compile('''
|
| 11 |
+
# This is <pip-setuptools-caller> -- a caller that pip uses to run setup.py
|
| 12 |
+
#
|
| 13 |
+
# - It imports setuptools before invoking setup.py, to enable projects that directly
|
| 14 |
+
# import from `distutils.core` to work with newer packaging standards.
|
| 15 |
+
# - It provides a clear error message when setuptools is not installed.
|
| 16 |
+
# - It sets `sys.argv[0]` to the underlying `setup.py`, when invoking `setup.py` so
|
| 17 |
+
# setuptools doesn't think the script is `-c`. This avoids the following warning:
|
| 18 |
+
# manifest_maker: standard file '-c' not found".
|
| 19 |
+
# - It generates a shim setup.py, for handling setup.cfg-only projects.
|
| 20 |
+
import os, sys, tokenize
|
| 21 |
+
|
| 22 |
+
try:
|
| 23 |
+
import setuptools
|
| 24 |
+
except ImportError as error:
|
| 25 |
+
print(
|
| 26 |
+
"ERROR: Can not execute `setup.py` since setuptools is not available in "
|
| 27 |
+
"the build environment.",
|
| 28 |
+
file=sys.stderr,
|
| 29 |
+
)
|
| 30 |
+
sys.exit(1)
|
| 31 |
+
|
| 32 |
+
__file__ = %r
|
| 33 |
+
sys.argv[0] = __file__
|
| 34 |
+
|
| 35 |
+
if os.path.exists(__file__):
|
| 36 |
+
filename = __file__
|
| 37 |
+
with tokenize.open(__file__) as f:
|
| 38 |
+
setup_py_code = f.read()
|
| 39 |
+
else:
|
| 40 |
+
filename = "<auto-generated setuptools caller>"
|
| 41 |
+
setup_py_code = "from setuptools import setup; setup()"
|
| 42 |
+
|
| 43 |
+
exec(compile(setup_py_code, filename, "exec"))
|
| 44 |
+
''' % ({!r},), "<pip-setuptools-caller>", "exec"))
|
| 45 |
+
"""
|
| 46 |
+
).rstrip()
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
def make_setuptools_shim_args(
|
| 50 |
+
setup_py_path: str,
|
| 51 |
+
global_options: Optional[Sequence[str]] = None,
|
| 52 |
+
no_user_config: bool = False,
|
| 53 |
+
unbuffered_output: bool = False,
|
| 54 |
+
) -> List[str]:
|
| 55 |
+
"""
|
| 56 |
+
Get setuptools command arguments with shim wrapped setup file invocation.
|
| 57 |
+
|
| 58 |
+
:param setup_py_path: The path to setup.py to be wrapped.
|
| 59 |
+
:param global_options: Additional global options.
|
| 60 |
+
:param no_user_config: If True, disables personal user configuration.
|
| 61 |
+
:param unbuffered_output: If True, adds the unbuffered switch to the
|
| 62 |
+
argument list.
|
| 63 |
+
"""
|
| 64 |
+
args = [sys.executable]
|
| 65 |
+
if unbuffered_output:
|
| 66 |
+
args += ["-u"]
|
| 67 |
+
args += ["-c", _SETUPTOOLS_SHIM.format(setup_py_path)]
|
| 68 |
+
if global_options:
|
| 69 |
+
args += global_options
|
| 70 |
+
if no_user_config:
|
| 71 |
+
args += ["--no-user-cfg"]
|
| 72 |
+
return args
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
def make_setuptools_bdist_wheel_args(
|
| 76 |
+
setup_py_path: str,
|
| 77 |
+
global_options: Sequence[str],
|
| 78 |
+
build_options: Sequence[str],
|
| 79 |
+
destination_dir: str,
|
| 80 |
+
) -> List[str]:
|
| 81 |
+
# NOTE: Eventually, we'd want to also -S to the flags here, when we're
|
| 82 |
+
# isolating. Currently, it breaks Python in virtualenvs, because it
|
| 83 |
+
# relies on site.py to find parts of the standard library outside the
|
| 84 |
+
# virtualenv.
|
| 85 |
+
args = make_setuptools_shim_args(
|
| 86 |
+
setup_py_path, global_options=global_options, unbuffered_output=True
|
| 87 |
+
)
|
| 88 |
+
args += ["bdist_wheel", "-d", destination_dir]
|
| 89 |
+
args += build_options
|
| 90 |
+
return args
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
def make_setuptools_clean_args(
|
| 94 |
+
setup_py_path: str,
|
| 95 |
+
global_options: Sequence[str],
|
| 96 |
+
) -> List[str]:
|
| 97 |
+
args = make_setuptools_shim_args(
|
| 98 |
+
setup_py_path, global_options=global_options, unbuffered_output=True
|
| 99 |
+
)
|
| 100 |
+
args += ["clean", "--all"]
|
| 101 |
+
return args
|
| 102 |
+
|
| 103 |
+
|
| 104 |
+
def make_setuptools_develop_args(
|
| 105 |
+
setup_py_path: str,
|
| 106 |
+
*,
|
| 107 |
+
global_options: Sequence[str],
|
| 108 |
+
no_user_config: bool,
|
| 109 |
+
prefix: Optional[str],
|
| 110 |
+
home: Optional[str],
|
| 111 |
+
use_user_site: bool,
|
| 112 |
+
) -> List[str]:
|
| 113 |
+
assert not (use_user_site and prefix)
|
| 114 |
+
|
| 115 |
+
args = make_setuptools_shim_args(
|
| 116 |
+
setup_py_path,
|
| 117 |
+
global_options=global_options,
|
| 118 |
+
no_user_config=no_user_config,
|
| 119 |
+
)
|
| 120 |
+
|
| 121 |
+
args += ["develop", "--no-deps"]
|
| 122 |
+
|
| 123 |
+
if prefix:
|
| 124 |
+
args += ["--prefix", prefix]
|
| 125 |
+
if home is not None:
|
| 126 |
+
args += ["--install-dir", home]
|
| 127 |
+
|
| 128 |
+
if use_user_site:
|
| 129 |
+
args += ["--user", "--prefix="]
|
| 130 |
+
|
| 131 |
+
return args
|
| 132 |
+
|
| 133 |
+
|
| 134 |
+
def make_setuptools_egg_info_args(
|
| 135 |
+
setup_py_path: str,
|
| 136 |
+
egg_info_dir: Optional[str],
|
| 137 |
+
no_user_config: bool,
|
| 138 |
+
) -> List[str]:
|
| 139 |
+
args = make_setuptools_shim_args(setup_py_path, no_user_config=no_user_config)
|
| 140 |
+
|
| 141 |
+
args += ["egg_info"]
|
| 142 |
+
|
| 143 |
+
if egg_info_dir:
|
| 144 |
+
args += ["--egg-base", egg_info_dir]
|
| 145 |
+
|
| 146 |
+
return args
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/subprocess.py
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import logging
|
| 2 |
+
import os
|
| 3 |
+
import shlex
|
| 4 |
+
import subprocess
|
| 5 |
+
from typing import (
|
| 6 |
+
TYPE_CHECKING,
|
| 7 |
+
Any,
|
| 8 |
+
Callable,
|
| 9 |
+
Iterable,
|
| 10 |
+
List,
|
| 11 |
+
Mapping,
|
| 12 |
+
Optional,
|
| 13 |
+
Union,
|
| 14 |
+
)
|
| 15 |
+
|
| 16 |
+
from pip._vendor.rich.markup import escape
|
| 17 |
+
|
| 18 |
+
from pip._internal.cli.spinners import SpinnerInterface, open_spinner
|
| 19 |
+
from pip._internal.exceptions import InstallationSubprocessError
|
| 20 |
+
from pip._internal.utils.logging import VERBOSE, subprocess_logger
|
| 21 |
+
from pip._internal.utils.misc import HiddenText
|
| 22 |
+
|
| 23 |
+
if TYPE_CHECKING:
|
| 24 |
+
# Literal was introduced in Python 3.8.
|
| 25 |
+
#
|
| 26 |
+
# TODO: Remove `if TYPE_CHECKING` when dropping support for Python 3.7.
|
| 27 |
+
from typing import Literal
|
| 28 |
+
|
| 29 |
+
CommandArgs = List[Union[str, HiddenText]]
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def make_command(*args: Union[str, HiddenText, CommandArgs]) -> CommandArgs:
|
| 33 |
+
"""
|
| 34 |
+
Create a CommandArgs object.
|
| 35 |
+
"""
|
| 36 |
+
command_args: CommandArgs = []
|
| 37 |
+
for arg in args:
|
| 38 |
+
# Check for list instead of CommandArgs since CommandArgs is
|
| 39 |
+
# only known during type-checking.
|
| 40 |
+
if isinstance(arg, list):
|
| 41 |
+
command_args.extend(arg)
|
| 42 |
+
else:
|
| 43 |
+
# Otherwise, arg is str or HiddenText.
|
| 44 |
+
command_args.append(arg)
|
| 45 |
+
|
| 46 |
+
return command_args
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
def format_command_args(args: Union[List[str], CommandArgs]) -> str:
|
| 50 |
+
"""
|
| 51 |
+
Format command arguments for display.
|
| 52 |
+
"""
|
| 53 |
+
# For HiddenText arguments, display the redacted form by calling str().
|
| 54 |
+
# Also, we don't apply str() to arguments that aren't HiddenText since
|
| 55 |
+
# this can trigger a UnicodeDecodeError in Python 2 if the argument
|
| 56 |
+
# has type unicode and includes a non-ascii character. (The type
|
| 57 |
+
# checker doesn't ensure the annotations are correct in all cases.)
|
| 58 |
+
return " ".join(
|
| 59 |
+
shlex.quote(str(arg)) if isinstance(arg, HiddenText) else shlex.quote(arg)
|
| 60 |
+
for arg in args
|
| 61 |
+
)
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
def reveal_command_args(args: Union[List[str], CommandArgs]) -> List[str]:
|
| 65 |
+
"""
|
| 66 |
+
Return the arguments in their raw, unredacted form.
|
| 67 |
+
"""
|
| 68 |
+
return [arg.secret if isinstance(arg, HiddenText) else arg for arg in args]
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
def call_subprocess(
|
| 72 |
+
cmd: Union[List[str], CommandArgs],
|
| 73 |
+
show_stdout: bool = False,
|
| 74 |
+
cwd: Optional[str] = None,
|
| 75 |
+
on_returncode: 'Literal["raise", "warn", "ignore"]' = "raise",
|
| 76 |
+
extra_ok_returncodes: Optional[Iterable[int]] = None,
|
| 77 |
+
extra_environ: Optional[Mapping[str, Any]] = None,
|
| 78 |
+
unset_environ: Optional[Iterable[str]] = None,
|
| 79 |
+
spinner: Optional[SpinnerInterface] = None,
|
| 80 |
+
log_failed_cmd: Optional[bool] = True,
|
| 81 |
+
stdout_only: Optional[bool] = False,
|
| 82 |
+
*,
|
| 83 |
+
command_desc: str,
|
| 84 |
+
) -> str:
|
| 85 |
+
"""
|
| 86 |
+
Args:
|
| 87 |
+
show_stdout: if true, use INFO to log the subprocess's stderr and
|
| 88 |
+
stdout streams. Otherwise, use DEBUG. Defaults to False.
|
| 89 |
+
extra_ok_returncodes: an iterable of integer return codes that are
|
| 90 |
+
acceptable, in addition to 0. Defaults to None, which means [].
|
| 91 |
+
unset_environ: an iterable of environment variable names to unset
|
| 92 |
+
prior to calling subprocess.Popen().
|
| 93 |
+
log_failed_cmd: if false, failed commands are not logged, only raised.
|
| 94 |
+
stdout_only: if true, return only stdout, else return both. When true,
|
| 95 |
+
logging of both stdout and stderr occurs when the subprocess has
|
| 96 |
+
terminated, else logging occurs as subprocess output is produced.
|
| 97 |
+
"""
|
| 98 |
+
if extra_ok_returncodes is None:
|
| 99 |
+
extra_ok_returncodes = []
|
| 100 |
+
if unset_environ is None:
|
| 101 |
+
unset_environ = []
|
| 102 |
+
# Most places in pip use show_stdout=False. What this means is--
|
| 103 |
+
#
|
| 104 |
+
# - We connect the child's output (combined stderr and stdout) to a
|
| 105 |
+
# single pipe, which we read.
|
| 106 |
+
# - We log this output to stderr at DEBUG level as it is received.
|
| 107 |
+
# - If DEBUG logging isn't enabled (e.g. if --verbose logging wasn't
|
| 108 |
+
# requested), then we show a spinner so the user can still see the
|
| 109 |
+
# subprocess is in progress.
|
| 110 |
+
# - If the subprocess exits with an error, we log the output to stderr
|
| 111 |
+
# at ERROR level if it hasn't already been displayed to the console
|
| 112 |
+
# (e.g. if --verbose logging wasn't enabled). This way we don't log
|
| 113 |
+
# the output to the console twice.
|
| 114 |
+
#
|
| 115 |
+
# If show_stdout=True, then the above is still done, but with DEBUG
|
| 116 |
+
# replaced by INFO.
|
| 117 |
+
if show_stdout:
|
| 118 |
+
# Then log the subprocess output at INFO level.
|
| 119 |
+
log_subprocess: Callable[..., None] = subprocess_logger.info
|
| 120 |
+
used_level = logging.INFO
|
| 121 |
+
else:
|
| 122 |
+
# Then log the subprocess output using VERBOSE. This also ensures
|
| 123 |
+
# it will be logged to the log file (aka user_log), if enabled.
|
| 124 |
+
log_subprocess = subprocess_logger.verbose
|
| 125 |
+
used_level = VERBOSE
|
| 126 |
+
|
| 127 |
+
# Whether the subprocess will be visible in the console.
|
| 128 |
+
showing_subprocess = subprocess_logger.getEffectiveLevel() <= used_level
|
| 129 |
+
|
| 130 |
+
# Only use the spinner if we're not showing the subprocess output
|
| 131 |
+
# and we have a spinner.
|
| 132 |
+
use_spinner = not showing_subprocess and spinner is not None
|
| 133 |
+
|
| 134 |
+
log_subprocess("Running command %s", command_desc)
|
| 135 |
+
env = os.environ.copy()
|
| 136 |
+
if extra_environ:
|
| 137 |
+
env.update(extra_environ)
|
| 138 |
+
for name in unset_environ:
|
| 139 |
+
env.pop(name, None)
|
| 140 |
+
try:
|
| 141 |
+
proc = subprocess.Popen(
|
| 142 |
+
# Convert HiddenText objects to the underlying str.
|
| 143 |
+
reveal_command_args(cmd),
|
| 144 |
+
stdin=subprocess.PIPE,
|
| 145 |
+
stdout=subprocess.PIPE,
|
| 146 |
+
stderr=subprocess.STDOUT if not stdout_only else subprocess.PIPE,
|
| 147 |
+
cwd=cwd,
|
| 148 |
+
env=env,
|
| 149 |
+
errors="backslashreplace",
|
| 150 |
+
)
|
| 151 |
+
except Exception as exc:
|
| 152 |
+
if log_failed_cmd:
|
| 153 |
+
subprocess_logger.critical(
|
| 154 |
+
"Error %s while executing command %s",
|
| 155 |
+
exc,
|
| 156 |
+
command_desc,
|
| 157 |
+
)
|
| 158 |
+
raise
|
| 159 |
+
all_output = []
|
| 160 |
+
if not stdout_only:
|
| 161 |
+
assert proc.stdout
|
| 162 |
+
assert proc.stdin
|
| 163 |
+
proc.stdin.close()
|
| 164 |
+
# In this mode, stdout and stderr are in the same pipe.
|
| 165 |
+
while True:
|
| 166 |
+
line: str = proc.stdout.readline()
|
| 167 |
+
if not line:
|
| 168 |
+
break
|
| 169 |
+
line = line.rstrip()
|
| 170 |
+
all_output.append(line + "\n")
|
| 171 |
+
|
| 172 |
+
# Show the line immediately.
|
| 173 |
+
log_subprocess(line)
|
| 174 |
+
# Update the spinner.
|
| 175 |
+
if use_spinner:
|
| 176 |
+
assert spinner
|
| 177 |
+
spinner.spin()
|
| 178 |
+
try:
|
| 179 |
+
proc.wait()
|
| 180 |
+
finally:
|
| 181 |
+
if proc.stdout:
|
| 182 |
+
proc.stdout.close()
|
| 183 |
+
output = "".join(all_output)
|
| 184 |
+
else:
|
| 185 |
+
# In this mode, stdout and stderr are in different pipes.
|
| 186 |
+
# We must use communicate() which is the only safe way to read both.
|
| 187 |
+
out, err = proc.communicate()
|
| 188 |
+
# log line by line to preserve pip log indenting
|
| 189 |
+
for out_line in out.splitlines():
|
| 190 |
+
log_subprocess(out_line)
|
| 191 |
+
all_output.append(out)
|
| 192 |
+
for err_line in err.splitlines():
|
| 193 |
+
log_subprocess(err_line)
|
| 194 |
+
all_output.append(err)
|
| 195 |
+
output = out
|
| 196 |
+
|
| 197 |
+
proc_had_error = proc.returncode and proc.returncode not in extra_ok_returncodes
|
| 198 |
+
if use_spinner:
|
| 199 |
+
assert spinner
|
| 200 |
+
if proc_had_error:
|
| 201 |
+
spinner.finish("error")
|
| 202 |
+
else:
|
| 203 |
+
spinner.finish("done")
|
| 204 |
+
if proc_had_error:
|
| 205 |
+
if on_returncode == "raise":
|
| 206 |
+
error = InstallationSubprocessError(
|
| 207 |
+
command_description=command_desc,
|
| 208 |
+
exit_code=proc.returncode,
|
| 209 |
+
output_lines=all_output if not showing_subprocess else None,
|
| 210 |
+
)
|
| 211 |
+
if log_failed_cmd:
|
| 212 |
+
subprocess_logger.error("%s", error, extra={"rich": True})
|
| 213 |
+
subprocess_logger.verbose(
|
| 214 |
+
"[bold magenta]full command[/]: [blue]%s[/]",
|
| 215 |
+
escape(format_command_args(cmd)),
|
| 216 |
+
extra={"markup": True},
|
| 217 |
+
)
|
| 218 |
+
subprocess_logger.verbose(
|
| 219 |
+
"[bold magenta]cwd[/]: %s",
|
| 220 |
+
escape(cwd or "[inherit]"),
|
| 221 |
+
extra={"markup": True},
|
| 222 |
+
)
|
| 223 |
+
|
| 224 |
+
raise error
|
| 225 |
+
elif on_returncode == "warn":
|
| 226 |
+
subprocess_logger.warning(
|
| 227 |
+
'Command "%s" had error code %s in %s',
|
| 228 |
+
command_desc,
|
| 229 |
+
proc.returncode,
|
| 230 |
+
cwd,
|
| 231 |
+
)
|
| 232 |
+
elif on_returncode == "ignore":
|
| 233 |
+
pass
|
| 234 |
+
else:
|
| 235 |
+
raise ValueError(f"Invalid value: on_returncode={on_returncode!r}")
|
| 236 |
+
return output
|
| 237 |
+
|
| 238 |
+
|
| 239 |
+
def runner_with_spinner_message(message: str) -> Callable[..., None]:
|
| 240 |
+
"""Provide a subprocess_runner that shows a spinner message.
|
| 241 |
+
|
| 242 |
+
Intended for use with for BuildBackendHookCaller. Thus, the runner has
|
| 243 |
+
an API that matches what's expected by BuildBackendHookCaller.subprocess_runner.
|
| 244 |
+
"""
|
| 245 |
+
|
| 246 |
+
def runner(
|
| 247 |
+
cmd: List[str],
|
| 248 |
+
cwd: Optional[str] = None,
|
| 249 |
+
extra_environ: Optional[Mapping[str, Any]] = None,
|
| 250 |
+
) -> None:
|
| 251 |
+
with open_spinner(message) as spinner:
|
| 252 |
+
call_subprocess(
|
| 253 |
+
cmd,
|
| 254 |
+
command_desc=message,
|
| 255 |
+
cwd=cwd,
|
| 256 |
+
extra_environ=extra_environ,
|
| 257 |
+
spinner=spinner,
|
| 258 |
+
)
|
| 259 |
+
|
| 260 |
+
return runner
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/temp_dir.py
ADDED
|
@@ -0,0 +1,296 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import errno
|
| 2 |
+
import itertools
|
| 3 |
+
import logging
|
| 4 |
+
import os.path
|
| 5 |
+
import tempfile
|
| 6 |
+
import traceback
|
| 7 |
+
from contextlib import ExitStack, contextmanager
|
| 8 |
+
from pathlib import Path
|
| 9 |
+
from typing import (
|
| 10 |
+
Any,
|
| 11 |
+
Callable,
|
| 12 |
+
Dict,
|
| 13 |
+
Generator,
|
| 14 |
+
List,
|
| 15 |
+
Optional,
|
| 16 |
+
TypeVar,
|
| 17 |
+
Union,
|
| 18 |
+
)
|
| 19 |
+
|
| 20 |
+
from pip._internal.utils.misc import enum, rmtree
|
| 21 |
+
|
| 22 |
+
logger = logging.getLogger(__name__)
|
| 23 |
+
|
| 24 |
+
_T = TypeVar("_T", bound="TempDirectory")
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
# Kinds of temporary directories. Only needed for ones that are
|
| 28 |
+
# globally-managed.
|
| 29 |
+
tempdir_kinds = enum(
|
| 30 |
+
BUILD_ENV="build-env",
|
| 31 |
+
EPHEM_WHEEL_CACHE="ephem-wheel-cache",
|
| 32 |
+
REQ_BUILD="req-build",
|
| 33 |
+
)
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
_tempdir_manager: Optional[ExitStack] = None
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
@contextmanager
|
| 40 |
+
def global_tempdir_manager() -> Generator[None, None, None]:
|
| 41 |
+
global _tempdir_manager
|
| 42 |
+
with ExitStack() as stack:
|
| 43 |
+
old_tempdir_manager, _tempdir_manager = _tempdir_manager, stack
|
| 44 |
+
try:
|
| 45 |
+
yield
|
| 46 |
+
finally:
|
| 47 |
+
_tempdir_manager = old_tempdir_manager
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
class TempDirectoryTypeRegistry:
|
| 51 |
+
"""Manages temp directory behavior"""
|
| 52 |
+
|
| 53 |
+
def __init__(self) -> None:
|
| 54 |
+
self._should_delete: Dict[str, bool] = {}
|
| 55 |
+
|
| 56 |
+
def set_delete(self, kind: str, value: bool) -> None:
|
| 57 |
+
"""Indicate whether a TempDirectory of the given kind should be
|
| 58 |
+
auto-deleted.
|
| 59 |
+
"""
|
| 60 |
+
self._should_delete[kind] = value
|
| 61 |
+
|
| 62 |
+
def get_delete(self, kind: str) -> bool:
|
| 63 |
+
"""Get configured auto-delete flag for a given TempDirectory type,
|
| 64 |
+
default True.
|
| 65 |
+
"""
|
| 66 |
+
return self._should_delete.get(kind, True)
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
_tempdir_registry: Optional[TempDirectoryTypeRegistry] = None
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
@contextmanager
|
| 73 |
+
def tempdir_registry() -> Generator[TempDirectoryTypeRegistry, None, None]:
|
| 74 |
+
"""Provides a scoped global tempdir registry that can be used to dictate
|
| 75 |
+
whether directories should be deleted.
|
| 76 |
+
"""
|
| 77 |
+
global _tempdir_registry
|
| 78 |
+
old_tempdir_registry = _tempdir_registry
|
| 79 |
+
_tempdir_registry = TempDirectoryTypeRegistry()
|
| 80 |
+
try:
|
| 81 |
+
yield _tempdir_registry
|
| 82 |
+
finally:
|
| 83 |
+
_tempdir_registry = old_tempdir_registry
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
class _Default:
|
| 87 |
+
pass
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
_default = _Default()
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
class TempDirectory:
|
| 94 |
+
"""Helper class that owns and cleans up a temporary directory.
|
| 95 |
+
|
| 96 |
+
This class can be used as a context manager or as an OO representation of a
|
| 97 |
+
temporary directory.
|
| 98 |
+
|
| 99 |
+
Attributes:
|
| 100 |
+
path
|
| 101 |
+
Location to the created temporary directory
|
| 102 |
+
delete
|
| 103 |
+
Whether the directory should be deleted when exiting
|
| 104 |
+
(when used as a contextmanager)
|
| 105 |
+
|
| 106 |
+
Methods:
|
| 107 |
+
cleanup()
|
| 108 |
+
Deletes the temporary directory
|
| 109 |
+
|
| 110 |
+
When used as a context manager, if the delete attribute is True, on
|
| 111 |
+
exiting the context the temporary directory is deleted.
|
| 112 |
+
"""
|
| 113 |
+
|
| 114 |
+
def __init__(
|
| 115 |
+
self,
|
| 116 |
+
path: Optional[str] = None,
|
| 117 |
+
delete: Union[bool, None, _Default] = _default,
|
| 118 |
+
kind: str = "temp",
|
| 119 |
+
globally_managed: bool = False,
|
| 120 |
+
ignore_cleanup_errors: bool = True,
|
| 121 |
+
):
|
| 122 |
+
super().__init__()
|
| 123 |
+
|
| 124 |
+
if delete is _default:
|
| 125 |
+
if path is not None:
|
| 126 |
+
# If we were given an explicit directory, resolve delete option
|
| 127 |
+
# now.
|
| 128 |
+
delete = False
|
| 129 |
+
else:
|
| 130 |
+
# Otherwise, we wait until cleanup and see what
|
| 131 |
+
# tempdir_registry says.
|
| 132 |
+
delete = None
|
| 133 |
+
|
| 134 |
+
# The only time we specify path is in for editables where it
|
| 135 |
+
# is the value of the --src option.
|
| 136 |
+
if path is None:
|
| 137 |
+
path = self._create(kind)
|
| 138 |
+
|
| 139 |
+
self._path = path
|
| 140 |
+
self._deleted = False
|
| 141 |
+
self.delete = delete
|
| 142 |
+
self.kind = kind
|
| 143 |
+
self.ignore_cleanup_errors = ignore_cleanup_errors
|
| 144 |
+
|
| 145 |
+
if globally_managed:
|
| 146 |
+
assert _tempdir_manager is not None
|
| 147 |
+
_tempdir_manager.enter_context(self)
|
| 148 |
+
|
| 149 |
+
@property
|
| 150 |
+
def path(self) -> str:
|
| 151 |
+
assert not self._deleted, f"Attempted to access deleted path: {self._path}"
|
| 152 |
+
return self._path
|
| 153 |
+
|
| 154 |
+
def __repr__(self) -> str:
|
| 155 |
+
return f"<{self.__class__.__name__} {self.path!r}>"
|
| 156 |
+
|
| 157 |
+
def __enter__(self: _T) -> _T:
|
| 158 |
+
return self
|
| 159 |
+
|
| 160 |
+
def __exit__(self, exc: Any, value: Any, tb: Any) -> None:
|
| 161 |
+
if self.delete is not None:
|
| 162 |
+
delete = self.delete
|
| 163 |
+
elif _tempdir_registry:
|
| 164 |
+
delete = _tempdir_registry.get_delete(self.kind)
|
| 165 |
+
else:
|
| 166 |
+
delete = True
|
| 167 |
+
|
| 168 |
+
if delete:
|
| 169 |
+
self.cleanup()
|
| 170 |
+
|
| 171 |
+
def _create(self, kind: str) -> str:
|
| 172 |
+
"""Create a temporary directory and store its path in self.path"""
|
| 173 |
+
# We realpath here because some systems have their default tmpdir
|
| 174 |
+
# symlinked to another directory. This tends to confuse build
|
| 175 |
+
# scripts, so we canonicalize the path by traversing potential
|
| 176 |
+
# symlinks here.
|
| 177 |
+
path = os.path.realpath(tempfile.mkdtemp(prefix=f"pip-{kind}-"))
|
| 178 |
+
logger.debug("Created temporary directory: %s", path)
|
| 179 |
+
return path
|
| 180 |
+
|
| 181 |
+
def cleanup(self) -> None:
|
| 182 |
+
"""Remove the temporary directory created and reset state"""
|
| 183 |
+
self._deleted = True
|
| 184 |
+
if not os.path.exists(self._path):
|
| 185 |
+
return
|
| 186 |
+
|
| 187 |
+
errors: List[BaseException] = []
|
| 188 |
+
|
| 189 |
+
def onerror(
|
| 190 |
+
func: Callable[..., Any],
|
| 191 |
+
path: Path,
|
| 192 |
+
exc_val: BaseException,
|
| 193 |
+
) -> None:
|
| 194 |
+
"""Log a warning for a `rmtree` error and continue"""
|
| 195 |
+
formatted_exc = "\n".join(
|
| 196 |
+
traceback.format_exception_only(type(exc_val), exc_val)
|
| 197 |
+
)
|
| 198 |
+
formatted_exc = formatted_exc.rstrip() # remove trailing new line
|
| 199 |
+
if func in (os.unlink, os.remove, os.rmdir):
|
| 200 |
+
logger.debug(
|
| 201 |
+
"Failed to remove a temporary file '%s' due to %s.\n",
|
| 202 |
+
path,
|
| 203 |
+
formatted_exc,
|
| 204 |
+
)
|
| 205 |
+
else:
|
| 206 |
+
logger.debug("%s failed with %s.", func.__qualname__, formatted_exc)
|
| 207 |
+
errors.append(exc_val)
|
| 208 |
+
|
| 209 |
+
if self.ignore_cleanup_errors:
|
| 210 |
+
try:
|
| 211 |
+
# first try with tenacity; retrying to handle ephemeral errors
|
| 212 |
+
rmtree(self._path, ignore_errors=False)
|
| 213 |
+
except OSError:
|
| 214 |
+
# last pass ignore/log all errors
|
| 215 |
+
rmtree(self._path, onexc=onerror)
|
| 216 |
+
if errors:
|
| 217 |
+
logger.warning(
|
| 218 |
+
"Failed to remove contents in a temporary directory '%s'.\n"
|
| 219 |
+
"You can safely remove it manually.",
|
| 220 |
+
self._path,
|
| 221 |
+
)
|
| 222 |
+
else:
|
| 223 |
+
rmtree(self._path)
|
| 224 |
+
|
| 225 |
+
|
| 226 |
+
class AdjacentTempDirectory(TempDirectory):
|
| 227 |
+
"""Helper class that creates a temporary directory adjacent to a real one.
|
| 228 |
+
|
| 229 |
+
Attributes:
|
| 230 |
+
original
|
| 231 |
+
The original directory to create a temp directory for.
|
| 232 |
+
path
|
| 233 |
+
After calling create() or entering, contains the full
|
| 234 |
+
path to the temporary directory.
|
| 235 |
+
delete
|
| 236 |
+
Whether the directory should be deleted when exiting
|
| 237 |
+
(when used as a contextmanager)
|
| 238 |
+
|
| 239 |
+
"""
|
| 240 |
+
|
| 241 |
+
# The characters that may be used to name the temp directory
|
| 242 |
+
# We always prepend a ~ and then rotate through these until
|
| 243 |
+
# a usable name is found.
|
| 244 |
+
# pkg_resources raises a different error for .dist-info folder
|
| 245 |
+
# with leading '-' and invalid metadata
|
| 246 |
+
LEADING_CHARS = "-~.=%0123456789"
|
| 247 |
+
|
| 248 |
+
def __init__(self, original: str, delete: Optional[bool] = None) -> None:
|
| 249 |
+
self.original = original.rstrip("/\\")
|
| 250 |
+
super().__init__(delete=delete)
|
| 251 |
+
|
| 252 |
+
@classmethod
|
| 253 |
+
def _generate_names(cls, name: str) -> Generator[str, None, None]:
|
| 254 |
+
"""Generates a series of temporary names.
|
| 255 |
+
|
| 256 |
+
The algorithm replaces the leading characters in the name
|
| 257 |
+
with ones that are valid filesystem characters, but are not
|
| 258 |
+
valid package names (for both Python and pip definitions of
|
| 259 |
+
package).
|
| 260 |
+
"""
|
| 261 |
+
for i in range(1, len(name)):
|
| 262 |
+
for candidate in itertools.combinations_with_replacement(
|
| 263 |
+
cls.LEADING_CHARS, i - 1
|
| 264 |
+
):
|
| 265 |
+
new_name = "~" + "".join(candidate) + name[i:]
|
| 266 |
+
if new_name != name:
|
| 267 |
+
yield new_name
|
| 268 |
+
|
| 269 |
+
# If we make it this far, we will have to make a longer name
|
| 270 |
+
for i in range(len(cls.LEADING_CHARS)):
|
| 271 |
+
for candidate in itertools.combinations_with_replacement(
|
| 272 |
+
cls.LEADING_CHARS, i
|
| 273 |
+
):
|
| 274 |
+
new_name = "~" + "".join(candidate) + name
|
| 275 |
+
if new_name != name:
|
| 276 |
+
yield new_name
|
| 277 |
+
|
| 278 |
+
def _create(self, kind: str) -> str:
|
| 279 |
+
root, name = os.path.split(self.original)
|
| 280 |
+
for candidate in self._generate_names(name):
|
| 281 |
+
path = os.path.join(root, candidate)
|
| 282 |
+
try:
|
| 283 |
+
os.mkdir(path)
|
| 284 |
+
except OSError as ex:
|
| 285 |
+
# Continue if the name exists already
|
| 286 |
+
if ex.errno != errno.EEXIST:
|
| 287 |
+
raise
|
| 288 |
+
else:
|
| 289 |
+
path = os.path.realpath(path)
|
| 290 |
+
break
|
| 291 |
+
else:
|
| 292 |
+
# Final fallback on the default behavior.
|
| 293 |
+
path = os.path.realpath(tempfile.mkdtemp(prefix=f"pip-{kind}-"))
|
| 294 |
+
|
| 295 |
+
logger.debug("Created temporary directory: %s", path)
|
| 296 |
+
return path
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/urls.py
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import string
|
| 3 |
+
import urllib.parse
|
| 4 |
+
import urllib.request
|
| 5 |
+
from typing import Optional
|
| 6 |
+
|
| 7 |
+
from .compat import WINDOWS
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def get_url_scheme(url: str) -> Optional[str]:
|
| 11 |
+
if ":" not in url:
|
| 12 |
+
return None
|
| 13 |
+
return url.split(":", 1)[0].lower()
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def path_to_url(path: str) -> str:
|
| 17 |
+
"""
|
| 18 |
+
Convert a path to a file: URL. The path will be made absolute and have
|
| 19 |
+
quoted path parts.
|
| 20 |
+
"""
|
| 21 |
+
path = os.path.normpath(os.path.abspath(path))
|
| 22 |
+
url = urllib.parse.urljoin("file:", urllib.request.pathname2url(path))
|
| 23 |
+
return url
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def url_to_path(url: str) -> str:
|
| 27 |
+
"""
|
| 28 |
+
Convert a file: URL to a path.
|
| 29 |
+
"""
|
| 30 |
+
assert url.startswith(
|
| 31 |
+
"file:"
|
| 32 |
+
), f"You can only turn file: urls into filenames (not {url!r})"
|
| 33 |
+
|
| 34 |
+
_, netloc, path, _, _ = urllib.parse.urlsplit(url)
|
| 35 |
+
|
| 36 |
+
if not netloc or netloc == "localhost":
|
| 37 |
+
# According to RFC 8089, same as empty authority.
|
| 38 |
+
netloc = ""
|
| 39 |
+
elif WINDOWS:
|
| 40 |
+
# If we have a UNC path, prepend UNC share notation.
|
| 41 |
+
netloc = "\\\\" + netloc
|
| 42 |
+
else:
|
| 43 |
+
raise ValueError(
|
| 44 |
+
f"non-local file URIs are not supported on this platform: {url!r}"
|
| 45 |
+
)
|
| 46 |
+
|
| 47 |
+
path = urllib.request.url2pathname(netloc + path)
|
| 48 |
+
|
| 49 |
+
# On Windows, urlsplit parses the path as something like "/C:/Users/foo".
|
| 50 |
+
# This creates issues for path-related functions like io.open(), so we try
|
| 51 |
+
# to detect and strip the leading slash.
|
| 52 |
+
if (
|
| 53 |
+
WINDOWS
|
| 54 |
+
and not netloc # Not UNC.
|
| 55 |
+
and len(path) >= 3
|
| 56 |
+
and path[0] == "/" # Leading slash to strip.
|
| 57 |
+
and path[1] in string.ascii_letters # Drive letter.
|
| 58 |
+
and path[2:4] in (":", ":/") # Colon + end of string, or colon + absolute path.
|
| 59 |
+
):
|
| 60 |
+
path = path[1:]
|
| 61 |
+
|
| 62 |
+
return path
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_internal/utils/wheel.py
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Support functions for working with wheel files.
|
| 2 |
+
"""
|
| 3 |
+
|
| 4 |
+
import logging
|
| 5 |
+
from email.message import Message
|
| 6 |
+
from email.parser import Parser
|
| 7 |
+
from typing import Tuple
|
| 8 |
+
from zipfile import BadZipFile, ZipFile
|
| 9 |
+
|
| 10 |
+
from pip._vendor.packaging.utils import canonicalize_name
|
| 11 |
+
|
| 12 |
+
from pip._internal.exceptions import UnsupportedWheel
|
| 13 |
+
|
| 14 |
+
VERSION_COMPATIBLE = (1, 0)
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
logger = logging.getLogger(__name__)
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def parse_wheel(wheel_zip: ZipFile, name: str) -> Tuple[str, Message]:
|
| 21 |
+
"""Extract information from the provided wheel, ensuring it meets basic
|
| 22 |
+
standards.
|
| 23 |
+
|
| 24 |
+
Returns the name of the .dist-info directory and the parsed WHEEL metadata.
|
| 25 |
+
"""
|
| 26 |
+
try:
|
| 27 |
+
info_dir = wheel_dist_info_dir(wheel_zip, name)
|
| 28 |
+
metadata = wheel_metadata(wheel_zip, info_dir)
|
| 29 |
+
version = wheel_version(metadata)
|
| 30 |
+
except UnsupportedWheel as e:
|
| 31 |
+
raise UnsupportedWheel(f"{name} has an invalid wheel, {str(e)}")
|
| 32 |
+
|
| 33 |
+
check_compatibility(version, name)
|
| 34 |
+
|
| 35 |
+
return info_dir, metadata
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def wheel_dist_info_dir(source: ZipFile, name: str) -> str:
|
| 39 |
+
"""Returns the name of the contained .dist-info directory.
|
| 40 |
+
|
| 41 |
+
Raises AssertionError or UnsupportedWheel if not found, >1 found, or
|
| 42 |
+
it doesn't match the provided name.
|
| 43 |
+
"""
|
| 44 |
+
# Zip file path separators must be /
|
| 45 |
+
subdirs = {p.split("/", 1)[0] for p in source.namelist()}
|
| 46 |
+
|
| 47 |
+
info_dirs = [s for s in subdirs if s.endswith(".dist-info")]
|
| 48 |
+
|
| 49 |
+
if not info_dirs:
|
| 50 |
+
raise UnsupportedWheel(".dist-info directory not found")
|
| 51 |
+
|
| 52 |
+
if len(info_dirs) > 1:
|
| 53 |
+
raise UnsupportedWheel(
|
| 54 |
+
"multiple .dist-info directories found: {}".format(", ".join(info_dirs))
|
| 55 |
+
)
|
| 56 |
+
|
| 57 |
+
info_dir = info_dirs[0]
|
| 58 |
+
|
| 59 |
+
info_dir_name = canonicalize_name(info_dir)
|
| 60 |
+
canonical_name = canonicalize_name(name)
|
| 61 |
+
if not info_dir_name.startswith(canonical_name):
|
| 62 |
+
raise UnsupportedWheel(
|
| 63 |
+
f".dist-info directory {info_dir!r} does not start with {canonical_name!r}"
|
| 64 |
+
)
|
| 65 |
+
|
| 66 |
+
return info_dir
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
def read_wheel_metadata_file(source: ZipFile, path: str) -> bytes:
|
| 70 |
+
try:
|
| 71 |
+
return source.read(path)
|
| 72 |
+
# BadZipFile for general corruption, KeyError for missing entry,
|
| 73 |
+
# and RuntimeError for password-protected files
|
| 74 |
+
except (BadZipFile, KeyError, RuntimeError) as e:
|
| 75 |
+
raise UnsupportedWheel(f"could not read {path!r} file: {e!r}")
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
def wheel_metadata(source: ZipFile, dist_info_dir: str) -> Message:
|
| 79 |
+
"""Return the WHEEL metadata of an extracted wheel, if possible.
|
| 80 |
+
Otherwise, raise UnsupportedWheel.
|
| 81 |
+
"""
|
| 82 |
+
path = f"{dist_info_dir}/WHEEL"
|
| 83 |
+
# Zip file path separators must be /
|
| 84 |
+
wheel_contents = read_wheel_metadata_file(source, path)
|
| 85 |
+
|
| 86 |
+
try:
|
| 87 |
+
wheel_text = wheel_contents.decode()
|
| 88 |
+
except UnicodeDecodeError as e:
|
| 89 |
+
raise UnsupportedWheel(f"error decoding {path!r}: {e!r}")
|
| 90 |
+
|
| 91 |
+
# FeedParser (used by Parser) does not raise any exceptions. The returned
|
| 92 |
+
# message may have .defects populated, but for backwards-compatibility we
|
| 93 |
+
# currently ignore them.
|
| 94 |
+
return Parser().parsestr(wheel_text)
|
| 95 |
+
|
| 96 |
+
|
| 97 |
+
def wheel_version(wheel_data: Message) -> Tuple[int, ...]:
|
| 98 |
+
"""Given WHEEL metadata, return the parsed Wheel-Version.
|
| 99 |
+
Otherwise, raise UnsupportedWheel.
|
| 100 |
+
"""
|
| 101 |
+
version_text = wheel_data["Wheel-Version"]
|
| 102 |
+
if version_text is None:
|
| 103 |
+
raise UnsupportedWheel("WHEEL is missing Wheel-Version")
|
| 104 |
+
|
| 105 |
+
version = version_text.strip()
|
| 106 |
+
|
| 107 |
+
try:
|
| 108 |
+
return tuple(map(int, version.split(".")))
|
| 109 |
+
except ValueError:
|
| 110 |
+
raise UnsupportedWheel(f"invalid Wheel-Version: {version!r}")
|
| 111 |
+
|
| 112 |
+
|
| 113 |
+
def check_compatibility(version: Tuple[int, ...], name: str) -> None:
|
| 114 |
+
"""Raises errors or warns if called with an incompatible Wheel-Version.
|
| 115 |
+
|
| 116 |
+
pip should refuse to install a Wheel-Version that's a major series
|
| 117 |
+
ahead of what it's compatible with (e.g 2.0 > 1.1); and warn when
|
| 118 |
+
installing a version only minor version ahead (e.g 1.2 > 1.1).
|
| 119 |
+
|
| 120 |
+
version: a 2-tuple representing a Wheel-Version (Major, Minor)
|
| 121 |
+
name: name of wheel or package to raise exception about
|
| 122 |
+
|
| 123 |
+
:raises UnsupportedWheel: when an incompatible Wheel-Version is given
|
| 124 |
+
"""
|
| 125 |
+
if version[0] > VERSION_COMPATIBLE[0]:
|
| 126 |
+
raise UnsupportedWheel(
|
| 127 |
+
"{}'s Wheel-Version ({}) is not compatible with this version "
|
| 128 |
+
"of pip".format(name, ".".join(map(str, version)))
|
| 129 |
+
)
|
| 130 |
+
elif version > VERSION_COMPATIBLE:
|
| 131 |
+
logger.warning(
|
| 132 |
+
"Installing from a newer Wheel-Version (%s)",
|
| 133 |
+
".".join(map(str, version)),
|
| 134 |
+
)
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_vendor/distro/__pycache__/__init__.cpython-38.pyc
ADDED
|
Binary file (960 Bytes). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_vendor/distro/__pycache__/__main__.cpython-38.pyc
ADDED
|
Binary file (222 Bytes). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_vendor/distro/__pycache__/distro.cpython-38.pyc
ADDED
|
Binary file (42.3 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/__init__.cpython-38.pyc
ADDED
|
Binary file (431 Bytes). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/_manylinux.cpython-38.pyc
ADDED
|
Binary file (7.25 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/_musllinux.cpython-38.pyc
ADDED
|
Binary file (4.58 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/requirements.cpython-38.pyc
ADDED
|
Binary file (3.94 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/specifiers.cpython-38.pyc
ADDED
|
Binary file (21.5 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/tags.cpython-38.pyc
ADDED
|
Binary file (12.2 kB). View file
|
|
|