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