1# -*- coding=utf-8 -*- 2""" 3Backports and helper functionality to support using new functionality. 4""" 5from __future__ import absolute_import, print_function 6 7import atexit 8import contextlib 9import functools 10import inspect 11import os 12import re 13import sys 14import types 15 16import six 17from packaging import specifiers 18 19from .environment import MYPY_RUNNING 20from .utils import ( 21 call_function_with_correct_args, 22 filter_allowed_args, 23 get_allowed_args, 24 get_method_args, 25 nullcontext, 26 suppress_setattr, 27) 28 29if sys.version_info[:2] < (3, 5): 30 from pipenv.vendor.vistir.compat import TemporaryDirectory 31else: 32 from tempfile import TemporaryDirectory 33 34if six.PY3: 35 from contextlib import ExitStack 36else: 37 from pipenv.vendor.contextlib2 import ExitStack 38 39 40if MYPY_RUNNING: 41 from optparse import Values 42 from requests import Session 43 from typing import ( 44 Any, 45 Callable, 46 Dict, 47 Generator, 48 Generic, 49 Iterable, 50 Iterator, 51 List, 52 Optional, 53 Tuple, 54 Type, 55 TypeVar, 56 Union, 57 ) 58 from .utils import TShimmedPath, TShim, TShimmedFunc 59 60 TFinder = TypeVar("TFinder") 61 TResolver = TypeVar("TResolver") 62 TReqTracker = TypeVar("TReqTracker") 63 TReqSet = TypeVar("TReqSet") 64 TLink = TypeVar("TLink") 65 TSession = TypeVar("TSession", bound=Session) 66 TCommand = TypeVar("TCommand", covariant=True) 67 TCommandInstance = TypeVar("TCommandInstance") 68 TCmdDict = Dict[str, Union[Tuple[str, str, str], TCommandInstance]] 69 TInstallRequirement = TypeVar("TInstallRequirement") 70 TFormatControl = TypeVar("TFormatControl") 71 TShimmedCmdDict = Union[TShim, TCmdDict] 72 TWheelCache = TypeVar("TWheelCache") 73 TPreparer = TypeVar("TPreparer") 74 75 76class SearchScope(object): 77 def __init__(self, find_links=None, index_urls=None): 78 self.index_urls = index_urls if index_urls else [] 79 self.find_links = find_links 80 81 @classmethod 82 def create(cls, find_links=None, index_urls=None): 83 if not index_urls: 84 index_urls = ["https://pypi.org/simple"] 85 return cls(find_links=find_links, index_urls=index_urls) 86 87 88class SelectionPreferences(object): 89 def __init__( 90 self, 91 allow_yanked=True, 92 allow_all_prereleases=False, 93 format_control=None, 94 prefer_binary=False, 95 ignore_requires_python=False, 96 ): 97 self.allow_yanked = allow_yanked 98 self.allow_all_prereleases = allow_all_prereleases 99 self.format_control = format_control 100 self.prefer_binary = prefer_binary 101 self.ignore_requires_python = ignore_requires_python 102 103 104class TargetPython(object): 105 fallback_get_tags = None # type: Optional[TShimmedFunc] 106 107 def __init__( 108 self, 109 platform=None, # type: Optional[str] 110 py_version_info=None, # type: Optional[Tuple[int, ...]] 111 abi=None, # type: Optional[str] 112 implementation=None, # type: Optional[str] 113 ): 114 # type: (...) -> None 115 self._given_py_version_info = py_version_info 116 if py_version_info is None: 117 py_version_info = sys.version_info[:3] 118 elif len(py_version_info) < 3: 119 py_version_info += (3 - len(py_version_info)) * (0,) 120 else: 121 py_version_info = py_version_info[:3] 122 py_version = ".".join(map(str, py_version_info[:2])) 123 self.abi = abi 124 self.implementation = implementation 125 self.platform = platform 126 self.py_version = py_version 127 self.py_version_info = py_version_info 128 self._valid_tags = None 129 130 def get_tags(self): 131 if self._valid_tags is None and self.fallback_get_tags: 132 fallback_func = resolve_possible_shim(self.fallback_get_tags) 133 versions = None 134 if self._given_py_version_info: 135 versions = ["".join(map(str, self._given_py_version_info[:2]))] 136 self._valid_tags = fallback_func( 137 versions=versions, 138 platform=self.platform, 139 abi=self.abi, 140 impl=self.implementation, 141 ) 142 return self._valid_tags 143 144 145class CandidatePreferences(object): 146 def __init__(self, prefer_binary=False, allow_all_prereleases=False): 147 self.prefer_binary = prefer_binary 148 self.allow_all_prereleases = allow_all_prereleases 149 150 151class LinkCollector(object): 152 def __init__(self, session=None, search_scope=None): 153 self.session = session 154 self.search_scope = search_scope 155 156 157class CandidateEvaluator(object): 158 @classmethod 159 def create( 160 cls, 161 project_name, # type: str 162 target_python=None, # type: Optional[TargetPython] 163 prefer_binary=False, # type: bool 164 allow_all_prereleases=False, # type: bool 165 specifier=None, # type: Optional[specifiers.BaseSpecifier] 166 hashes=None, # type: Optional[Any] 167 ): 168 if target_python is None: 169 target_python = TargetPython() 170 if specifier is None: 171 specifier = specifiers.SpecifierSet() 172 173 supported_tags = target_python.get_tags() 174 175 return cls( 176 project_name=project_name, 177 supported_tags=supported_tags, 178 specifier=specifier, 179 prefer_binary=prefer_binary, 180 allow_all_prereleases=allow_all_prereleases, 181 hashes=hashes, 182 ) 183 184 def __init__( 185 self, 186 project_name, # type: str 187 supported_tags, # type: List[Any] 188 specifier, # type: specifiers.BaseSpecifier 189 prefer_binary=False, # type: bool 190 allow_all_prereleases=False, # type: bool 191 hashes=None, # type: Optional[Any] 192 ): 193 self._allow_all_prereleases = allow_all_prereleases 194 self._hashes = hashes 195 self._prefer_binary = prefer_binary 196 self._project_name = project_name 197 self._specifier = specifier 198 self._supported_tags = supported_tags 199 200 201class LinkEvaluator(object): 202 def __init__( 203 self, 204 allow_yanked, 205 project_name, 206 canonical_name, 207 formats, 208 target_python, 209 ignore_requires_python=False, 210 ignore_compatibility=True, 211 ): 212 self._allow_yanked = allow_yanked 213 self._canonical_name = canonical_name 214 self._ignore_requires_python = ignore_requires_python 215 self._formats = formats 216 self._target_python = target_python 217 self._ignore_compatibility = ignore_compatibility 218 219 self.project_name = project_name 220 221 222class InvalidWheelFilename(Exception): 223 """Wheel Filename is Invalid""" 224 225 226class Wheel(object): 227 wheel_file_re = re.compile( 228 r"""^(?P<namever>(?P<name>.+?)-(?P<ver>.*?)) 229 ((-(?P<build>\d[^-]*?))?-(?P<pyver>.+?)-(?P<abi>.+?)-(?P<plat>.+?) 230 \.whl|\.dist-info)$""", 231 re.VERBOSE, 232 ) 233 234 def __init__(self, filename): 235 # type: (str) -> None 236 wheel_info = self.wheel_file_re.match(filename) 237 if not wheel_info: 238 raise InvalidWheelFilename("%s is not a valid wheel filename." % filename) 239 self.filename = filename 240 self.name = wheel_info.group("name").replace("_", "-") 241 # we'll assume "_" means "-" due to wheel naming scheme 242 # (https://github.com/pypa/pip/issues/1150) 243 self.version = wheel_info.group("ver").replace("_", "-") 244 self.build_tag = wheel_info.group("build") 245 self.pyversions = wheel_info.group("pyver").split(".") 246 self.abis = wheel_info.group("abi").split(".") 247 self.plats = wheel_info.group("plat").split(".") 248 249 # All the tag combinations from this file 250 self.file_tags = { 251 (x, y, z) for x in self.pyversions for y in self.abis for z in self.plats 252 } 253 254 def get_formatted_file_tags(self): 255 # type: () -> List[str] 256 """ 257 Return the wheel's tags as a sorted list of strings. 258 """ 259 return sorted("-".join(tag) for tag in self.file_tags) 260 261 def support_index_min(self, tags): 262 # type: (List[Any]) -> int 263 """ 264 Return the lowest index that one of the wheel's file_tag combinations 265 achieves in the given list of supported tags. 266 267 For example, if there are 8 supported tags and one of the file tags 268 is first in the list, then return 0. 269 270 :param tags: the PEP 425 tags to check the wheel against, in order 271 with most preferred first. 272 :raises ValueError: If none of the wheel's file tags match one of 273 the supported tags. 274 """ 275 return min(tags.index(tag) for tag in self.file_tags if tag in tags) 276 277 def supported(self, tags): 278 # type: (List[Any]) -> bool 279 """ 280 Return whether the wheel is compatible with one of the given tags. 281 282 :param tags: the PEP 425 tags to check the wheel against. 283 """ 284 return not self.file_tags.isdisjoint(tags) 285 286 287def resolve_possible_shim(target): 288 # type: (TShimmedFunc) -> Optional[Union[Type, Callable]] 289 if target is None: 290 return target 291 if getattr(target, "shim", None) and isinstance( 292 target.shim, (types.MethodType, types.FunctionType) 293 ): 294 return target.shim() 295 return target 296 297 298@contextlib.contextmanager 299def temp_environ(): 300 """Allow the ability to set os.environ temporarily""" 301 environ = dict(os.environ) 302 try: 303 yield 304 finally: 305 os.environ.clear() 306 os.environ.update(environ) 307 308 309@contextlib.contextmanager 310def get_requirement_tracker(req_tracker_creator=None): 311 # type: (Optional[Callable]) -> Generator[Optional[TReqTracker], None, None] 312 root = os.environ.get("PIP_REQ_TRACKER") 313 if not req_tracker_creator: 314 yield None 315 else: 316 req_tracker_args = [] 317 _, required_args = get_method_args(req_tracker_creator.__init__) # type: ignore 318 with ExitStack() as ctx: 319 if root is None: 320 root = ctx.enter_context(TemporaryDirectory(prefix="req-tracker")) 321 if root: 322 root = str(root) 323 ctx.enter_context(temp_environ()) 324 os.environ["PIP_REQ_TRACKER"] = root 325 if required_args is not None and "root" in required_args: 326 req_tracker_args.append(root) 327 with req_tracker_creator(*req_tracker_args) as tracker: 328 yield tracker 329 330 331@contextlib.contextmanager 332def ensure_resolution_dirs(**kwargs): 333 # type: (Any) -> Iterator[Dict[str, Any]] 334 """ 335 Ensures that the proper directories are scaffolded and present in the provided kwargs 336 for performing dependency resolution via pip. 337 338 :return: A new kwargs dictionary with scaffolded directories for **build_dir**, **src_dir**, 339 **download_dir**, and **wheel_download_dir** added to the key value pairs. 340 :rtype: Dict[str, Any] 341 """ 342 keys = ("build_dir", "src_dir", "download_dir", "wheel_download_dir") 343 if not any(kwargs.get(key) is None for key in keys): 344 yield kwargs 345 else: 346 with TemporaryDirectory(prefix="pip-shims-") as base_dir: 347 for key in keys: 348 if kwargs.get(key) is not None: 349 continue 350 target = os.path.join(base_dir, key) 351 os.makedirs(target) 352 kwargs[key] = target 353 yield kwargs 354 355 356@contextlib.contextmanager 357def wheel_cache( 358 cache_dir=None, # type: str 359 format_control=None, # type: Any 360 wheel_cache_provider=None, # type: TShimmedFunc 361 format_control_provider=None, # type: Optional[TShimmedFunc] 362 tempdir_manager_provider=None, # type: TShimmedFunc 363): 364 tempdir_manager_provider = resolve_possible_shim(tempdir_manager_provider) 365 wheel_cache_provider = resolve_possible_shim(wheel_cache_provider) 366 format_control_provider = resolve_possible_shim(format_control_provider) 367 if not format_control and not format_control_provider: 368 raise TypeError("Format control or provider needed for wheel cache!") 369 if not format_control: 370 format_control = format_control_provider(None, None) 371 with ExitStack() as ctx: 372 ctx.enter_context(tempdir_manager_provider()) 373 wheel_cache = wheel_cache_provider(cache_dir, format_control) 374 yield wheel_cache 375 376 377def partial_command(shimmed_path, cmd_mapping=None): 378 # type: (Type, Optional[TShimmedCmdDict]) -> Union[Type[TCommandInstance], functools.partial] 379 """ 380 Maps a default set of arguments across all members of a 381 :class:`~pip_shims.models.ShimmedPath` instance, specifically for 382 :class:`~pip._internal.command.Command` instances which need 383 `summary` and `name` arguments. 384 385 :param :class:`~pip_shims.models.ShimmedPath` shimmed_path: A 386 :class:`~pip_shims.models.ShimmedCollection` instance 387 :param Any cmd_mapping: A reference to use for mapping against, e.g. an 388 import that depends on pip also 389 :return: A dictionary mapping new arguments to their default values 390 :rtype: Dict[str, str] 391 """ 392 basecls = shimmed_path.shim() 393 resolved_cmd_mapping = None # type: Optional[Dict[str, Any]] 394 cmd_mapping = resolve_possible_shim(cmd_mapping) 395 if cmd_mapping is not None and isinstance(cmd_mapping, dict): 396 resolved_cmd_mapping = cmd_mapping.copy() 397 base_args = [] # type: List[str] 398 for root_cls in basecls.mro(): 399 if root_cls.__name__ == "Command": 400 _, root_init_args = get_method_args(root_cls.__init__) 401 if root_init_args is not None: 402 base_args = root_init_args.args 403 needs_name_and_summary = any(arg in base_args for arg in ("name", "summary")) 404 if not needs_name_and_summary: 405 basecls.name = shimmed_path.name 406 return basecls 407 elif ( 408 not resolved_cmd_mapping 409 and needs_name_and_summary 410 and getattr(functools, "partialmethod", None) 411 ): 412 new_init = functools.partial( 413 basecls.__init__, name=shimmed_path.name, summary="Summary" 414 ) 415 basecls.__init__ = new_init 416 result = basecls 417 assert resolved_cmd_mapping is not None 418 for command_name, command_info in resolved_cmd_mapping.items(): 419 if getattr(command_info, "class_name", None) == shimmed_path.name: 420 summary = getattr(command_info, "summary", "Command summary") 421 result = functools.partial(basecls, command_name, summary) 422 break 423 return result 424 425 426def get_session( 427 install_cmd_provider=None, # type: Optional[TShimmedFunc] 428 install_cmd=None, # type: TCommandInstance 429 options=None, # type: Optional[Values] 430): 431 # type: (...) -> TSession 432 session = None # type: Optional[TSession] 433 if install_cmd is None: 434 assert install_cmd_provider is not None 435 install_cmd_provider = resolve_possible_shim(install_cmd_provider) 436 assert isinstance(install_cmd_provider, (type, functools.partial)) 437 install_cmd = install_cmd_provider() 438 if options is None: 439 options, _ = install_cmd.parser.parse_args([]) # type: ignore 440 session = install_cmd._build_session(options) # type: ignore 441 assert session is not None 442 atexit.register(session.close) 443 return session 444 445 446def populate_options( 447 install_command=None, # type: TCommandInstance 448 options=None, # type: Optional[Values] 449 **kwargs # type: Any 450): 451 # (...) -> Tuple[Dict[str, Any], Values] 452 results = {} 453 if install_command is None and options is None: 454 raise TypeError("Must pass either options or InstallCommand to populate options") 455 if options is None and install_command is not None: 456 options, _ = install_command.parser.parse_args([]) # type: ignore 457 options_dict = options.__dict__ 458 for provided_key, provided_value in kwargs.items(): 459 if provided_key == "isolated": 460 options_key = "isolated_mode" 461 elif provided_key == "source_dir": 462 options_key = "src_dir" 463 else: 464 options_key = provided_key 465 if provided_key in options_dict and provided_value is not None: 466 setattr(options, options_key, provided_value) 467 results[provided_key] = provided_value 468 elif getattr(options, options_key, None) is not None: 469 results[provided_key] = getattr(options, options_key) 470 else: 471 results[provided_key] = provided_value 472 return results, options 473 474 475def get_requirement_set( 476 install_command=None, # type: Optional[TCommandInstance] 477 req_set_provider=None, # type: Optional[TShimmedFunc] 478 build_dir=None, # type: Optional[str] 479 src_dir=None, # type: Optional[str] 480 download_dir=None, # type: Optional[str] 481 wheel_download_dir=None, # type: Optional[str] 482 session=None, # type: Optional[TSession] 483 wheel_cache=None, # type: Optional[TWheelCache] 484 upgrade=False, # type: bool 485 upgrade_strategy=None, # type: Optional[str] 486 ignore_installed=False, # type: bool 487 ignore_dependencies=False, # type: bool 488 force_reinstall=False, # type: bool 489 use_user_site=False, # type: bool 490 isolated=False, # type: bool 491 ignore_requires_python=False, # type: bool 492 require_hashes=None, # type: bool 493 cache_dir=None, # type: Optional[str] 494 options=None, # type: Optional[Values] 495 install_cmd_provider=None, # type: Optional[TShimmedFunc] 496 wheel_cache_provider=None, # type: Optional[TShimmedFunc] 497): 498 # (...) -> TRequirementSet 499 """ 500 Creates a requirement set from the supplied parameters. 501 502 Not all parameters are passed through for all pip versions, but any 503 invalid parameters will be ignored if they are not needed to generate a 504 requirement set on the current pip version. 505 506 :param :class:`~pip_shims.models.ShimmedPathCollection` wheel_cache_provider: A 507 context manager provider which resolves to a `WheelCache` instance 508 :param install_command: A :class:`~pip._internal.commands.install.InstallCommand` 509 instance which is used to generate the finder. 510 :param :class:`~pip_shims.models.ShimmedPathCollection` req_set_provider: A provider 511 to build requirement set instances. 512 :param str build_dir: The directory to build requirements in. Removed in pip 10, 513 defeaults to None 514 :param str source_dir: The directory to use for source requirements. Removed in 515 pip 10, defaults to None 516 :param str download_dir: The directory to download requirement artifacts to. Removed 517 in pip 10, defaults to None 518 :param str wheel_download_dir: The directory to download wheels to. Removed in pip 519 10, defaults ot None 520 :param :class:`~requests.Session` session: The pip session to use. Removed in pip 10, 521 defaults to None 522 :param WheelCache wheel_cache: The pip WheelCache instance to use for caching wheels. 523 Removed in pip 10, defaults to None 524 :param bool upgrade: Whether to try to upgrade existing requirements. Removed in pip 525 10, defaults to False. 526 :param str upgrade_strategy: The upgrade strategy to use, e.g. "only-if-needed". 527 Removed in pip 10, defaults to None. 528 :param bool ignore_installed: Whether to ignore installed packages when resolving. 529 Removed in pip 10, defaults to False. 530 :param bool ignore_dependencies: Whether to ignore dependencies of requirements 531 when resolving. Removed in pip 10, defaults to False. 532 :param bool force_reinstall: Whether to force reinstall of packages when resolving. 533 Removed in pip 10, defaults to False. 534 :param bool use_user_site: Whether to use user site packages when resolving. Removed 535 in pip 10, defaults to False. 536 :param bool isolated: Whether to resolve in isolation. Removed in pip 10, defaults 537 to False. 538 :param bool ignore_requires_python: Removed in pip 10, defaults to False. 539 :param bool require_hashes: Whether to require hashes when resolving. Defaults to 540 False. 541 :param Values options: An :class:`~optparse.Values` instance from an install cmd 542 :param install_cmd_provider: A shim for providing new install command instances. 543 :type install_cmd_provider: :class:`~pip_shims.models.ShimmedPathCollection` 544 :return: A new requirement set instance 545 :rtype: :class:`~pip._internal.req.req_set.RequirementSet` 546 """ 547 wheel_cache_provider = resolve_possible_shim(wheel_cache_provider) 548 req_set_provider = resolve_possible_shim(req_set_provider) 549 if install_command is None: 550 install_cmd_provider = resolve_possible_shim(install_cmd_provider) 551 assert isinstance(install_cmd_provider, (type, functools.partial)) 552 install_command = install_cmd_provider() 553 required_args = inspect.getargs( 554 req_set_provider.__init__.__code__ 555 ).args # type: ignore 556 results, options = populate_options( 557 install_command, 558 options, 559 build_dir=build_dir, 560 src_dir=src_dir, 561 download_dir=download_dir, 562 upgrade=upgrade, 563 upgrade_strategy=upgrade_strategy, 564 ignore_installed=ignore_installed, 565 ignore_dependencies=ignore_dependencies, 566 force_reinstall=force_reinstall, 567 use_user_site=use_user_site, 568 isolated=isolated, 569 ignore_requires_python=ignore_requires_python, 570 require_hashes=require_hashes, 571 cache_dir=cache_dir, 572 ) 573 if session is None and "session" in required_args: 574 session = get_session(install_cmd=install_command, options=options) 575 with ExitStack() as stack: 576 if wheel_cache is None: 577 wheel_cache = stack.enter_context(wheel_cache_provider(cache_dir=cache_dir)) 578 results["wheel_cache"] = wheel_cache 579 results["session"] = session 580 results["wheel_download_dir"] = wheel_download_dir 581 return call_function_with_correct_args(req_set_provider, **results) 582 583 584def get_package_finder( 585 install_cmd=None, # type: Optional[TCommand] 586 options=None, # type: Optional[Values] 587 session=None, # type: Optional[TSession] 588 platform=None, # type: Optional[str] 589 python_versions=None, # type: Optional[Tuple[str, ...]] 590 abi=None, # type: Optional[str] 591 implementation=None, # type: Optional[str] 592 target_python=None, # type: Optional[Any] 593 ignore_requires_python=None, # type: Optional[bool] 594 target_python_builder=None, # type: Optional[TShimmedFunc] 595 install_cmd_provider=None, # type: Optional[TShimmedFunc] 596): 597 # type: (...) -> TFinder 598 """Shim for compatibility to generate package finders. 599 600 Build and return a :class:`~pip._internal.index.package_finder.PackageFinder` 601 instance using the :class:`~pip._internal.commands.install.InstallCommand` helper 602 method to construct the finder, shimmed with backports as needed for compatibility. 603 604 :param install_cmd_provider: A shim for providing new install command instances. 605 :type install_cmd_provider: :class:`~pip_shims.models.ShimmedPathCollection` 606 :param install_cmd: A :class:`~pip._internal.commands.install.InstallCommand` 607 instance which is used to generate the finder. 608 :param optparse.Values options: An optional :class:`optparse.Values` instance 609 generated by calling `install_cmd.parser.parse_args()` typically. 610 :param session: An optional session instance, can be created by the `install_cmd`. 611 :param Optional[str] platform: An optional platform string, e.g. linux_x86_64 612 :param Optional[Tuple[str, ...]] python_versions: A tuple of 2-digit strings 613 representing python versions, e.g. ("27", "35", "36", "37"...) 614 :param Optional[str] abi: The target abi to support, e.g. "cp38" 615 :param Optional[str] implementation: An optional implementation string for limiting 616 searches to a specific implementation, e.g. "cp" or "py" 617 :param target_python: A :class:`~pip._internal.models.target_python.TargetPython` 618 instance (will be translated to alternate arguments if necessary on incompatible 619 pip versions). 620 :param Optional[bool] ignore_requires_python: Whether to ignore `requires_python` 621 on resulting candidates, only valid after pip version 19.3.1 622 :param target_python_builder: A 'TargetPython' builder (e.g. the class itself, 623 uninstantiated) 624 :return: A :class:`pip._internal.index.package_finder.PackageFinder` instance 625 :rtype: :class:`pip._internal.index.package_finder.PackageFinder` 626 627 :Example: 628 629 >>> from pip_shims.shims import InstallCommand, get_package_finder 630 >>> install_cmd = InstallCommand() 631 >>> finder = get_package_finder( 632 ... install_cmd, python_versions=("27", "35", "36", "37", "38"), implementation=" 633 cp" 634 ... ) 635 >>> candidates = finder.find_all_candidates("requests") 636 >>> requests_222 = next(iter(c for c in candidates if c.version.public == "2.22.0")) 637 >>> requests_222 638 <InstallationCandidate('requests', <Version('2.22.0')>, <Link https://files.pythonhos 639 ted.org/packages/51/bd/23c926cd341ea6b7dd0b2a00aba99ae0f828be89d72b2190f27c11d4b7fb/r 640 equests-2.22.0-py2.py3-none-any.whl#sha256=9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9 641 a590f48c010551dc6c4b31 (from https://pypi.org/simple/requests/) (requires-python:>=2. 642 7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*)>)> 643 """ 644 if install_cmd is None: 645 install_cmd_provider = resolve_possible_shim(install_cmd_provider) 646 assert isinstance(install_cmd_provider, (type, functools.partial)) 647 install_cmd = install_cmd_provider() 648 if options is None: 649 options, _ = install_cmd.parser.parse_args([]) # type: ignore 650 if session is None: 651 session = get_session(install_cmd=install_cmd, options=options) # type: ignore 652 builder_args = inspect.getargs( 653 install_cmd._build_package_finder.__code__ 654 ) # type: ignore 655 build_kwargs = {"options": options, "session": session} 656 expects_targetpython = "target_python" in builder_args.args 657 received_python = any(arg for arg in [platform, python_versions, abi, implementation]) 658 if expects_targetpython and received_python and not target_python: 659 if target_python_builder is None: 660 target_python_builder = TargetPython 661 py_version_info = None 662 if python_versions: 663 py_version_info_python = max(python_versions) 664 py_version_info = tuple([int(part) for part in py_version_info_python]) 665 target_python = target_python_builder( 666 platform=platform, 667 abi=abi, 668 implementation=implementation, 669 py_version_info=py_version_info, 670 ) 671 build_kwargs["target_python"] = target_python 672 elif any( 673 arg in builder_args.args 674 for arg in ["platform", "python_versions", "abi", "implementation"] 675 ): 676 if target_python and not received_python: 677 tags = target_python.get_tags() 678 version_impl = {t[0] for t in tags} 679 # impls = set([v[:2] for v in version_impl]) 680 # impls.remove("py") 681 # impl = next(iter(impls), "py") if not target_python 682 versions = {v[2:] for v in version_impl} 683 build_kwargs.update( 684 { 685 "platform": target_python.platform, 686 "python_versions": versions, 687 "abi": target_python.abi, 688 "implementation": target_python.implementation, 689 } 690 ) 691 if ( 692 ignore_requires_python is not None 693 and "ignore_requires_python" in builder_args.args 694 ): 695 build_kwargs["ignore_requires_python"] = ignore_requires_python 696 return install_cmd._build_package_finder(**build_kwargs) # type: ignore 697 698 699def shim_unpack( 700 unpack_fn, # type: TShimmedFunc 701 download_dir, # type str 702 tempdir_manager_provider, # type: TShimmedFunc 703 ireq=None, # type: Optional[Any] 704 link=None, # type: Optional[Any] 705 location=None, # type Optional[str], 706 hashes=None, # type: Optional[Any] 707 progress_bar="off", # type: str 708 only_download=None, # type: Optional[bool] 709 downloader_provider=None, # type: Optional[TShimmedFunc] 710 session=None, # type: Optional[Any] 711): 712 # (...) -> None 713 """ 714 Accepts all parameters that have been valid to pass 715 to :func:`pip._internal.download.unpack_url` and selects or 716 drops parameters as needed before invoking the provided 717 callable. 718 719 :param unpack_fn: A callable or shim referring to the pip implementation 720 :type unpack_fn: Callable 721 :param str download_dir: The directory to download the file to 722 :param TShimmedFunc tempdir_manager_provider: A callable or shim referring to 723 `global_tempdir_manager` function from pip or a shimmed no-op context manager 724 :param Optional[:class:`~pip._internal.req.req_install.InstallRequirement`] ireq: 725 an Install Requirement instance, defaults to None 726 :param Optional[:class:`~pip._internal.models.link.Link`] link: A Link instance, 727 defaults to None. 728 :param Optional[str] location: A location or source directory if the target is 729 a VCS url, defaults to None. 730 :param Optional[Any] hashes: A Hashes instance, defaults to None 731 :param str progress_bar: Indicates progress par usage during download, defatuls to 732 off. 733 :param Optional[bool] only_download: Whether to skip install, defaults to None. 734 :param Optional[ShimmedPathCollection] downloader_provider: A downloader class 735 to instantiate, if applicable. 736 :param Optional[`~requests.Session`] session: A PipSession instance, defaults to 737 None. 738 :return: The result of unpacking the url. 739 :rtype: None 740 """ 741 unpack_fn = resolve_possible_shim(unpack_fn) 742 downloader_provider = resolve_possible_shim(downloader_provider) 743 tempdir_manager_provider = resolve_possible_shim(tempdir_manager_provider) 744 required_args = inspect.getargs(unpack_fn.__code__).args # type: ignore 745 unpack_kwargs = {"download_dir": download_dir} 746 with tempdir_manager_provider(): 747 if ireq: 748 if not link and ireq.link: 749 link = ireq.link 750 if only_download is None: 751 only_download = ireq.is_wheel 752 if hashes is None: 753 hashes = ireq.hashes(True) 754 if location is None and getattr(ireq, "source_dir", None): 755 location = ireq.source_dir 756 unpack_kwargs.update({"link": link, "location": location}) 757 if hashes is not None and "hashes" in required_args: 758 unpack_kwargs["hashes"] = hashes 759 if "progress_bar" in required_args: 760 unpack_kwargs["progress_bar"] = progress_bar 761 if only_download is not None and "only_download" in required_args: 762 unpack_kwargs["only_download"] = only_download 763 if session is not None and "session" in required_args: 764 unpack_kwargs["session"] = session 765 if "downloader" in required_args and downloader_provider is not None: 766 assert session is not None 767 assert progress_bar is not None 768 unpack_kwargs["downloader"] = downloader_provider(session, progress_bar) 769 return unpack_fn(**unpack_kwargs) # type: ignore 770 771 772def _ensure_finder( 773 finder=None, # type: Optional[TFinder] 774 finder_provider=None, # type: Optional[Callable] 775 install_cmd=None, # type: Optional[TCommandInstance] 776 options=None, # type: Optional[Values] 777 session=None, # type: Optional[TSession] 778): 779 if not any([finder, finder_provider, install_cmd]): 780 raise TypeError( 781 "RequirementPreparer requires a packagefinder but no InstallCommand" 782 " was provided to build one and none was passed in." 783 ) 784 if finder is not None: 785 return finder 786 else: 787 if session is None: 788 session = get_session(install_cmd=install_cmd, options=options) 789 if finder_provider is not None and options is not None: 790 finder_provider(options=options, session=session) 791 else: 792 finder = get_package_finder(install_cmd, options=options, session=session) 793 return finder 794 795 796@contextlib.contextmanager 797def make_preparer( 798 preparer_fn, # type: TShimmedFunc 799 req_tracker_fn=None, # type: Optional[TShimmedFunc] 800 build_dir=None, # type: Optional[str] 801 src_dir=None, # type: Optional[str] 802 download_dir=None, # type: Optional[str] 803 wheel_download_dir=None, # type: Optional[str] 804 progress_bar="off", # type: str 805 build_isolation=False, # type: bool 806 session=None, # type: Optional[TSession] 807 finder=None, # type: Optional[TFinder] 808 options=None, # type: Optional[Values] 809 require_hashes=None, # type: Optional[bool] 810 use_user_site=None, # type: Optional[bool] 811 req_tracker=None, # type: Optional[Union[TReqTracker, TShimmedFunc]] 812 install_cmd_provider=None, # type: Optional[TShimmedFunc] 813 downloader_provider=None, # type: Optional[TShimmedFunc] 814 install_cmd=None, # type: Optional[TCommandInstance] 815 finder_provider=None, # type: Optional[TShimmedFunc] 816): 817 # (...) -> ContextManager 818 """ 819 Creates a requirement preparer for preparing pip requirements. 820 821 Provides a compatibilty shim that accepts all previously valid arguments and 822 discards any that are no longer used. 823 824 :raises TypeError: No requirement tracker provided and one cannot be generated 825 :raises TypeError: No valid sessions provided and one cannot be generated 826 :raises TypeError: No valid finders provided and one cannot be generated 827 :param TShimmedFunc preparer_fn: Callable or shim for generating preparers. 828 :param Optional[TShimmedFunc] req_tracker_fn: Callable or shim for generating 829 requirement trackers, defualts to None 830 :param Optional[str] build_dir: Directory for building packages and wheels, 831 defaults to None 832 :param Optional[str] src_dir: Directory to find or extract source files, defaults 833 to None 834 :param Optional[str] download_dir: Target directory to download files, defaults to 835 None 836 :param Optional[str] wheel_download_dir: Target directoryto download wheels, defaults 837 to None 838 :param str progress_bar: Whether to display a progress bar, defaults to off 839 :param bool build_isolation: Whether to build requirements in isolation, defaults 840 to False 841 :param Optional[TSession] session: Existing session to use for getting requirements, 842 defaults to None 843 :param Optional[TFinder] finder: The package finder to use during resolution, 844 defaults to None 845 :param Optional[Values] options: Pip options to use if needed, defaults to None 846 :param Optional[bool] require_hashes: Whether to require hashes for preparation 847 :param Optional[bool] use_user_site: Whether to use the user site directory for 848 preparing requirements 849 :param Optional[Union[TReqTracker, TShimmedFunc]] req_tracker: The requirement 850 tracker to use for building packages, defaults to None 851 :param Optional[TShimmedFunc] downloader_provider: A downloader provider 852 :param Optional[TCommandInstance] install_cmd: The install command used to create 853 the finder, session, and options if needed, defaults to None 854 :param Optional[TShimmedFunc] finder_provider: A package finder provider 855 :yield: A new requirement preparer instance 856 :rtype: ContextManager[:class:`~pip._internal.operations.prepare.RequirementPreparer`] 857 858 :Example: 859 860 >>> from pip_shims.shims import ( 861 ... InstallCommand, get_package_finder, make_preparer, get_requirement_tracker 862 ... ) 863 >>> install_cmd = InstallCommand() 864 >>> pip_options, _ = install_cmd.parser.parse_args([]) 865 >>> session = install_cmd._build_session(pip_options) 866 >>> finder = get_package_finder( 867 ... install_cmd, session=session, options=pip_options 868 ... ) 869 >>> with make_preparer( 870 ... options=pip_options, finder=finder, session=session, install_cmd=ic 871 ... ) as preparer: 872 ... print(preparer) 873 <pip._internal.operations.prepare.RequirementPreparer object at 0x7f8a2734be80> 874 """ 875 preparer_fn = resolve_possible_shim(preparer_fn) 876 downloader_provider = resolve_possible_shim(downloader_provider) 877 finder_provider = resolve_possible_shim(finder_provider) 878 required_args, required_kwargs = get_allowed_args(preparer_fn) # type: ignore 879 if not req_tracker and not req_tracker_fn and "req_tracker" in required_args: 880 raise TypeError("No requirement tracker and no req tracker generator found!") 881 if "downloader" in required_args and not downloader_provider: 882 raise TypeError("no downloader provided, but one is required to continue!") 883 req_tracker_fn = resolve_possible_shim(req_tracker_fn) 884 pip_options_created = options is None 885 session_is_required = "session" in required_args 886 finder_is_required = "finder" in required_args 887 downloader_is_required = "downloader" in required_args 888 options_map = { 889 "src_dir": src_dir, 890 "download_dir": download_dir, 891 "wheel_download_dir": wheel_download_dir, 892 "build_dir": build_dir, 893 "progress_bar": progress_bar, 894 "build_isolation": build_isolation, 895 "require_hashes": require_hashes, 896 "use_user_site": use_user_site, 897 } 898 if install_cmd is None: 899 assert install_cmd_provider is not None 900 install_cmd_provider = resolve_possible_shim(install_cmd_provider) 901 assert isinstance(install_cmd_provider, (type, functools.partial)) 902 install_cmd = install_cmd_provider() 903 preparer_args, options = populate_options(install_cmd, options, **options_map) 904 if options is not None and pip_options_created: 905 for k, v in options_map.items(): 906 suppress_setattr(options, k, v, filter_none=True) 907 if session_is_required: 908 if session is None: 909 session = get_session(install_cmd=install_cmd, options=options) 910 preparer_args["session"] = session 911 if finder_is_required: 912 finder = _ensure_finder( 913 finder=finder, 914 finder_provider=finder_provider, 915 install_cmd=install_cmd, 916 options=options, 917 session=session, 918 ) 919 preparer_args["finder"] = finder 920 if downloader_is_required: 921 preparer_args["downloader"] = downloader_provider(session, progress_bar) 922 req_tracker_fn = nullcontext if not req_tracker_fn else req_tracker_fn 923 with req_tracker_fn() as tracker_ctx: 924 if "req_tracker" in required_args: 925 req_tracker = tracker_ctx if req_tracker is None else req_tracker 926 preparer_args["req_tracker"] = req_tracker 927 preparer_args["lazy_wheel"] = True 928 result = call_function_with_correct_args(preparer_fn, **preparer_args) 929 yield result 930 931 932@contextlib.contextmanager 933def _ensure_wheel_cache( 934 wheel_cache=None, # type: Optional[Type[TWheelCache]] 935 wheel_cache_provider=None, # type: Optional[Callable] 936 format_control=None, # type: Optional[TFormatControl] 937 format_control_provider=None, # type: Optional[Type[TShimmedFunc]] 938 options=None, # type: Optional[Values] 939 cache_dir=None, # type: Optional[str] 940): 941 if wheel_cache is not None: 942 yield wheel_cache 943 elif wheel_cache_provider is not None: 944 with ExitStack() as stack: 945 cache_dir = getattr(options, "cache_dir", cache_dir) 946 format_control = getattr( 947 options, 948 "format_control", 949 format_control_provider(None, None), # TFormatControl 950 ) 951 wheel_cache = stack.enter_context( 952 wheel_cache_provider(cache_dir, format_control) 953 ) 954 yield wheel_cache 955 956 957def get_ireq_output_path(wheel_cache, ireq): 958 if getattr(wheel_cache, "get_path_for_link", None): 959 return wheel_cache.get_path_for_link(ireq.link) 960 elif getattr(wheel_cache, "cached_wheel", None): 961 return wheel_cache.cached_wheel(ireq.link, ireq.name).url_without_fragment 962 963 964def get_resolver( 965 resolver_fn, # type: TShimmedFunc 966 install_req_provider=None, # type: Optional[TShimmedFunc] 967 format_control_provider=None, # type: Optional[TShimmedFunc] 968 wheel_cache_provider=None, # type: Optional[TShimmedFunc] 969 finder=None, # type: Optional[TFinder] 970 upgrade_strategy="to-satisfy-only", # type: str 971 force_reinstall=None, # type: Optional[bool] 972 ignore_dependencies=None, # type: Optional[bool] 973 ignore_requires_python=None, # type: Optional[bool] 974 ignore_installed=True, # type: bool 975 use_user_site=False, # type: bool 976 isolated=None, # type: Optional[bool] 977 wheel_cache=None, # type: Optional[TWheelCache] 978 preparer=None, # type: Optional[TPreparer] 979 session=None, # type: Optional[TSession] 980 options=None, # type: Optional[Values] 981 make_install_req=None, # type: Optional[Callable] 982 install_cmd_provider=None, # type: Optional[TShimmedFunc] 983 install_cmd=None, # type: Optional[TCommandInstance] 984 use_pep517=True, # type: bool 985): 986 # (...) -> TResolver 987 """ 988 A resolver creation compatibility shim for generating a resolver. 989 990 Consumes any argument that was previously used to instantiate a 991 resolver, discards anything that is no longer valid. 992 993 .. note:: This is only valid for **pip >= 10.0.0** 994 995 :raises ValueError: A session is required but not provided and one cannot be created 996 :raises ValueError: A finder is required but not provided and one cannot be created 997 :raises ValueError: An install requirement provider is required and has not been 998 provided 999 :param TShimmedFunc resolver_fn: The resolver function used to create new resolver 1000 instances. 1001 :param TShimmedFunc install_req_provider: The provider function to use to generate 1002 install requirements if needed. 1003 :param TShimmedFunc format_control_provider: The provider function to use to generate 1004 a format_control instance if needed. 1005 :param TShimmedFunc wheel_cache_provider: The provider function to use to generate 1006 a wheel cache if needed. 1007 :param Optional[TFinder] finder: The package finder to use during resolution, 1008 defaults to None. 1009 :param str upgrade_strategy: Upgrade strategy to use, defaults to ``only-if-needed``. 1010 :param Optional[bool] force_reinstall: Whether to simulate or assume package 1011 reinstallation during resolution, defaults to None 1012 :param Optional[bool] ignore_dependencies: Whether to ignore package dependencies, 1013 defaults to None 1014 :param Optional[bool] ignore_requires_python: Whether to ignore indicated 1015 required_python versions on packages, defaults to None 1016 :param bool ignore_installed: Whether to ignore installed packages during resolution, 1017 defaults to True 1018 :param bool use_user_site: Whether to use the user site location during resolution, 1019 defaults to False 1020 :param Optional[bool] isolated: Whether to isolate the resolution process, defaults 1021 to None 1022 :param Optional[TWheelCache] wheel_cache: The wheel cache to use, defaults to None 1023 :param Optional[TPreparer] preparer: The requirement preparer to use, defaults to 1024 None 1025 :param Optional[TSession] session: Existing session to use for getting requirements, 1026 defaults to None 1027 :param Optional[Values] options: Pip options to use if needed, defaults to None 1028 :param Optional[functools.partial] make_install_req: The partial function to pass in 1029 to the resolver for actually generating install requirements, if necessary 1030 :param Optional[TCommandInstance] install_cmd: The install command used to create 1031 the finder, session, and options if needed, defaults to None. 1032 :param bool use_pep517: Whether to use the pep517 build process. 1033 :return: A new resolver instance. 1034 :rtype: :class:`~pip._internal.legacy_resolve.Resolver` 1035 1036 :Example: 1037 1038 >>> import os 1039 >>> from tempdir import TemporaryDirectory 1040 >>> from pip_shims.shims import ( 1041 ... InstallCommand, get_package_finder, make_preparer, get_requirement_tracker, 1042 ... get_resolver, InstallRequirement, RequirementSet 1043 ... ) 1044 >>> install_cmd = InstallCommand() 1045 >>> pip_options, _ = install_cmd.parser.parse_args([]) 1046 >>> session = install_cmd._build_session(pip_options) 1047 >>> finder = get_package_finder( 1048 ... install_cmd, session=session, options=pip_options 1049 ... ) 1050 >>> wheel_cache = WheelCache(USER_CACHE_DIR, FormatControl(None, None)) 1051 >>> with TemporaryDirectory() as temp_base: 1052 ... reqset = RequirementSet() 1053 ... ireq = InstallRequirement.from_line("requests") 1054 ... ireq.is_direct = True 1055 ... build_dir = os.path.join(temp_base, "build") 1056 ... src_dir = os.path.join(temp_base, "src") 1057 ... ireq.build_location(build_dir) 1058 ... with make_preparer( 1059 ... options=pip_options, finder=finder, session=session, 1060 ... build_dir=build_dir, install_cmd=install_cmd, 1061 ... ) as preparer: 1062 ... resolver = get_resolver( 1063 ... finder=finder, ignore_dependencies=False, ignore_requires_python=True, 1064 ... preparer=preparer, session=session, options=pip_options, 1065 ... install_cmd=install_cmd, wheel_cache=wheel_cache, 1066 ... ) 1067 ... resolver.require_hashes = False 1068 ... reqset.add_requirement(ireq) 1069 ... results = resolver.resolve(reqset) 1070 ... #reqset.cleanup_files() 1071 ... for result_req in reqset.requirements: 1072 ... print(result_req) 1073 requests 1074 chardet 1075 certifi 1076 urllib3 1077 idna 1078 """ 1079 resolver_fn = resolve_possible_shim(resolver_fn) 1080 install_req_provider = resolve_possible_shim(install_req_provider) 1081 format_control_provider = resolve_possible_shim(format_control_provider) 1082 wheel_cache_provider = resolve_possible_shim(wheel_cache_provider) 1083 install_cmd_provider = resolve_possible_shim(install_cmd_provider) 1084 required_args = inspect.getargs(resolver_fn.__init__.__code__).args # type: ignore 1085 install_cmd_dependency_map = {"session": session, "finder": finder} 1086 resolver_kwargs = {} # type: Dict[str, Any] 1087 if install_cmd is None: 1088 assert isinstance(install_cmd_provider, (type, functools.partial)) 1089 install_cmd = install_cmd_provider() 1090 if options is None and install_cmd is not None: 1091 options, _ = install_cmd.parser.parse_args([]) # type: ignore 1092 for arg, val in install_cmd_dependency_map.items(): 1093 if arg not in required_args: 1094 continue 1095 elif val is None and install_cmd is None: 1096 raise TypeError( 1097 "Preparer requires a {} but did not receive one " 1098 "and cannot generate one".format(arg) 1099 ) 1100 elif arg == "session" and val is None: 1101 val = get_session(install_cmd=install_cmd, options=options) 1102 elif arg == "finder" and val is None: 1103 val = get_package_finder(install_cmd, options=options, session=session) 1104 resolver_kwargs[arg] = val 1105 if "make_install_req" in required_args: 1106 if make_install_req is None and install_req_provider is not None: 1107 make_install_req_kwargs = { 1108 "isolated": isolated, 1109 "wheel_cache": wheel_cache, 1110 "use_pep517": use_pep517, 1111 } 1112 factory_args, factory_kwargs = filter_allowed_args( 1113 install_req_provider, **make_install_req_kwargs 1114 ) 1115 make_install_req = functools.partial( 1116 install_req_provider, *factory_args, **factory_kwargs 1117 ) 1118 assert make_install_req is not None 1119 resolver_kwargs["make_install_req"] = make_install_req 1120 if "isolated" in required_args: 1121 resolver_kwargs["isolated"] = isolated 1122 resolver_kwargs.update( 1123 { 1124 "upgrade_strategy": upgrade_strategy, 1125 "force_reinstall": force_reinstall, 1126 "ignore_dependencies": ignore_dependencies, 1127 "ignore_requires_python": ignore_requires_python, 1128 "ignore_installed": ignore_installed, 1129 "use_user_site": use_user_site, 1130 "preparer": preparer, 1131 } 1132 ) 1133 if "wheel_cache" in required_args: 1134 with _ensure_wheel_cache( 1135 wheel_cache=wheel_cache, 1136 wheel_cache_provider=wheel_cache_provider, 1137 format_control_provider=format_control_provider, 1138 options=options, 1139 ) as wheel_cache: 1140 resolver_kwargs["wheel_cache"] = wheel_cache 1141 return resolver_fn(**resolver_kwargs) # type: ignore 1142 return resolver_fn(**resolver_kwargs) # type: ignore 1143 1144 1145def resolve( # noqa:C901 1146 ireq, # type: TInstallRequirement 1147 reqset_provider=None, # type: Optional[TShimmedFunc] 1148 req_tracker_provider=None, # type: Optional[TShimmedFunc] 1149 install_cmd_provider=None, # type: Optional[TShimmedFunc] 1150 install_command=None, # type: Optional[TCommand] 1151 finder_provider=None, # type: Optional[TShimmedFunc] 1152 resolver_provider=None, # type: Optional[TShimmedFunc] 1153 wheel_cache_provider=None, # type: Optional[TShimmedFunc] 1154 format_control_provider=None, # type: Optional[TShimmedFunc] 1155 make_preparer_provider=None, # type: Optional[TShimmedFunc] 1156 tempdir_manager_provider=None, # type: Optional[TShimmedFunc] 1157 options=None, # type: Optional[Values] 1158 session=None, # type: Optional[TSession] 1159 resolver=None, # type: Optional[TResolver] 1160 finder=None, # type: Optional[TFinder] 1161 upgrade_strategy="to-satisfy-only", # type: str 1162 force_reinstall=None, # type: Optional[bool] 1163 ignore_dependencies=None, # type: Optional[bool] 1164 ignore_requires_python=None, # type: Optional[bool] 1165 ignore_installed=True, # type: bool 1166 use_user_site=False, # type: bool 1167 isolated=None, # type: Optional[bool] 1168 build_dir=None, # type: Optional[str] 1169 source_dir=None, # type: Optional[str] 1170 download_dir=None, # type: Optional[str] 1171 cache_dir=None, # type: Optional[str] 1172 wheel_download_dir=None, # type: Optional[str] 1173 wheel_cache=None, # type: Optional[TWheelCache] 1174 require_hashes=None, # type: bool 1175 check_supported_wheels=True, # type: bool 1176): 1177 # (...) -> Set[TInstallRequirement] 1178 """ 1179 Resolves the provided **InstallRequirement**, returning a dictionary. 1180 1181 Maps a dictionary of names to corresponding ``InstallRequirement`` values. 1182 1183 :param :class:`~pip._internal.req.req_install.InstallRequirement` ireq: An 1184 InstallRequirement to initiate the resolution process 1185 :param :class:`~pip_shims.models.ShimmedPathCollection` reqset_provider: A provider 1186 to build requirement set instances. 1187 :param :class:`~pip_shims.models.ShimmedPathCollection` req_tracker_provider: A 1188 provider to build requirement tracker instances 1189 :param install_cmd_provider: A shim for providing new install command instances. 1190 :type install_cmd_provider: :class:`~pip_shims.models.ShimmedPathCollection` 1191 :param Optional[TCommandInstance] install_command: The install command used to 1192 create the finder, session, and options if needed, defaults to None. 1193 :param :class:`~pip_shims.models.ShimmedPathCollection` finder_provider: A provider 1194 to package finder instances. 1195 :param :class:`~pip_shims.models.ShimmedPathCollection` resolver_provider: A provider 1196 to build resolver instances 1197 :param TShimmedFunc wheel_cache_provider: The provider function to use to generate a 1198 wheel cache if needed. 1199 :param TShimmedFunc format_control_provider: The provider function to use to generate 1200 a format_control instance if needed. 1201 :param TShimmedFunc make_preparer_provider: Callable or shim for generating preparers. 1202 :param Optional[TShimmedFunc] tempdir_manager_provider: Shim for generating tempdir 1203 manager for pip temporary directories 1204 :param Optional[Values] options: Pip options to use if needed, defaults to None 1205 :param Optional[TSession] session: Existing session to use for getting requirements, 1206 defaults to None 1207 :param :class:`~pip._internal.legacy_resolve.Resolver` resolver: A pre-existing 1208 resolver instance to use for resolution 1209 :param Optional[TFinder] finder: The package finder to use during resolution, 1210 defaults to None. 1211 :param str upgrade_strategy: Upgrade strategy to use, defaults to ``only-if-needed``. 1212 :param Optional[bool] force_reinstall: Whether to simulate or assume package 1213 reinstallation during resolution, defaults to None 1214 :param Optional[bool] ignore_dependencies: Whether to ignore package dependencies, 1215 defaults to None 1216 :param Optional[bool] ignore_requires_python: Whether to ignore indicated 1217 required_python versions on packages, defaults to None 1218 :param bool ignore_installed: Whether to ignore installed packages during 1219 resolution, defaults to True 1220 :param bool use_user_site: Whether to use the user site location during resolution, 1221 defaults to False 1222 :param Optional[bool] isolated: Whether to isolate the resolution process, defaults 1223 to None 1224 :param Optional[str] build_dir: Directory for building packages and wheels, defaults 1225 to None 1226 :param str source_dir: The directory to use for source requirements. Removed in pip 1227 10, defaults to None 1228 :param Optional[str] download_dir: Target directory to download files, defaults to 1229 None 1230 :param str cache_dir: The cache directory to use for caching artifacts during 1231 resolution 1232 :param Optional[str] wheel_download_dir: Target directoryto download wheels, defaults 1233 to None 1234 :param Optional[TWheelCache] wheel_cache: The wheel cache to use, defaults to None 1235 :param bool require_hashes: Whether to require hashes when resolving. Defaults to 1236 False. 1237 :param bool check_supported_wheels: Whether to check support of wheels before including 1238 them in resolution. 1239 :return: A dictionary mapping requirements to corresponding 1240 :class:`~pip._internal.req.req_install.InstallRequirement`s 1241 :rtype: :class:`~pip._internal.req.req_install.InstallRequirement` 1242 1243 :Example: 1244 1245 >>> from pip_shims.shims import resolve, InstallRequirement 1246 >>> ireq = InstallRequirement.from_line("requests>=2.20") 1247 >>> results = resolve(ireq) 1248 >>> for k, v in results.items(): 1249 ... print("{0}: {1!r}".format(k, v)) 1250 requests: <InstallRequirement object: requests>=2.20 from https://files.pythonhosted. 1251 org/packages/51/bd/23c926cd341ea6b7dd0b2a00aba99ae0f828be89d72b2190f27c11d4b7fb/reque 1252 sts-2.22.0-py2.py3-none-any.whl#sha256=9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590 1253 f48c010551dc6c4b31 editable=False> 1254 idna: <InstallRequirement object: idna<2.9,>=2.5 from https://files.pythonhosted.org/ 1255 packages/14/2c/cd551d81dbe15200be1cf41cd03869a46fe7226e7450af7a6545bfc474c9/idna-2.8- 1256 py2.py3-none-any.whl#sha256=ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432 1257 f7e4a3c (from requests>=2.20) editable=False> 1258 urllib3: <InstallRequirement object: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 from htt 1259 ps://files.pythonhosted.org/packages/b4/40/a9837291310ee1ccc242ceb6ebfd9eb21539649f19 1260 3a7c8c86ba15b98539/urllib3-1.25.7-py2.py3-none-any.whl#sha256=a8a318824cc77d1fd4b2bec 1261 2ded92646630d7fe8619497b142c84a9e6f5a7293 (from requests>=2.20) editable=False> 1262 chardet: <InstallRequirement object: chardet<3.1.0,>=3.0.2 from https://files.pythonh 1263 osted.org/packages/bc/a9/01ffebfb562e4274b6487b4bb1ddec7ca55ec7510b22e4c51f14098443b8 1264 /chardet-3.0.4-py2.py3-none-any.whl#sha256=fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed 1265 4531e3e15460124c106691 (from requests>=2.20) editable=False> 1266 certifi: <InstallRequirement object: certifi>=2017.4.17 from https://files.pythonhost 1267 ed.org/packages/18/b0/8146a4f8dd402f60744fa380bc73ca47303cccf8b9190fd16a827281eac2/ce 1268 rtifi-2019.9.11-py2.py3-none-any.whl#sha256=fd7c7c74727ddcf00e9acd26bba8da604ffec95bf 1269 1c2144e67aff7a8b50e6cef (from requests>=2.20) editable=False> 1270 """ 1271 reqset_provider = resolve_possible_shim(reqset_provider) 1272 finder_provider = resolve_possible_shim(finder_provider) 1273 resolver_provider = resolve_possible_shim(resolver_provider) 1274 wheel_cache_provider = resolve_possible_shim(wheel_cache_provider) 1275 format_control_provider = resolve_possible_shim(format_control_provider) 1276 make_preparer_provider = resolve_possible_shim(make_preparer_provider) 1277 req_tracker_provider = resolve_possible_shim(req_tracker_provider) 1278 install_cmd_provider = resolve_possible_shim(install_cmd_provider) 1279 tempdir_manager_provider = resolve_possible_shim(tempdir_manager_provider) 1280 if install_command is None: 1281 assert isinstance(install_cmd_provider, (type, functools.partial)) 1282 install_command = install_cmd_provider() 1283 kwarg_map = { 1284 "upgrade_strategy": upgrade_strategy, 1285 "force_reinstall": force_reinstall, 1286 "ignore_dependencies": ignore_dependencies, 1287 "ignore_requires_python": ignore_requires_python, 1288 "ignore_installed": ignore_installed, 1289 "use_user_site": use_user_site, 1290 "isolated": isolated, 1291 "build_dir": build_dir, 1292 "src_dir": source_dir, 1293 "download_dir": download_dir, 1294 "require_hashes": require_hashes, 1295 "cache_dir": cache_dir, 1296 } 1297 kwargs, options = populate_options(install_command, options, **kwarg_map) 1298 with ExitStack() as ctx: 1299 ctx.enter_context(tempdir_manager_provider()) 1300 kwargs = ctx.enter_context( 1301 ensure_resolution_dirs(wheel_download_dir=wheel_download_dir, **kwargs) 1302 ) 1303 wheel_download_dir = kwargs.pop("wheel_download_dir") 1304 if session is None: 1305 session = get_session(install_cmd=install_command, options=options) 1306 if finder is None: 1307 finder = finder_provider( 1308 install_command, options=options, session=session 1309 ) # type: ignore 1310 format_control = getattr(options, "format_control", None) 1311 if not format_control: 1312 format_control = format_control_provider(None, None) # type: ignore 1313 wheel_cache = ctx.enter_context( 1314 wheel_cache_provider(kwargs["cache_dir"], format_control) 1315 ) # type: ignore 1316 ireq.is_direct = True # type: ignore 1317 build_location_kwargs = { 1318 "build_dir": kwargs["build_dir"], 1319 "autodelete": True, 1320 "parallel_builds": False 1321 } 1322 call_function_with_correct_args(ireq.build_location, **build_location_kwargs) 1323 if reqset_provider is None: 1324 raise TypeError( 1325 "cannot resolve without a requirement set provider... failed!" 1326 ) 1327 reqset = reqset_provider( 1328 install_command, 1329 options=options, 1330 session=session, 1331 wheel_download_dir=wheel_download_dir, 1332 **kwargs 1333 ) # type: ignore 1334 if getattr(reqset, "prepare_files", None): 1335 reqset.add_requirement(ireq) 1336 results = reqset.prepare_files(finder) 1337 result = reqset.requirements 1338 reqset.cleanup_files() 1339 return result 1340 if make_preparer_provider is None: 1341 raise TypeError("Cannot create requirement preparer, cannot resolve!") 1342 1343 preparer_args = { 1344 "build_dir": kwargs["build_dir"], 1345 "src_dir": kwargs["src_dir"], 1346 "download_dir": kwargs["download_dir"], 1347 "wheel_download_dir": wheel_download_dir, 1348 "build_isolation": kwargs["isolated"], 1349 "install_cmd": install_command, 1350 "options": options, 1351 "finder": finder, 1352 "session": session, 1353 "use_user_site": use_user_site, 1354 "require_hashes": require_hashes, 1355 } 1356 if isinstance(req_tracker_provider, (types.FunctionType, functools.partial)): 1357 preparer_args["req_tracker"] = ctx.enter_context(req_tracker_provider()) 1358 resolver_keys = [ 1359 "upgrade_strategy", 1360 "force_reinstall", 1361 "ignore_dependencies", 1362 "ignore_installed", 1363 "use_user_site", 1364 "isolated", 1365 "use_user_site", 1366 ] 1367 resolver_args = {key: kwargs[key] for key in resolver_keys if key in kwargs} 1368 if resolver_provider is None: 1369 raise TypeError("Cannot resolve without a resolver provider... failed!") 1370 preparer = ctx.enter_context(make_preparer_provider(**preparer_args)) 1371 resolver = resolver_provider( 1372 finder=finder, 1373 preparer=preparer, 1374 session=session, 1375 options=options, 1376 install_cmd=install_command, 1377 wheel_cache=wheel_cache, 1378 **resolver_args 1379 ) # type: ignore 1380 resolver.require_hashes = kwargs.get("require_hashes", False) # type: ignore 1381 _, required_resolver_args = get_method_args(resolver.resolve) 1382 resolver_args = [] 1383 if "requirement_set" in required_resolver_args.args: 1384 reqset.add_requirement(ireq) 1385 resolver_args.append(reqset) 1386 elif "root_reqs" in required_resolver_args.args: 1387 resolver_args.append([ireq]) 1388 if "check_supported_wheels" in required_resolver_args.args: 1389 resolver_args.append(check_supported_wheels) 1390 result_reqset = resolver.resolve(*resolver_args) # type: ignore 1391 if result_reqset is None: 1392 result_reqset = reqset 1393 results = result_reqset.requirements 1394 cleanup_fn = getattr(reqset, "cleanup_files", None) 1395 if cleanup_fn is not None: 1396 cleanup_fn() 1397 return results 1398 1399 1400def build_wheel( # noqa:C901 1401 req=None, # type: Optional[TInstallRequirement] 1402 reqset=None, # type: Optional[Union[TReqSet, Iterable[TInstallRequirement]]] 1403 output_dir=None, # type: Optional[str] 1404 preparer=None, # type: Optional[TPreparer] 1405 wheel_cache=None, # type: Optional[TWheelCache] 1406 build_options=None, # type: Optional[List[str]] 1407 global_options=None, # type: Optional[List[str]] 1408 check_binary_allowed=None, # type: Optional[Callable[TInstallRequirement, bool]] 1409 no_clean=False, # type: bool 1410 session=None, # type: Optional[TSession] 1411 finder=None, # type: Optional[TFinder] 1412 install_command=None, # type: Optional[TCommand] 1413 req_tracker=None, # type: Optional[TReqTracker] 1414 build_dir=None, # type: Optional[str] 1415 src_dir=None, # type: Optional[str] 1416 download_dir=None, # type: Optional[str] 1417 wheel_download_dir=None, # type: Optional[str] 1418 cache_dir=None, # type: Optional[str] 1419 use_user_site=False, # type: bool 1420 use_pep517=None, # type: Optional[bool] 1421 format_control_provider=None, # type: Optional[TShimmedFunc] 1422 wheel_cache_provider=None, # type: Optional[TShimmedFunc] 1423 preparer_provider=None, # type: Optional[TShimmedFunc] 1424 wheel_builder_provider=None, # type: Optional[TShimmedFunc] 1425 build_one_provider=None, # type: Optional[TShimmedFunc] 1426 build_one_inside_env_provider=None, # type: Optional[TShimmedFunc] 1427 build_many_provider=None, # type: Optional[TShimmedFunc] 1428 install_command_provider=None, # type: Optional[TShimmedFunc] 1429 finder_provider=None, # type: Optional[TShimmedFunc] 1430 reqset_provider=None, # type: Optional[TShimmedFunc] 1431): 1432 # type: (...) -> Generator[Union[str, Tuple[List[TInstallRequirement], ...]], None, None] 1433 """ 1434 Build a wheel or a set of wheels 1435 1436 :raises TypeError: Raised when no requirements are provided 1437 :param Optional[TInstallRequirement] req: An `InstallRequirement` to build 1438 :param Optional[TReqSet] reqset: A `RequirementSet` instance (`pip<10`) or an 1439 iterable of `InstallRequirement` instances (`pip>=10`) to build 1440 :param Optional[str] output_dir: Target output directory, only useful when building 1441 one wheel using pip>=20.0 1442 :param Optional[TPreparer] preparer: A preparer instance, defaults to None 1443 :param Optional[TWheelCache] wheel_cache: A wheel cache instance, defaults to None 1444 :param Optional[List[str]] build_options: A list of build options to pass in 1445 :param Optional[List[str]] global_options: A list of global options to pass in 1446 :param Optional[Callable[TInstallRequirement, bool]] check_binary_allowed: A callable 1447 to check whether we are allowed to build and cache wheels for an ireq 1448 :param bool no_clean: Whether to avoid cleaning up wheels 1449 :param Optional[TSession] session: A `PipSession` instance to pass to create a 1450 `finder` if necessary 1451 :param Optional[TFinder] finder: A `PackageFinder` instance to use for generating a 1452 `WheelBuilder` instance on `pip<20` 1453 :param Optional[TCommandInstance] install_command: The install command used to 1454 create the finder, session, and options if needed, defaults to None. 1455 :param Optional[TReqTracker] req_tracker: An optional requirement tracker instance, 1456 if one already exists 1457 :param Optional[str] build_dir: Passthrough parameter for building preparer 1458 :param Optional[str] src_dir: Passthrough parameter for building preparer 1459 :param Optional[str] download_dir: Passthrough parameter for building preparer 1460 :param Optional[str] wheel_download_dir: Passthrough parameter for building preparer 1461 :param Optional[str] cache_dir: Passthrough cache directory for wheel cache options 1462 :param bool use_user_site: Whether to use the user site directory when preparing 1463 install requirements on `pip<20` 1464 :param Optional[bool] use_pep517: When set to *True* or *False*, prefers building 1465 with or without pep517 as specified, otherwise uses requirement preference. 1466 Only works for single requirements. 1467 :param Optional[TShimmedFunc] format_control_provider: A provider for the 1468 `FormatControl` class 1469 :param Optional[TShimmedFunc] wheel_cache_provider: A provider for the `WheelCache` 1470 class 1471 :param Optional[TShimmedFunc] preparer_provider: A provider for the 1472 `RequirementPreparer` class 1473 :param Optional[TShimmedFunc] wheel_builder_provider: A provider for the 1474 `WheelBuilder` class, if it exists 1475 :param Optional[TShimmedFunc] build_one_provider: A provider for the `_build_one` 1476 function, if it exists 1477 :param Optional[TShimmedFunc] build_one_inside_env_provider: A provider for the 1478 `_build_one_inside_env` function, if it exists 1479 :param Optional[TShimmedFunc] build_many_provider: A provider for the `build` 1480 function, if it exists 1481 :param Optional[TShimmedFunc] install_command_provider: A shim for providing new 1482 install command instances 1483 :param TShimmedFunc finder_provider: A provider to package finder instances 1484 :param TShimmedFunc reqset_provider: A provider for requirement set generation 1485 :return: A tuple of successful and failed install requirements or else a path to 1486 a wheel 1487 :rtype: Optional[Union[str, Tuple[List[TInstallRequirement], List[TInstallRequirement]]]] 1488 """ 1489 wheel_cache_provider = resolve_possible_shim(wheel_cache_provider) 1490 preparer_provider = resolve_possible_shim(preparer_provider) 1491 wheel_builder_provider = resolve_possible_shim(wheel_builder_provider) 1492 build_one_provider = resolve_possible_shim(build_one_provider) 1493 build_one_inside_env_provider = resolve_possible_shim(build_one_inside_env_provider) 1494 build_many_provider = resolve_possible_shim(build_many_provider) 1495 install_cmd_provider = resolve_possible_shim(install_command_provider) 1496 format_control_provider = resolve_possible_shim(format_control_provider) 1497 finder_provider = resolve_possible_shim(finder_provider) or get_package_finder 1498 reqset_provider = resolve_possible_shim(reqset_provider) 1499 global_options = [] if global_options is None else global_options 1500 build_options = [] if build_options is None else build_options 1501 options = None 1502 kwarg_map = { 1503 "cache_dir": cache_dir, 1504 "src_dir": src_dir, 1505 "download_dir": download_dir, 1506 "wheel_download_dir": wheel_download_dir, 1507 "build_dir": build_dir, 1508 "use_user_site": use_user_site, 1509 } 1510 if not req and not reqset: 1511 raise TypeError("Must provide either a requirement or requirement set to build") 1512 with ExitStack() as ctx: 1513 kwargs = kwarg_map.copy() 1514 if wheel_cache is None and (reqset is not None or output_dir is None): 1515 if install_command is None: 1516 assert isinstance(install_cmd_provider, (type, functools.partial)) 1517 install_command = install_cmd_provider() 1518 kwargs, options = populate_options(install_command, options, **kwarg_map) 1519 format_control = getattr(options, "format_control", None) 1520 if not format_control: 1521 format_control = format_control_provider(None, None) # type: ignore 1522 wheel_cache = ctx.enter_context( 1523 wheel_cache_provider(options.cache_dir, format_control) 1524 ) 1525 if req and not reqset and not output_dir: 1526 output_dir = get_ireq_output_path(wheel_cache, req) 1527 if not reqset and build_one_provider: 1528 yield build_one_provider(req, output_dir, build_options, global_options) 1529 elif build_many_provider: 1530 yield build_many_provider( 1531 reqset, wheel_cache, build_options, global_options, check_binary_allowed 1532 ) 1533 else: 1534 builder_args, builder_kwargs = get_allowed_args(wheel_builder_provider) 1535 if "requirement_set" in builder_args and not reqset: 1536 reqset = reqset_provider() 1537 if session is None and finder is None: 1538 session = get_session(install_cmd=install_command, options=options) 1539 finder = finder_provider( 1540 install_command, options=options, session=session 1541 ) 1542 if preparer is None: 1543 preparer_kwargs = { 1544 "build_dir": kwargs["build_dir"], 1545 "src_dir": kwargs["src_dir"], 1546 "download_dir": kwargs["download_dir"], 1547 "wheel_download_dir": kwargs["wheel_download_dir"], 1548 "finder": finder, 1549 "session": session 1550 if session 1551 else get_session(install_cmd=install_command, options=options), 1552 "install_cmd": install_command, 1553 "options": options, 1554 "use_user_site": use_user_site, 1555 "req_tracker": req_tracker, 1556 } 1557 preparer = ctx.enter_context(preparer_provider(**preparer_kwargs)) 1558 check_bin = check_binary_allowed if check_binary_allowed else lambda x: True 1559 builder_kwargs = { 1560 "requirement_set": reqset, 1561 "finder": finder, 1562 "preparer": preparer, 1563 "wheel_cache": wheel_cache, 1564 "no_clean": no_clean, 1565 "build_options": build_options, 1566 "global_options": global_options, 1567 "check_binary_allowed": check_bin, 1568 } 1569 builder = call_function_with_correct_args( 1570 wheel_builder_provider, **builder_kwargs 1571 ) 1572 if req and not reqset: 1573 if not output_dir: 1574 output_dir = get_ireq_output_path(wheel_cache, req) 1575 if use_pep517 is not None: 1576 req.use_pep517 = use_pep517 1577 yield builder._build_one(req, output_dir) 1578 else: 1579 yield builder.build(reqset) 1580