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