Mercurial > repos > shellac > sam_consensus_v3
comparison env/lib/python3.9/site-packages/pip/_internal/cli/req_command.py @ 0:4f3585e2f14b draft default tip
"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author | shellac |
---|---|
date | Mon, 22 Mar 2021 18:12:50 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4f3585e2f14b |
---|---|
1 """Contains the Command base classes that depend on PipSession. | |
2 | |
3 The classes in this module are in a separate module so the commands not | |
4 needing download / PackageFinder capability don't unnecessarily import the | |
5 PackageFinder machinery and all its vendored dependencies, etc. | |
6 """ | |
7 | |
8 import logging | |
9 import os | |
10 from functools import partial | |
11 | |
12 from pip._internal.cli import cmdoptions | |
13 from pip._internal.cli.base_command import Command | |
14 from pip._internal.cli.command_context import CommandContextMixIn | |
15 from pip._internal.exceptions import CommandError, PreviousBuildDirError | |
16 from pip._internal.index.collector import LinkCollector | |
17 from pip._internal.index.package_finder import PackageFinder | |
18 from pip._internal.models.selection_prefs import SelectionPreferences | |
19 from pip._internal.network.session import PipSession | |
20 from pip._internal.operations.prepare import RequirementPreparer | |
21 from pip._internal.req.constructors import ( | |
22 install_req_from_editable, | |
23 install_req_from_line, | |
24 install_req_from_parsed_requirement, | |
25 install_req_from_req_string, | |
26 ) | |
27 from pip._internal.req.req_file import parse_requirements | |
28 from pip._internal.self_outdated_check import pip_self_version_check | |
29 from pip._internal.utils.temp_dir import tempdir_kinds | |
30 from pip._internal.utils.typing import MYPY_CHECK_RUNNING | |
31 | |
32 if MYPY_CHECK_RUNNING: | |
33 from optparse import Values | |
34 from typing import Any, List, Optional, Tuple | |
35 | |
36 from pip._internal.cache import WheelCache | |
37 from pip._internal.models.target_python import TargetPython | |
38 from pip._internal.req.req_install import InstallRequirement | |
39 from pip._internal.req.req_tracker import RequirementTracker | |
40 from pip._internal.resolution.base import BaseResolver | |
41 from pip._internal.utils.temp_dir import TempDirectory, TempDirectoryTypeRegistry | |
42 | |
43 | |
44 logger = logging.getLogger(__name__) | |
45 | |
46 | |
47 class SessionCommandMixin(CommandContextMixIn): | |
48 | |
49 """ | |
50 A class mixin for command classes needing _build_session(). | |
51 """ | |
52 def __init__(self): | |
53 # type: () -> None | |
54 super().__init__() | |
55 self._session = None # Optional[PipSession] | |
56 | |
57 @classmethod | |
58 def _get_index_urls(cls, options): | |
59 # type: (Values) -> Optional[List[str]] | |
60 """Return a list of index urls from user-provided options.""" | |
61 index_urls = [] | |
62 if not getattr(options, "no_index", False): | |
63 url = getattr(options, "index_url", None) | |
64 if url: | |
65 index_urls.append(url) | |
66 urls = getattr(options, "extra_index_urls", None) | |
67 if urls: | |
68 index_urls.extend(urls) | |
69 # Return None rather than an empty list | |
70 return index_urls or None | |
71 | |
72 def get_default_session(self, options): | |
73 # type: (Values) -> PipSession | |
74 """Get a default-managed session.""" | |
75 if self._session is None: | |
76 self._session = self.enter_context(self._build_session(options)) | |
77 # there's no type annotation on requests.Session, so it's | |
78 # automatically ContextManager[Any] and self._session becomes Any, | |
79 # then https://github.com/python/mypy/issues/7696 kicks in | |
80 assert self._session is not None | |
81 return self._session | |
82 | |
83 def _build_session(self, options, retries=None, timeout=None): | |
84 # type: (Values, Optional[int], Optional[int]) -> PipSession | |
85 assert not options.cache_dir or os.path.isabs(options.cache_dir) | |
86 session = PipSession( | |
87 cache=( | |
88 os.path.join(options.cache_dir, "http") | |
89 if options.cache_dir else None | |
90 ), | |
91 retries=retries if retries is not None else options.retries, | |
92 trusted_hosts=options.trusted_hosts, | |
93 index_urls=self._get_index_urls(options), | |
94 ) | |
95 | |
96 # Handle custom ca-bundles from the user | |
97 if options.cert: | |
98 session.verify = options.cert | |
99 | |
100 # Handle SSL client certificate | |
101 if options.client_cert: | |
102 session.cert = options.client_cert | |
103 | |
104 # Handle timeouts | |
105 if options.timeout or timeout: | |
106 session.timeout = ( | |
107 timeout if timeout is not None else options.timeout | |
108 ) | |
109 | |
110 # Handle configured proxies | |
111 if options.proxy: | |
112 session.proxies = { | |
113 "http": options.proxy, | |
114 "https": options.proxy, | |
115 } | |
116 | |
117 # Determine if we can prompt the user for authentication or not | |
118 session.auth.prompting = not options.no_input | |
119 | |
120 return session | |
121 | |
122 | |
123 class IndexGroupCommand(Command, SessionCommandMixin): | |
124 | |
125 """ | |
126 Abstract base class for commands with the index_group options. | |
127 | |
128 This also corresponds to the commands that permit the pip version check. | |
129 """ | |
130 | |
131 def handle_pip_version_check(self, options): | |
132 # type: (Values) -> None | |
133 """ | |
134 Do the pip version check if not disabled. | |
135 | |
136 This overrides the default behavior of not doing the check. | |
137 """ | |
138 # Make sure the index_group options are present. | |
139 assert hasattr(options, 'no_index') | |
140 | |
141 if options.disable_pip_version_check or options.no_index: | |
142 return | |
143 | |
144 # Otherwise, check if we're using the latest version of pip available. | |
145 session = self._build_session( | |
146 options, | |
147 retries=0, | |
148 timeout=min(5, options.timeout) | |
149 ) | |
150 with session: | |
151 pip_self_version_check(session, options) | |
152 | |
153 | |
154 KEEPABLE_TEMPDIR_TYPES = [ | |
155 tempdir_kinds.BUILD_ENV, | |
156 tempdir_kinds.EPHEM_WHEEL_CACHE, | |
157 tempdir_kinds.REQ_BUILD, | |
158 ] | |
159 | |
160 | |
161 def with_cleanup(func): | |
162 # type: (Any) -> Any | |
163 """Decorator for common logic related to managing temporary | |
164 directories. | |
165 """ | |
166 def configure_tempdir_registry(registry): | |
167 # type: (TempDirectoryTypeRegistry) -> None | |
168 for t in KEEPABLE_TEMPDIR_TYPES: | |
169 registry.set_delete(t, False) | |
170 | |
171 def wrapper(self, options, args): | |
172 # type: (RequirementCommand, Values, List[Any]) -> Optional[int] | |
173 assert self.tempdir_registry is not None | |
174 if options.no_clean: | |
175 configure_tempdir_registry(self.tempdir_registry) | |
176 | |
177 try: | |
178 return func(self, options, args) | |
179 except PreviousBuildDirError: | |
180 # This kind of conflict can occur when the user passes an explicit | |
181 # build directory with a pre-existing folder. In that case we do | |
182 # not want to accidentally remove it. | |
183 configure_tempdir_registry(self.tempdir_registry) | |
184 raise | |
185 | |
186 return wrapper | |
187 | |
188 | |
189 class RequirementCommand(IndexGroupCommand): | |
190 | |
191 def __init__(self, *args, **kw): | |
192 # type: (Any, Any) -> None | |
193 super().__init__(*args, **kw) | |
194 | |
195 self.cmd_opts.add_option(cmdoptions.no_clean()) | |
196 | |
197 @staticmethod | |
198 def determine_resolver_variant(options): | |
199 # type: (Values) -> str | |
200 """Determines which resolver should be used, based on the given options.""" | |
201 if "legacy-resolver" in options.deprecated_features_enabled: | |
202 return "legacy" | |
203 | |
204 return "2020-resolver" | |
205 | |
206 @classmethod | |
207 def make_requirement_preparer( | |
208 cls, | |
209 temp_build_dir, # type: TempDirectory | |
210 options, # type: Values | |
211 req_tracker, # type: RequirementTracker | |
212 session, # type: PipSession | |
213 finder, # type: PackageFinder | |
214 use_user_site, # type: bool | |
215 download_dir=None, # type: str | |
216 ): | |
217 # type: (...) -> RequirementPreparer | |
218 """ | |
219 Create a RequirementPreparer instance for the given parameters. | |
220 """ | |
221 temp_build_dir_path = temp_build_dir.path | |
222 assert temp_build_dir_path is not None | |
223 | |
224 resolver_variant = cls.determine_resolver_variant(options) | |
225 if resolver_variant == "2020-resolver": | |
226 lazy_wheel = 'fast-deps' in options.features_enabled | |
227 if lazy_wheel: | |
228 logger.warning( | |
229 'pip is using lazily downloaded wheels using HTTP ' | |
230 'range requests to obtain dependency information. ' | |
231 'This experimental feature is enabled through ' | |
232 '--use-feature=fast-deps and it is not ready for ' | |
233 'production.' | |
234 ) | |
235 else: | |
236 lazy_wheel = False | |
237 if 'fast-deps' in options.features_enabled: | |
238 logger.warning( | |
239 'fast-deps has no effect when used with the legacy resolver.' | |
240 ) | |
241 | |
242 return RequirementPreparer( | |
243 build_dir=temp_build_dir_path, | |
244 src_dir=options.src_dir, | |
245 download_dir=download_dir, | |
246 build_isolation=options.build_isolation, | |
247 req_tracker=req_tracker, | |
248 session=session, | |
249 progress_bar=options.progress_bar, | |
250 finder=finder, | |
251 require_hashes=options.require_hashes, | |
252 use_user_site=use_user_site, | |
253 lazy_wheel=lazy_wheel, | |
254 ) | |
255 | |
256 @classmethod | |
257 def make_resolver( | |
258 cls, | |
259 preparer, # type: RequirementPreparer | |
260 finder, # type: PackageFinder | |
261 options, # type: Values | |
262 wheel_cache=None, # type: Optional[WheelCache] | |
263 use_user_site=False, # type: bool | |
264 ignore_installed=True, # type: bool | |
265 ignore_requires_python=False, # type: bool | |
266 force_reinstall=False, # type: bool | |
267 upgrade_strategy="to-satisfy-only", # type: str | |
268 use_pep517=None, # type: Optional[bool] | |
269 py_version_info=None, # type: Optional[Tuple[int, ...]] | |
270 ): | |
271 # type: (...) -> BaseResolver | |
272 """ | |
273 Create a Resolver instance for the given parameters. | |
274 """ | |
275 make_install_req = partial( | |
276 install_req_from_req_string, | |
277 isolated=options.isolated_mode, | |
278 use_pep517=use_pep517, | |
279 ) | |
280 resolver_variant = cls.determine_resolver_variant(options) | |
281 # The long import name and duplicated invocation is needed to convince | |
282 # Mypy into correctly typechecking. Otherwise it would complain the | |
283 # "Resolver" class being redefined. | |
284 if resolver_variant == "2020-resolver": | |
285 import pip._internal.resolution.resolvelib.resolver | |
286 | |
287 return pip._internal.resolution.resolvelib.resolver.Resolver( | |
288 preparer=preparer, | |
289 finder=finder, | |
290 wheel_cache=wheel_cache, | |
291 make_install_req=make_install_req, | |
292 use_user_site=use_user_site, | |
293 ignore_dependencies=options.ignore_dependencies, | |
294 ignore_installed=ignore_installed, | |
295 ignore_requires_python=ignore_requires_python, | |
296 force_reinstall=force_reinstall, | |
297 upgrade_strategy=upgrade_strategy, | |
298 py_version_info=py_version_info, | |
299 ) | |
300 import pip._internal.resolution.legacy.resolver | |
301 return pip._internal.resolution.legacy.resolver.Resolver( | |
302 preparer=preparer, | |
303 finder=finder, | |
304 wheel_cache=wheel_cache, | |
305 make_install_req=make_install_req, | |
306 use_user_site=use_user_site, | |
307 ignore_dependencies=options.ignore_dependencies, | |
308 ignore_installed=ignore_installed, | |
309 ignore_requires_python=ignore_requires_python, | |
310 force_reinstall=force_reinstall, | |
311 upgrade_strategy=upgrade_strategy, | |
312 py_version_info=py_version_info, | |
313 ) | |
314 | |
315 def get_requirements( | |
316 self, | |
317 args, # type: List[str] | |
318 options, # type: Values | |
319 finder, # type: PackageFinder | |
320 session, # type: PipSession | |
321 ): | |
322 # type: (...) -> List[InstallRequirement] | |
323 """ | |
324 Parse command-line arguments into the corresponding requirements. | |
325 """ | |
326 requirements = [] # type: List[InstallRequirement] | |
327 for filename in options.constraints: | |
328 for parsed_req in parse_requirements( | |
329 filename, | |
330 constraint=True, finder=finder, options=options, | |
331 session=session): | |
332 req_to_add = install_req_from_parsed_requirement( | |
333 parsed_req, | |
334 isolated=options.isolated_mode, | |
335 user_supplied=False, | |
336 ) | |
337 requirements.append(req_to_add) | |
338 | |
339 for req in args: | |
340 req_to_add = install_req_from_line( | |
341 req, None, isolated=options.isolated_mode, | |
342 use_pep517=options.use_pep517, | |
343 user_supplied=True, | |
344 ) | |
345 requirements.append(req_to_add) | |
346 | |
347 for req in options.editables: | |
348 req_to_add = install_req_from_editable( | |
349 req, | |
350 user_supplied=True, | |
351 isolated=options.isolated_mode, | |
352 use_pep517=options.use_pep517, | |
353 ) | |
354 requirements.append(req_to_add) | |
355 | |
356 # NOTE: options.require_hashes may be set if --require-hashes is True | |
357 for filename in options.requirements: | |
358 for parsed_req in parse_requirements( | |
359 filename, | |
360 finder=finder, options=options, session=session): | |
361 req_to_add = install_req_from_parsed_requirement( | |
362 parsed_req, | |
363 isolated=options.isolated_mode, | |
364 use_pep517=options.use_pep517, | |
365 user_supplied=True, | |
366 ) | |
367 requirements.append(req_to_add) | |
368 | |
369 # If any requirement has hash options, enable hash checking. | |
370 if any(req.has_hash_options for req in requirements): | |
371 options.require_hashes = True | |
372 | |
373 if not (args or options.editables or options.requirements): | |
374 opts = {'name': self.name} | |
375 if options.find_links: | |
376 raise CommandError( | |
377 'You must give at least one requirement to {name} ' | |
378 '(maybe you meant "pip {name} {links}"?)'.format( | |
379 **dict(opts, links=' '.join(options.find_links)))) | |
380 else: | |
381 raise CommandError( | |
382 'You must give at least one requirement to {name} ' | |
383 '(see "pip help {name}")'.format(**opts)) | |
384 | |
385 return requirements | |
386 | |
387 @staticmethod | |
388 def trace_basic_info(finder): | |
389 # type: (PackageFinder) -> None | |
390 """ | |
391 Trace basic information about the provided objects. | |
392 """ | |
393 # Display where finder is looking for packages | |
394 search_scope = finder.search_scope | |
395 locations = search_scope.get_formatted_locations() | |
396 if locations: | |
397 logger.info(locations) | |
398 | |
399 def _build_package_finder( | |
400 self, | |
401 options, # type: Values | |
402 session, # type: PipSession | |
403 target_python=None, # type: Optional[TargetPython] | |
404 ignore_requires_python=None, # type: Optional[bool] | |
405 ): | |
406 # type: (...) -> PackageFinder | |
407 """ | |
408 Create a package finder appropriate to this requirement command. | |
409 | |
410 :param ignore_requires_python: Whether to ignore incompatible | |
411 "Requires-Python" values in links. Defaults to False. | |
412 """ | |
413 link_collector = LinkCollector.create(session, options=options) | |
414 selection_prefs = SelectionPreferences( | |
415 allow_yanked=True, | |
416 format_control=options.format_control, | |
417 allow_all_prereleases=options.pre, | |
418 prefer_binary=options.prefer_binary, | |
419 ignore_requires_python=ignore_requires_python, | |
420 ) | |
421 | |
422 return PackageFinder.create( | |
423 link_collector=link_collector, | |
424 selection_prefs=selection_prefs, | |
425 target_python=target_python, | |
426 ) |