Mercurial > repos > guerler > hhblits
comparison lib/python3.8/site-packages/pip/_internal/operations/freeze.py @ 1:64071f2a4cf0 draft default tip
Deleted selected files
| author | guerler |
|---|---|
| date | Mon, 27 Jul 2020 03:55:49 -0400 |
| parents | 9e54283cc701 |
| children |
comparison
equal
deleted
inserted
replaced
| 0:9e54283cc701 | 1:64071f2a4cf0 |
|---|---|
| 1 # The following comment should be removed at some point in the future. | |
| 2 # mypy: strict-optional=False | |
| 3 # mypy: disallow-untyped-defs=False | |
| 4 | |
| 5 from __future__ import absolute_import | |
| 6 | |
| 7 import collections | |
| 8 import logging | |
| 9 import os | |
| 10 import re | |
| 11 | |
| 12 from pip._vendor import six | |
| 13 from pip._vendor.packaging.utils import canonicalize_name | |
| 14 from pip._vendor.pkg_resources import RequirementParseError | |
| 15 | |
| 16 from pip._internal.exceptions import BadCommand, InstallationError | |
| 17 from pip._internal.req.constructors import ( | |
| 18 install_req_from_editable, | |
| 19 install_req_from_line, | |
| 20 ) | |
| 21 from pip._internal.req.req_file import COMMENT_RE | |
| 22 from pip._internal.utils.misc import ( | |
| 23 dist_is_editable, | |
| 24 get_installed_distributions, | |
| 25 ) | |
| 26 from pip._internal.utils.typing import MYPY_CHECK_RUNNING | |
| 27 | |
| 28 if MYPY_CHECK_RUNNING: | |
| 29 from typing import ( | |
| 30 Iterator, Optional, List, Container, Set, Dict, Tuple, Iterable, Union | |
| 31 ) | |
| 32 from pip._internal.cache import WheelCache | |
| 33 from pip._vendor.pkg_resources import ( | |
| 34 Distribution, Requirement | |
| 35 ) | |
| 36 | |
| 37 RequirementInfo = Tuple[Optional[Union[str, Requirement]], bool, List[str]] | |
| 38 | |
| 39 | |
| 40 logger = logging.getLogger(__name__) | |
| 41 | |
| 42 | |
| 43 def freeze( | |
| 44 requirement=None, # type: Optional[List[str]] | |
| 45 find_links=None, # type: Optional[List[str]] | |
| 46 local_only=None, # type: Optional[bool] | |
| 47 user_only=None, # type: Optional[bool] | |
| 48 paths=None, # type: Optional[List[str]] | |
| 49 skip_regex=None, # type: Optional[str] | |
| 50 isolated=False, # type: bool | |
| 51 wheel_cache=None, # type: Optional[WheelCache] | |
| 52 exclude_editable=False, # type: bool | |
| 53 skip=() # type: Container[str] | |
| 54 ): | |
| 55 # type: (...) -> Iterator[str] | |
| 56 find_links = find_links or [] | |
| 57 skip_match = None | |
| 58 | |
| 59 if skip_regex: | |
| 60 skip_match = re.compile(skip_regex).search | |
| 61 | |
| 62 for link in find_links: | |
| 63 yield '-f %s' % link | |
| 64 installations = {} # type: Dict[str, FrozenRequirement] | |
| 65 for dist in get_installed_distributions(local_only=local_only, | |
| 66 skip=(), | |
| 67 user_only=user_only, | |
| 68 paths=paths): | |
| 69 try: | |
| 70 req = FrozenRequirement.from_dist(dist) | |
| 71 except RequirementParseError as exc: | |
| 72 # We include dist rather than dist.project_name because the | |
| 73 # dist string includes more information, like the version and | |
| 74 # location. We also include the exception message to aid | |
| 75 # troubleshooting. | |
| 76 logger.warning( | |
| 77 'Could not generate requirement for distribution %r: %s', | |
| 78 dist, exc | |
| 79 ) | |
| 80 continue | |
| 81 if exclude_editable and req.editable: | |
| 82 continue | |
| 83 installations[req.canonical_name] = req | |
| 84 | |
| 85 if requirement: | |
| 86 # the options that don't get turned into an InstallRequirement | |
| 87 # should only be emitted once, even if the same option is in multiple | |
| 88 # requirements files, so we need to keep track of what has been emitted | |
| 89 # so that we don't emit it again if it's seen again | |
| 90 emitted_options = set() # type: Set[str] | |
| 91 # keep track of which files a requirement is in so that we can | |
| 92 # give an accurate warning if a requirement appears multiple times. | |
| 93 req_files = collections.defaultdict(list) # type: Dict[str, List[str]] | |
| 94 for req_file_path in requirement: | |
| 95 with open(req_file_path) as req_file: | |
| 96 for line in req_file: | |
| 97 if (not line.strip() or | |
| 98 line.strip().startswith('#') or | |
| 99 (skip_match and skip_match(line)) or | |
| 100 line.startswith(( | |
| 101 '-r', '--requirement', | |
| 102 '-Z', '--always-unzip', | |
| 103 '-f', '--find-links', | |
| 104 '-i', '--index-url', | |
| 105 '--pre', | |
| 106 '--trusted-host', | |
| 107 '--process-dependency-links', | |
| 108 '--extra-index-url'))): | |
| 109 line = line.rstrip() | |
| 110 if line not in emitted_options: | |
| 111 emitted_options.add(line) | |
| 112 yield line | |
| 113 continue | |
| 114 | |
| 115 if line.startswith('-e') or line.startswith('--editable'): | |
| 116 if line.startswith('-e'): | |
| 117 line = line[2:].strip() | |
| 118 else: | |
| 119 line = line[len('--editable'):].strip().lstrip('=') | |
| 120 line_req = install_req_from_editable( | |
| 121 line, | |
| 122 isolated=isolated, | |
| 123 wheel_cache=wheel_cache, | |
| 124 ) | |
| 125 else: | |
| 126 line_req = install_req_from_line( | |
| 127 COMMENT_RE.sub('', line).strip(), | |
| 128 isolated=isolated, | |
| 129 wheel_cache=wheel_cache, | |
| 130 ) | |
| 131 | |
| 132 if not line_req.name: | |
| 133 logger.info( | |
| 134 "Skipping line in requirement file [%s] because " | |
| 135 "it's not clear what it would install: %s", | |
| 136 req_file_path, line.strip(), | |
| 137 ) | |
| 138 logger.info( | |
| 139 " (add #egg=PackageName to the URL to avoid" | |
| 140 " this warning)" | |
| 141 ) | |
| 142 else: | |
| 143 line_req_canonical_name = canonicalize_name( | |
| 144 line_req.name) | |
| 145 if line_req_canonical_name not in installations: | |
| 146 # either it's not installed, or it is installed | |
| 147 # but has been processed already | |
| 148 if not req_files[line_req.name]: | |
| 149 logger.warning( | |
| 150 "Requirement file [%s] contains %s, but " | |
| 151 "package %r is not installed", | |
| 152 req_file_path, | |
| 153 COMMENT_RE.sub('', line).strip(), | |
| 154 line_req.name | |
| 155 ) | |
| 156 else: | |
| 157 req_files[line_req.name].append(req_file_path) | |
| 158 else: | |
| 159 yield str(installations[ | |
| 160 line_req_canonical_name]).rstrip() | |
| 161 del installations[line_req_canonical_name] | |
| 162 req_files[line_req.name].append(req_file_path) | |
| 163 | |
| 164 # Warn about requirements that were included multiple times (in a | |
| 165 # single requirements file or in different requirements files). | |
| 166 for name, files in six.iteritems(req_files): | |
| 167 if len(files) > 1: | |
| 168 logger.warning("Requirement %s included multiple times [%s]", | |
| 169 name, ', '.join(sorted(set(files)))) | |
| 170 | |
| 171 yield( | |
| 172 '## The following requirements were added by ' | |
| 173 'pip freeze:' | |
| 174 ) | |
| 175 for installation in sorted( | |
| 176 installations.values(), key=lambda x: x.name.lower()): | |
| 177 if installation.canonical_name not in skip: | |
| 178 yield str(installation).rstrip() | |
| 179 | |
| 180 | |
| 181 def get_requirement_info(dist): | |
| 182 # type: (Distribution) -> RequirementInfo | |
| 183 """ | |
| 184 Compute and return values (req, editable, comments) for use in | |
| 185 FrozenRequirement.from_dist(). | |
| 186 """ | |
| 187 if not dist_is_editable(dist): | |
| 188 return (None, False, []) | |
| 189 | |
| 190 location = os.path.normcase(os.path.abspath(dist.location)) | |
| 191 | |
| 192 from pip._internal.vcs import vcs, RemoteNotFoundError | |
| 193 vcs_backend = vcs.get_backend_for_dir(location) | |
| 194 | |
| 195 if vcs_backend is None: | |
| 196 req = dist.as_requirement() | |
| 197 logger.debug( | |
| 198 'No VCS found for editable requirement "%s" in: %r', req, | |
| 199 location, | |
| 200 ) | |
| 201 comments = [ | |
| 202 '# Editable install with no version control ({})'.format(req) | |
| 203 ] | |
| 204 return (location, True, comments) | |
| 205 | |
| 206 try: | |
| 207 req = vcs_backend.get_src_requirement(location, dist.project_name) | |
| 208 except RemoteNotFoundError: | |
| 209 req = dist.as_requirement() | |
| 210 comments = [ | |
| 211 '# Editable {} install with no remote ({})'.format( | |
| 212 type(vcs_backend).__name__, req, | |
| 213 ) | |
| 214 ] | |
| 215 return (location, True, comments) | |
| 216 | |
| 217 except BadCommand: | |
| 218 logger.warning( | |
| 219 'cannot determine version of editable source in %s ' | |
| 220 '(%s command not found in path)', | |
| 221 location, | |
| 222 vcs_backend.name, | |
| 223 ) | |
| 224 return (None, True, []) | |
| 225 | |
| 226 except InstallationError as exc: | |
| 227 logger.warning( | |
| 228 "Error when trying to get requirement for VCS system %s, " | |
| 229 "falling back to uneditable format", exc | |
| 230 ) | |
| 231 else: | |
| 232 if req is not None: | |
| 233 return (req, True, []) | |
| 234 | |
| 235 logger.warning( | |
| 236 'Could not determine repository location of %s', location | |
| 237 ) | |
| 238 comments = ['## !! Could not determine repository location'] | |
| 239 | |
| 240 return (None, False, comments) | |
| 241 | |
| 242 | |
| 243 class FrozenRequirement(object): | |
| 244 def __init__(self, name, req, editable, comments=()): | |
| 245 # type: (str, Union[str, Requirement], bool, Iterable[str]) -> None | |
| 246 self.name = name | |
| 247 self.canonical_name = canonicalize_name(name) | |
| 248 self.req = req | |
| 249 self.editable = editable | |
| 250 self.comments = comments | |
| 251 | |
| 252 @classmethod | |
| 253 def from_dist(cls, dist): | |
| 254 # type: (Distribution) -> FrozenRequirement | |
| 255 req, editable, comments = get_requirement_info(dist) | |
| 256 if req is None: | |
| 257 req = dist.as_requirement() | |
| 258 | |
| 259 return cls(dist.project_name, req, editable, comments=comments) | |
| 260 | |
| 261 def __str__(self): | |
| 262 req = self.req | |
| 263 if self.editable: | |
| 264 req = '-e %s' % req | |
| 265 return '\n'.join(list(self.comments) + [str(req)]) + '\n' |
