diff options
Diffstat (limited to 'venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/operations')
4 files changed, 0 insertions, 738 deletions
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/operations/__init__.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/operations/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/operations/__init__.py +++ /dev/null | |||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/operations/check.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/operations/check.py deleted file mode 100644 index bab6b9f..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/operations/check.py +++ /dev/null | |||
| @@ -1,106 +0,0 @@ | |||
| 1 | """Validation of dependencies of packages | ||
| 2 | """ | ||
| 3 | |||
| 4 | from collections import namedtuple | ||
| 5 | |||
| 6 | from pip._vendor.packaging.utils import canonicalize_name | ||
| 7 | |||
| 8 | from pip._internal.operations.prepare import make_abstract_dist | ||
| 9 | |||
| 10 | from pip._internal.utils.misc import get_installed_distributions | ||
| 11 | from pip._internal.utils.typing import MYPY_CHECK_RUNNING | ||
| 12 | |||
| 13 | if MYPY_CHECK_RUNNING: | ||
| 14 | from pip._internal.req.req_install import InstallRequirement | ||
| 15 | from typing import Any, Dict, Iterator, Set, Tuple, List | ||
| 16 | |||
| 17 | # Shorthands | ||
| 18 | PackageSet = Dict[str, 'PackageDetails'] | ||
| 19 | Missing = Tuple[str, Any] | ||
| 20 | Conflicting = Tuple[str, str, Any] | ||
| 21 | |||
| 22 | MissingDict = Dict[str, List[Missing]] | ||
| 23 | ConflictingDict = Dict[str, List[Conflicting]] | ||
| 24 | CheckResult = Tuple[MissingDict, ConflictingDict] | ||
| 25 | |||
| 26 | PackageDetails = namedtuple('PackageDetails', ['version', 'requires']) | ||
| 27 | |||
| 28 | |||
| 29 | def create_package_set_from_installed(**kwargs): | ||
| 30 | # type: (**Any) -> PackageSet | ||
| 31 | """Converts a list of distributions into a PackageSet. | ||
| 32 | """ | ||
| 33 | # Default to using all packages installed on the system | ||
| 34 | if kwargs == {}: | ||
| 35 | kwargs = {"local_only": False, "skip": ()} | ||
| 36 | retval = {} | ||
| 37 | for dist in get_installed_distributions(**kwargs): | ||
| 38 | name = canonicalize_name(dist.project_name) | ||
| 39 | retval[name] = PackageDetails(dist.version, dist.requires()) | ||
| 40 | return retval | ||
| 41 | |||
| 42 | |||
| 43 | def check_package_set(package_set): | ||
| 44 | # type: (PackageSet) -> CheckResult | ||
| 45 | """Check if a package set is consistent | ||
| 46 | """ | ||
| 47 | missing = dict() | ||
| 48 | conflicting = dict() | ||
| 49 | |||
| 50 | for package_name in package_set: | ||
| 51 | # Info about dependencies of package_name | ||
| 52 | missing_deps = set() # type: Set[Missing] | ||
| 53 | conflicting_deps = set() # type: Set[Conflicting] | ||
| 54 | |||
| 55 | for req in package_set[package_name].requires: | ||
| 56 | name = canonicalize_name(req.project_name) # type: str | ||
| 57 | |||
| 58 | # Check if it's missing | ||
| 59 | if name not in package_set: | ||
| 60 | missed = True | ||
| 61 | if req.marker is not None: | ||
| 62 | missed = req.marker.evaluate() | ||
| 63 | if missed: | ||
| 64 | missing_deps.add((name, req)) | ||
| 65 | continue | ||
| 66 | |||
| 67 | # Check if there's a conflict | ||
| 68 | version = package_set[name].version # type: str | ||
| 69 | if not req.specifier.contains(version, prereleases=True): | ||
| 70 | conflicting_deps.add((name, version, req)) | ||
| 71 | |||
| 72 | def str_key(x): | ||
| 73 | return str(x) | ||
| 74 | |||
| 75 | if missing_deps: | ||
| 76 | missing[package_name] = sorted(missing_deps, key=str_key) | ||
| 77 | if conflicting_deps: | ||
| 78 | conflicting[package_name] = sorted(conflicting_deps, key=str_key) | ||
| 79 | |||
| 80 | return missing, conflicting | ||
| 81 | |||
| 82 | |||
| 83 | def check_install_conflicts(to_install): | ||
| 84 | # type: (List[InstallRequirement]) -> Tuple[PackageSet, CheckResult] | ||
| 85 | """For checking if the dependency graph would be consistent after \ | ||
| 86 | installing given requirements | ||
| 87 | """ | ||
| 88 | # Start from the current state | ||
| 89 | state = create_package_set_from_installed() | ||
| 90 | _simulate_installation_of(to_install, state) | ||
| 91 | return state, check_package_set(state) | ||
| 92 | |||
| 93 | |||
| 94 | # NOTE from @pradyunsg | ||
| 95 | # This required a minor update in dependency link handling logic over at | ||
| 96 | # operations.prepare.IsSDist.dist() to get it working | ||
| 97 | def _simulate_installation_of(to_install, state): | ||
| 98 | # type: (List[InstallRequirement], PackageSet) -> None | ||
| 99 | """Computes the version of packages after installing to_install. | ||
| 100 | """ | ||
| 101 | |||
| 102 | # Modify it as installing requirement_set would (assuming no errors) | ||
| 103 | for inst_req in to_install: | ||
| 104 | dist = make_abstract_dist(inst_req).dist(finder=None) | ||
| 105 | name = canonicalize_name(dist.key) | ||
| 106 | state[name] = PackageDetails(dist.version, dist.requires()) | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/operations/freeze.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/operations/freeze.py deleted file mode 100644 index 000102d..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/operations/freeze.py +++ /dev/null | |||
| @@ -1,252 +0,0 @@ | |||
| 1 | from __future__ import absolute_import | ||
| 2 | |||
| 3 | import collections | ||
| 4 | import logging | ||
| 5 | import os | ||
| 6 | import re | ||
| 7 | import warnings | ||
| 8 | |||
| 9 | from pip._vendor import pkg_resources, six | ||
| 10 | from pip._vendor.packaging.utils import canonicalize_name | ||
| 11 | from pip._vendor.pkg_resources import RequirementParseError | ||
| 12 | |||
| 13 | from pip._internal.exceptions import InstallationError | ||
| 14 | from pip._internal.req import InstallRequirement | ||
| 15 | from pip._internal.req.req_file import COMMENT_RE | ||
| 16 | from pip._internal.utils.deprecation import RemovedInPip11Warning | ||
| 17 | from pip._internal.utils.misc import ( | ||
| 18 | dist_is_editable, get_installed_distributions, | ||
| 19 | ) | ||
| 20 | |||
| 21 | logger = logging.getLogger(__name__) | ||
| 22 | |||
| 23 | |||
| 24 | def freeze( | ||
| 25 | requirement=None, | ||
| 26 | find_links=None, local_only=None, user_only=None, skip_regex=None, | ||
| 27 | isolated=False, | ||
| 28 | wheel_cache=None, | ||
| 29 | exclude_editable=False, | ||
| 30 | skip=()): | ||
| 31 | find_links = find_links or [] | ||
| 32 | skip_match = None | ||
| 33 | |||
| 34 | if skip_regex: | ||
| 35 | skip_match = re.compile(skip_regex).search | ||
| 36 | |||
| 37 | dependency_links = [] | ||
| 38 | |||
| 39 | for dist in pkg_resources.working_set: | ||
| 40 | if dist.has_metadata('dependency_links.txt'): | ||
| 41 | dependency_links.extend( | ||
| 42 | dist.get_metadata_lines('dependency_links.txt') | ||
| 43 | ) | ||
| 44 | for link in find_links: | ||
| 45 | if '#egg=' in link: | ||
| 46 | dependency_links.append(link) | ||
| 47 | for link in find_links: | ||
| 48 | yield '-f %s' % link | ||
| 49 | installations = {} | ||
| 50 | for dist in get_installed_distributions(local_only=local_only, | ||
| 51 | skip=(), | ||
| 52 | user_only=user_only): | ||
| 53 | try: | ||
| 54 | req = FrozenRequirement.from_dist( | ||
| 55 | dist, | ||
| 56 | dependency_links | ||
| 57 | ) | ||
| 58 | except RequirementParseError: | ||
| 59 | logger.warning( | ||
| 60 | "Could not parse requirement: %s", | ||
| 61 | dist.project_name | ||
| 62 | ) | ||
| 63 | continue | ||
| 64 | if exclude_editable and req.editable: | ||
| 65 | continue | ||
| 66 | installations[req.name] = req | ||
| 67 | |||
| 68 | if requirement: | ||
| 69 | # the options that don't get turned into an InstallRequirement | ||
| 70 | # should only be emitted once, even if the same option is in multiple | ||
| 71 | # requirements files, so we need to keep track of what has been emitted | ||
| 72 | # so that we don't emit it again if it's seen again | ||
| 73 | emitted_options = set() | ||
| 74 | # keep track of which files a requirement is in so that we can | ||
| 75 | # give an accurate warning if a requirement appears multiple times. | ||
| 76 | req_files = collections.defaultdict(list) | ||
| 77 | for req_file_path in requirement: | ||
| 78 | with open(req_file_path) as req_file: | ||
| 79 | for line in req_file: | ||
| 80 | if (not line.strip() or | ||
| 81 | line.strip().startswith('#') or | ||
| 82 | (skip_match and skip_match(line)) or | ||
| 83 | line.startswith(( | ||
| 84 | '-r', '--requirement', | ||
| 85 | '-Z', '--always-unzip', | ||
| 86 | '-f', '--find-links', | ||
| 87 | '-i', '--index-url', | ||
| 88 | '--pre', | ||
| 89 | '--trusted-host', | ||
| 90 | '--process-dependency-links', | ||
| 91 | '--extra-index-url'))): | ||
| 92 | line = line.rstrip() | ||
| 93 | if line not in emitted_options: | ||
| 94 | emitted_options.add(line) | ||
| 95 | yield line | ||
| 96 | continue | ||
| 97 | |||
| 98 | if line.startswith('-e') or line.startswith('--editable'): | ||
| 99 | if line.startswith('-e'): | ||
| 100 | line = line[2:].strip() | ||
| 101 | else: | ||
| 102 | line = line[len('--editable'):].strip().lstrip('=') | ||
| 103 | line_req = InstallRequirement.from_editable( | ||
| 104 | line, | ||
| 105 | isolated=isolated, | ||
| 106 | wheel_cache=wheel_cache, | ||
| 107 | ) | ||
| 108 | else: | ||
| 109 | line_req = InstallRequirement.from_line( | ||
| 110 | COMMENT_RE.sub('', line).strip(), | ||
| 111 | isolated=isolated, | ||
| 112 | wheel_cache=wheel_cache, | ||
| 113 | ) | ||
| 114 | |||
| 115 | if not line_req.name: | ||
| 116 | logger.info( | ||
| 117 | "Skipping line in requirement file [%s] because " | ||
| 118 | "it's not clear what it would install: %s", | ||
| 119 | req_file_path, line.strip(), | ||
| 120 | ) | ||
| 121 | logger.info( | ||
| 122 | " (add #egg=PackageName to the URL to avoid" | ||
| 123 | " this warning)" | ||
| 124 | ) | ||
| 125 | elif line_req.name not in installations: | ||
| 126 | # either it's not installed, or it is installed | ||
| 127 | # but has been processed already | ||
| 128 | if not req_files[line_req.name]: | ||
| 129 | logger.warning( | ||
| 130 | "Requirement file [%s] contains %s, but that " | ||
| 131 | "package is not installed", | ||
| 132 | req_file_path, | ||
| 133 | COMMENT_RE.sub('', line).strip(), | ||
| 134 | ) | ||
| 135 | else: | ||
| 136 | req_files[line_req.name].append(req_file_path) | ||
| 137 | else: | ||
| 138 | yield str(installations[line_req.name]).rstrip() | ||
| 139 | del installations[line_req.name] | ||
| 140 | req_files[line_req.name].append(req_file_path) | ||
| 141 | |||
| 142 | # Warn about requirements that were included multiple times (in a | ||
| 143 | # single requirements file or in different requirements files). | ||
| 144 | for name, files in six.iteritems(req_files): | ||
| 145 | if len(files) > 1: | ||
| 146 | logger.warning("Requirement %s included multiple times [%s]", | ||
| 147 | name, ', '.join(sorted(set(files)))) | ||
| 148 | |||
| 149 | yield( | ||
| 150 | '## The following requirements were added by ' | ||
| 151 | 'pip freeze:' | ||
| 152 | ) | ||
| 153 | for installation in sorted( | ||
| 154 | installations.values(), key=lambda x: x.name.lower()): | ||
| 155 | if canonicalize_name(installation.name) not in skip: | ||
| 156 | yield str(installation).rstrip() | ||
| 157 | |||
| 158 | |||
| 159 | class FrozenRequirement(object): | ||
| 160 | def __init__(self, name, req, editable, comments=()): | ||
| 161 | self.name = name | ||
| 162 | self.req = req | ||
| 163 | self.editable = editable | ||
| 164 | self.comments = comments | ||
| 165 | |||
| 166 | _rev_re = re.compile(r'-r(\d+)$') | ||
| 167 | _date_re = re.compile(r'-(20\d\d\d\d\d\d)$') | ||
| 168 | |||
| 169 | @classmethod | ||
| 170 | def from_dist(cls, dist, dependency_links): | ||
| 171 | location = os.path.normcase(os.path.abspath(dist.location)) | ||
| 172 | comments = [] | ||
| 173 | from pip._internal.vcs import vcs, get_src_requirement | ||
| 174 | if dist_is_editable(dist) and vcs.get_backend_name(location): | ||
| 175 | editable = True | ||
| 176 | try: | ||
| 177 | req = get_src_requirement(dist, location) | ||
| 178 | except InstallationError as exc: | ||
| 179 | logger.warning( | ||
| 180 | "Error when trying to get requirement for VCS system %s, " | ||
| 181 | "falling back to uneditable format", exc | ||
| 182 | ) | ||
| 183 | req = None | ||
| 184 | if req is None: | ||
| 185 | logger.warning( | ||
| 186 | 'Could not determine repository location of %s', location | ||
| 187 | ) | ||
| 188 | comments.append( | ||
| 189 | '## !! Could not determine repository location' | ||
| 190 | ) | ||
| 191 | req = dist.as_requirement() | ||
| 192 | editable = False | ||
| 193 | else: | ||
| 194 | editable = False | ||
| 195 | req = dist.as_requirement() | ||
| 196 | specs = req.specs | ||
| 197 | assert len(specs) == 1 and specs[0][0] in ["==", "==="], \ | ||
| 198 | 'Expected 1 spec with == or ===; specs = %r; dist = %r' % \ | ||
| 199 | (specs, dist) | ||
| 200 | version = specs[0][1] | ||
| 201 | ver_match = cls._rev_re.search(version) | ||
| 202 | date_match = cls._date_re.search(version) | ||
| 203 | if ver_match or date_match: | ||
| 204 | svn_backend = vcs.get_backend('svn') | ||
| 205 | if svn_backend: | ||
| 206 | svn_location = svn_backend().get_location( | ||
| 207 | dist, | ||
| 208 | dependency_links, | ||
| 209 | ) | ||
| 210 | if not svn_location: | ||
| 211 | logger.warning( | ||
| 212 | 'Warning: cannot find svn location for %s', req, | ||
| 213 | ) | ||
| 214 | comments.append( | ||
| 215 | '## FIXME: could not find svn URL in dependency_links ' | ||
| 216 | 'for this package:' | ||
| 217 | ) | ||
| 218 | else: | ||
| 219 | warnings.warn( | ||
| 220 | "SVN editable detection based on dependency links " | ||
| 221 | "will be dropped in the future.", | ||
| 222 | RemovedInPip11Warning, | ||
| 223 | ) | ||
| 224 | comments.append( | ||
| 225 | '# Installing as editable to satisfy requirement %s:' % | ||
| 226 | req | ||
| 227 | ) | ||
| 228 | if ver_match: | ||
| 229 | rev = ver_match.group(1) | ||
| 230 | else: | ||
| 231 | rev = '{%s}' % date_match.group(1) | ||
| 232 | editable = True | ||
| 233 | req = '%s@%s#egg=%s' % ( | ||
| 234 | svn_location, | ||
| 235 | rev, | ||
| 236 | cls.egg_name(dist) | ||
| 237 | ) | ||
| 238 | return cls(dist.project_name, req, editable, comments) | ||
| 239 | |||
| 240 | @staticmethod | ||
| 241 | def egg_name(dist): | ||
| 242 | name = dist.egg_name() | ||
| 243 | match = re.search(r'-py\d\.\d$', name) | ||
| 244 | if match: | ||
| 245 | name = name[:match.start()] | ||
| 246 | return name | ||
| 247 | |||
| 248 | def __str__(self): | ||
| 249 | req = self.req | ||
| 250 | if self.editable: | ||
| 251 | req = '-e %s' % req | ||
| 252 | return '\n'.join(list(self.comments) + [str(req)]) + '\n' | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/operations/prepare.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/operations/prepare.py deleted file mode 100644 index c1e8158..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/operations/prepare.py +++ /dev/null | |||
| @@ -1,380 +0,0 @@ | |||
| 1 | """Prepares a distribution for installation | ||
| 2 | """ | ||
| 3 | |||
| 4 | import itertools | ||
| 5 | import logging | ||
| 6 | import os | ||
| 7 | import sys | ||
| 8 | from copy import copy | ||
| 9 | |||
| 10 | from pip._vendor import pkg_resources, requests | ||
| 11 | |||
| 12 | from pip._internal.build_env import NoOpBuildEnvironment | ||
| 13 | from pip._internal.compat import expanduser | ||
| 14 | from pip._internal.download import ( | ||
| 15 | is_dir_url, is_file_url, is_vcs_url, unpack_url, url_to_path, | ||
| 16 | ) | ||
| 17 | from pip._internal.exceptions import ( | ||
| 18 | DirectoryUrlHashUnsupported, HashUnpinned, InstallationError, | ||
| 19 | PreviousBuildDirError, VcsHashUnsupported, | ||
| 20 | ) | ||
| 21 | from pip._internal.index import FormatControl | ||
| 22 | from pip._internal.req.req_install import InstallRequirement | ||
| 23 | from pip._internal.utils.hashes import MissingHashes | ||
| 24 | from pip._internal.utils.logging import indent_log | ||
| 25 | from pip._internal.utils.misc import ( | ||
| 26 | call_subprocess, display_path, normalize_path, | ||
| 27 | ) | ||
| 28 | from pip._internal.utils.ui import open_spinner | ||
| 29 | from pip._internal.vcs import vcs | ||
| 30 | |||
| 31 | logger = logging.getLogger(__name__) | ||
| 32 | |||
| 33 | |||
| 34 | def make_abstract_dist(req): | ||
| 35 | """Factory to make an abstract dist object. | ||
| 36 | |||
| 37 | Preconditions: Either an editable req with a source_dir, or satisfied_by or | ||
| 38 | a wheel link, or a non-editable req with a source_dir. | ||
| 39 | |||
| 40 | :return: A concrete DistAbstraction. | ||
| 41 | """ | ||
| 42 | if req.editable: | ||
| 43 | return IsSDist(req) | ||
| 44 | elif req.link and req.link.is_wheel: | ||
| 45 | return IsWheel(req) | ||
| 46 | else: | ||
| 47 | return IsSDist(req) | ||
| 48 | |||
| 49 | |||
| 50 | def _install_build_reqs(finder, prefix, build_requirements): | ||
| 51 | # NOTE: What follows is not a very good thing. | ||
| 52 | # Eventually, this should move into the BuildEnvironment class and | ||
| 53 | # that should handle all the isolation and sub-process invocation. | ||
| 54 | finder = copy(finder) | ||
| 55 | finder.format_control = FormatControl(set(), set([":all:"])) | ||
| 56 | urls = [ | ||
| 57 | finder.find_requirement( | ||
| 58 | InstallRequirement.from_line(r), upgrade=False).url | ||
| 59 | for r in build_requirements | ||
| 60 | ] | ||
| 61 | args = [ | ||
| 62 | sys.executable, '-m', 'pip', 'install', '--ignore-installed', | ||
| 63 | '--no-user', '--prefix', prefix, | ||
| 64 | ] + list(urls) | ||
| 65 | |||
| 66 | with open_spinner("Installing build dependencies") as spinner: | ||
| 67 | call_subprocess(args, show_stdout=False, spinner=spinner) | ||
| 68 | |||
| 69 | |||
| 70 | class DistAbstraction(object): | ||
| 71 | """Abstracts out the wheel vs non-wheel Resolver.resolve() logic. | ||
| 72 | |||
| 73 | The requirements for anything installable are as follows: | ||
| 74 | - we must be able to determine the requirement name | ||
| 75 | (or we can't correctly handle the non-upgrade case). | ||
| 76 | - we must be able to generate a list of run-time dependencies | ||
| 77 | without installing any additional packages (or we would | ||
| 78 | have to either burn time by doing temporary isolated installs | ||
| 79 | or alternatively violate pips 'don't start installing unless | ||
| 80 | all requirements are available' rule - neither of which are | ||
| 81 | desirable). | ||
| 82 | - for packages with setup requirements, we must also be able | ||
| 83 | to determine their requirements without installing additional | ||
| 84 | packages (for the same reason as run-time dependencies) | ||
| 85 | - we must be able to create a Distribution object exposing the | ||
| 86 | above metadata. | ||
| 87 | """ | ||
| 88 | |||
| 89 | def __init__(self, req): | ||
| 90 | self.req = req | ||
| 91 | |||
| 92 | def dist(self, finder): | ||
| 93 | """Return a setuptools Dist object.""" | ||
| 94 | raise NotImplementedError(self.dist) | ||
| 95 | |||
| 96 | def prep_for_dist(self, finder): | ||
| 97 | """Ensure that we can get a Dist for this requirement.""" | ||
| 98 | raise NotImplementedError(self.dist) | ||
| 99 | |||
| 100 | |||
| 101 | class IsWheel(DistAbstraction): | ||
| 102 | |||
| 103 | def dist(self, finder): | ||
| 104 | return list(pkg_resources.find_distributions( | ||
| 105 | self.req.source_dir))[0] | ||
| 106 | |||
| 107 | def prep_for_dist(self, finder, build_isolation): | ||
| 108 | # FIXME:https://github.com/pypa/pip/issues/1112 | ||
| 109 | pass | ||
| 110 | |||
| 111 | |||
| 112 | class IsSDist(DistAbstraction): | ||
| 113 | |||
| 114 | def dist(self, finder): | ||
| 115 | dist = self.req.get_dist() | ||
| 116 | # FIXME: shouldn't be globally added. | ||
| 117 | if finder and dist.has_metadata('dependency_links.txt'): | ||
| 118 | finder.add_dependency_links( | ||
| 119 | dist.get_metadata_lines('dependency_links.txt') | ||
| 120 | ) | ||
| 121 | return dist | ||
| 122 | |||
| 123 | def prep_for_dist(self, finder, build_isolation): | ||
| 124 | # Before calling "setup.py egg_info", we need to set-up the build | ||
| 125 | # environment. | ||
| 126 | build_requirements, isolate = self.req.get_pep_518_info() | ||
| 127 | should_isolate = build_isolation and isolate | ||
| 128 | |||
| 129 | minimum_requirements = ('setuptools', 'wheel') | ||
| 130 | missing_requirements = set(minimum_requirements) - set( | ||
| 131 | pkg_resources.Requirement(r).key | ||
| 132 | for r in build_requirements | ||
| 133 | ) | ||
| 134 | if missing_requirements: | ||
| 135 | def format_reqs(rs): | ||
| 136 | return ' and '.join(map(repr, sorted(rs))) | ||
| 137 | logger.warning( | ||
| 138 | "Missing build time requirements in pyproject.toml for %s: " | ||
| 139 | "%s.", self.req, format_reqs(missing_requirements) | ||
| 140 | ) | ||
| 141 | logger.warning( | ||
| 142 | "This version of pip does not implement PEP 517 so it cannot " | ||
| 143 | "build a wheel without %s.", format_reqs(minimum_requirements) | ||
| 144 | ) | ||
| 145 | |||
| 146 | if should_isolate: | ||
| 147 | with self.req.build_env: | ||
| 148 | pass | ||
| 149 | _install_build_reqs(finder, self.req.build_env.path, | ||
| 150 | build_requirements) | ||
| 151 | else: | ||
| 152 | self.req.build_env = NoOpBuildEnvironment(no_clean=False) | ||
| 153 | |||
| 154 | self.req.run_egg_info() | ||
| 155 | self.req.assert_source_matches_version() | ||
| 156 | |||
| 157 | |||
| 158 | class Installed(DistAbstraction): | ||
| 159 | |||
| 160 | def dist(self, finder): | ||
| 161 | return self.req.satisfied_by | ||
| 162 | |||
| 163 | def prep_for_dist(self, finder): | ||
| 164 | pass | ||
| 165 | |||
| 166 | |||
| 167 | class RequirementPreparer(object): | ||
| 168 | """Prepares a Requirement | ||
| 169 | """ | ||
| 170 | |||
| 171 | def __init__(self, build_dir, download_dir, src_dir, wheel_download_dir, | ||
| 172 | progress_bar, build_isolation): | ||
| 173 | super(RequirementPreparer, self).__init__() | ||
| 174 | |||
| 175 | self.src_dir = src_dir | ||
| 176 | self.build_dir = build_dir | ||
| 177 | |||
| 178 | # Where still packed archives should be written to. If None, they are | ||
| 179 | # not saved, and are deleted immediately after unpacking. | ||
| 180 | self.download_dir = download_dir | ||
| 181 | |||
| 182 | # Where still-packed .whl files should be written to. If None, they are | ||
| 183 | # written to the download_dir parameter. Separate to download_dir to | ||
| 184 | # permit only keeping wheel archives for pip wheel. | ||
| 185 | if wheel_download_dir: | ||
| 186 | wheel_download_dir = normalize_path(wheel_download_dir) | ||
| 187 | self.wheel_download_dir = wheel_download_dir | ||
| 188 | |||
| 189 | # NOTE | ||
| 190 | # download_dir and wheel_download_dir overlap semantically and may | ||
| 191 | # be combined if we're willing to have non-wheel archives present in | ||
| 192 | # the wheelhouse output by 'pip wheel'. | ||
| 193 | |||
| 194 | self.progress_bar = progress_bar | ||
| 195 | |||
| 196 | # Is build isolation allowed? | ||
| 197 | self.build_isolation = build_isolation | ||
| 198 | |||
| 199 | @property | ||
| 200 | def _download_should_save(self): | ||
| 201 | # TODO: Modify to reduce indentation needed | ||
| 202 | if self.download_dir: | ||
| 203 | self.download_dir = expanduser(self.download_dir) | ||
| 204 | if os.path.exists(self.download_dir): | ||
| 205 | return True | ||
| 206 | else: | ||
| 207 | logger.critical('Could not find download directory') | ||
| 208 | raise InstallationError( | ||
| 209 | "Could not find or access download directory '%s'" | ||
| 210 | % display_path(self.download_dir)) | ||
| 211 | return False | ||
| 212 | |||
| 213 | def prepare_linked_requirement(self, req, session, finder, | ||
| 214 | upgrade_allowed, require_hashes): | ||
| 215 | """Prepare a requirement that would be obtained from req.link | ||
| 216 | """ | ||
| 217 | # TODO: Breakup into smaller functions | ||
| 218 | if req.link and req.link.scheme == 'file': | ||
| 219 | path = url_to_path(req.link.url) | ||
| 220 | logger.info('Processing %s', display_path(path)) | ||
| 221 | else: | ||
| 222 | logger.info('Collecting %s', req) | ||
| 223 | |||
| 224 | with indent_log(): | ||
| 225 | # @@ if filesystem packages are not marked | ||
| 226 | # editable in a req, a non deterministic error | ||
| 227 | # occurs when the script attempts to unpack the | ||
| 228 | # build directory | ||
| 229 | req.ensure_has_source_dir(self.build_dir) | ||
| 230 | # If a checkout exists, it's unwise to keep going. version | ||
| 231 | # inconsistencies are logged later, but do not fail the | ||
| 232 | # installation. | ||
| 233 | # FIXME: this won't upgrade when there's an existing | ||
| 234 | # package unpacked in `req.source_dir` | ||
| 235 | # package unpacked in `req.source_dir` | ||
| 236 | if os.path.exists(os.path.join(req.source_dir, 'setup.py')): | ||
| 237 | raise PreviousBuildDirError( | ||
| 238 | "pip can't proceed with requirements '%s' due to a" | ||
| 239 | " pre-existing build directory (%s). This is " | ||
| 240 | "likely due to a previous installation that failed" | ||
| 241 | ". pip is being responsible and not assuming it " | ||
| 242 | "can delete this. Please delete it and try again." | ||
| 243 | % (req, req.source_dir) | ||
| 244 | ) | ||
| 245 | req.populate_link(finder, upgrade_allowed, require_hashes) | ||
| 246 | |||
| 247 | # We can't hit this spot and have populate_link return None. | ||
| 248 | # req.satisfied_by is None here (because we're | ||
| 249 | # guarded) and upgrade has no impact except when satisfied_by | ||
| 250 | # is not None. | ||
| 251 | # Then inside find_requirement existing_applicable -> False | ||
| 252 | # If no new versions are found, DistributionNotFound is raised, | ||
| 253 | # otherwise a result is guaranteed. | ||
| 254 | assert req.link | ||
| 255 | link = req.link | ||
| 256 | |||
| 257 | # Now that we have the real link, we can tell what kind of | ||
| 258 | # requirements we have and raise some more informative errors | ||
| 259 | # than otherwise. (For example, we can raise VcsHashUnsupported | ||
| 260 | # for a VCS URL rather than HashMissing.) | ||
| 261 | if require_hashes: | ||
| 262 | # We could check these first 2 conditions inside | ||
| 263 | # unpack_url and save repetition of conditions, but then | ||
| 264 | # we would report less-useful error messages for | ||
| 265 | # unhashable requirements, complaining that there's no | ||
| 266 | # hash provided. | ||
| 267 | if is_vcs_url(link): | ||
| 268 | raise VcsHashUnsupported() | ||
| 269 | elif is_file_url(link) and is_dir_url(link): | ||
| 270 | raise DirectoryUrlHashUnsupported() | ||
| 271 | if not req.original_link and not req.is_pinned: | ||
| 272 | # Unpinned packages are asking for trouble when a new | ||
| 273 | # version is uploaded. This isn't a security check, but | ||
| 274 | # it saves users a surprising hash mismatch in the | ||
| 275 | # future. | ||
| 276 | # | ||
| 277 | # file:/// URLs aren't pinnable, so don't complain | ||
| 278 | # about them not being pinned. | ||
| 279 | raise HashUnpinned() | ||
| 280 | |||
| 281 | hashes = req.hashes(trust_internet=not require_hashes) | ||
| 282 | if require_hashes and not hashes: | ||
| 283 | # Known-good hashes are missing for this requirement, so | ||
| 284 | # shim it with a facade object that will provoke hash | ||
| 285 | # computation and then raise a HashMissing exception | ||
| 286 | # showing the user what the hash should be. | ||
| 287 | hashes = MissingHashes() | ||
| 288 | |||
| 289 | try: | ||
| 290 | download_dir = self.download_dir | ||
| 291 | # We always delete unpacked sdists after pip ran. | ||
| 292 | autodelete_unpacked = True | ||
| 293 | if req.link.is_wheel and self.wheel_download_dir: | ||
| 294 | # when doing 'pip wheel` we download wheels to a | ||
| 295 | # dedicated dir. | ||
| 296 | download_dir = self.wheel_download_dir | ||
| 297 | if req.link.is_wheel: | ||
| 298 | if download_dir: | ||
| 299 | # When downloading, we only unpack wheels to get | ||
| 300 | # metadata. | ||
| 301 | autodelete_unpacked = True | ||
| 302 | else: | ||
| 303 | # When installing a wheel, we use the unpacked | ||
| 304 | # wheel. | ||
| 305 | autodelete_unpacked = False | ||
| 306 | unpack_url( | ||
| 307 | req.link, req.source_dir, | ||
| 308 | download_dir, autodelete_unpacked, | ||
| 309 | session=session, hashes=hashes, | ||
| 310 | progress_bar=self.progress_bar | ||
| 311 | ) | ||
| 312 | except requests.HTTPError as exc: | ||
| 313 | logger.critical( | ||
| 314 | 'Could not install requirement %s because of error %s', | ||
| 315 | req, | ||
| 316 | exc, | ||
| 317 | ) | ||
| 318 | raise InstallationError( | ||
| 319 | 'Could not install requirement %s because of HTTP ' | ||
| 320 | 'error %s for URL %s' % | ||
| 321 | (req, exc, req.link) | ||
| 322 | ) | ||
| 323 | abstract_dist = make_abstract_dist(req) | ||
| 324 | abstract_dist.prep_for_dist(finder, self.build_isolation) | ||
| 325 | if self._download_should_save: | ||
| 326 | # Make a .zip of the source_dir we already created. | ||
| 327 | if req.link.scheme in vcs.all_schemes: | ||
| 328 | req.archive(self.download_dir) | ||
| 329 | return abstract_dist | ||
| 330 | |||
| 331 | def prepare_editable_requirement(self, req, require_hashes, use_user_site, | ||
| 332 | finder): | ||
| 333 | """Prepare an editable requirement | ||
| 334 | """ | ||
| 335 | assert req.editable, "cannot prepare a non-editable req as editable" | ||
| 336 | |||
| 337 | logger.info('Obtaining %s', req) | ||
| 338 | |||
| 339 | with indent_log(): | ||
| 340 | if require_hashes: | ||
| 341 | raise InstallationError( | ||
| 342 | 'The editable requirement %s cannot be installed when ' | ||
| 343 | 'requiring hashes, because there is no single file to ' | ||
| 344 | 'hash.' % req | ||
| 345 | ) | ||
| 346 | req.ensure_has_source_dir(self.src_dir) | ||
| 347 | req.update_editable(not self._download_should_save) | ||
| 348 | |||
| 349 | abstract_dist = make_abstract_dist(req) | ||
| 350 | abstract_dist.prep_for_dist(finder, self.build_isolation) | ||
| 351 | |||
| 352 | if self._download_should_save: | ||
| 353 | req.archive(self.download_dir) | ||
| 354 | req.check_if_exists(use_user_site) | ||
| 355 | |||
| 356 | return abstract_dist | ||
| 357 | |||
| 358 | def prepare_installed_requirement(self, req, require_hashes, skip_reason): | ||
| 359 | """Prepare an already-installed requirement | ||
| 360 | """ | ||
| 361 | assert req.satisfied_by, "req should have been satisfied but isn't" | ||
| 362 | assert skip_reason is not None, ( | ||
| 363 | "did not get skip reason skipped but req.satisfied_by " | ||
| 364 | "is set to %r" % (req.satisfied_by,) | ||
| 365 | ) | ||
| 366 | logger.info( | ||
| 367 | 'Requirement %s: %s (%s)', | ||
| 368 | skip_reason, req, req.satisfied_by.version | ||
| 369 | ) | ||
| 370 | with indent_log(): | ||
| 371 | if require_hashes: | ||
| 372 | logger.debug( | ||
| 373 | 'Since it is already installed, we are trusting this ' | ||
| 374 | 'package without checking its hash. To ensure a ' | ||
| 375 | 'completely repeatable environment, install into an ' | ||
| 376 | 'empty virtualenv.' | ||
| 377 | ) | ||
| 378 | abstract_dist = Installed(req) | ||
| 379 | |||
| 380 | return abstract_dist | ||
