Source code for pip_shims.compat

# -*- coding=utf-8 -*-
"""
Backports and helper functionality to support using new functionality.
"""
from __future__ import absolute_import, print_function

import atexit
import contextlib
import functools
import inspect
import os
import re
import sys
import types

import six
from packaging import specifiers

from .environment import MYPY_RUNNING
from .utils import (
    call_function_with_correct_args,
    filter_allowed_args,
    get_allowed_args,
    get_method_args,
    nullcontext,
    suppress_setattr,
)

if sys.version_info[:2] < (3, 5):
    from backports.tempfile import TemporaryDirectory
else:
    from tempfile import TemporaryDirectory

if six.PY3:
    from contextlib import ExitStack
else:
    from contextlib2 import ExitStack


if MYPY_RUNNING:
    from optparse import Values
    from requests import Session
    from typing import (
        Any,
        Callable,
        Dict,
        Generator,
        Generic,
        Iterable,
        Iterator,
        List,
        Optional,
        Tuple,
        Type,
        TypeVar,
        Union,
    )
    from .utils import TShimmedPath, TShim, TShimmedFunc

    TFinder = TypeVar("TFinder")
    TResolver = TypeVar("TResolver")
    TReqTracker = TypeVar("TReqTracker")
    TReqSet = TypeVar("TReqSet")
    TLink = TypeVar("TLink")
    TSession = TypeVar("TSession", bound=Session)
    TCommand = TypeVar("TCommand", covariant=True)
    TCommandInstance = TypeVar("TCommandInstance")
    TCmdDict = Dict[str, Union[Tuple[str, str, str], TCommandInstance]]
    TInstallRequirement = TypeVar("TInstallRequirement")
    TFormatControl = TypeVar("TFormatControl")
    TShimmedCmdDict = Union[TShim, TCmdDict]
    TWheelCache = TypeVar("TWheelCache")
    TPreparer = TypeVar("TPreparer")


[docs]class SearchScope(object): def __init__(self, find_links=None, index_urls=None): self.index_urls = index_urls if index_urls else [] self.find_links = find_links
[docs] @classmethod def create(cls, find_links=None, index_urls=None): if not index_urls: index_urls = ["https://pypi.org/simple"] return cls(find_links=find_links, index_urls=index_urls)
[docs]class SelectionPreferences(object): def __init__( self, allow_yanked=True, allow_all_prereleases=False, format_control=None, prefer_binary=False, ignore_requires_python=False, ): self.allow_yanked = allow_yanked self.allow_all_prereleases = allow_all_prereleases self.format_control = format_control self.prefer_binary = prefer_binary self.ignore_requires_python = ignore_requires_python
[docs]class TargetPython(object): fallback_get_tags = None # type: Optional[TShimmedFunc] def __init__( self, platform=None, # type: Optional[str] py_version_info=None, # type: Optional[Tuple[int, ...]] abi=None, # type: Optional[str] implementation=None, # type: Optional[str] ): # type: (...) -> None self._given_py_version_info = py_version_info if py_version_info is None: py_version_info = sys.version_info[:3] elif len(py_version_info) < 3: py_version_info += (3 - len(py_version_info)) * (0,) else: py_version_info = py_version_info[:3] py_version = ".".join(map(str, py_version_info[:2])) self.abi = abi self.implementation = implementation self.platform = platform self.py_version = py_version self.py_version_info = py_version_info self._valid_tags = None
[docs] def get_tags(self): if self._valid_tags is None and self.fallback_get_tags: fallback_func = resolve_possible_shim(self.fallback_get_tags) versions = None if self._given_py_version_info: versions = ["".join(map(str, self._given_py_version_info[:2]))] self._valid_tags = fallback_func( versions=versions, platform=self.platform, abi=self.abi, impl=self.implementation, ) return self._valid_tags
[docs]class CandidatePreferences(object): def __init__(self, prefer_binary=False, allow_all_prereleases=False): self.prefer_binary = prefer_binary self.allow_all_prereleases = allow_all_prereleases
[docs]class LinkCollector(object): def __init__(self, session=None, search_scope=None): self.session = session self.search_scope = search_scope
[docs]class CandidateEvaluator(object):
[docs] @classmethod def create( cls, project_name, # type: str target_python=None, # type: Optional[TargetPython] prefer_binary=False, # type: bool allow_all_prereleases=False, # type: bool specifier=None, # type: Optional[specifiers.BaseSpecifier] hashes=None, # type: Optional[Any] ): if target_python is None: target_python = TargetPython() if specifier is None: specifier = specifiers.SpecifierSet() supported_tags = target_python.get_tags() return cls( project_name=project_name, supported_tags=supported_tags, specifier=specifier, prefer_binary=prefer_binary, allow_all_prereleases=allow_all_prereleases, hashes=hashes, )
def __init__( self, project_name, # type: str supported_tags, # type: List[Any] specifier, # type: specifiers.BaseSpecifier prefer_binary=False, # type: bool allow_all_prereleases=False, # type: bool hashes=None, # type: Optional[Any] ): self._allow_all_prereleases = allow_all_prereleases self._hashes = hashes self._prefer_binary = prefer_binary self._project_name = project_name self._specifier = specifier self._supported_tags = supported_tags
[docs]class LinkEvaluator(object): def __init__( self, allow_yanked, project_name, canonical_name, formats, target_python, ignore_requires_python=False, ignore_compatibility=True, ): self._allow_yanked = allow_yanked self._canonical_name = canonical_name self._ignore_requires_python = ignore_requires_python self._formats = formats self._target_python = target_python self._ignore_compatibility = ignore_compatibility self.project_name = project_name
[docs]class InvalidWheelFilename(Exception): """Wheel Filename is Invalid"""
[docs]class Wheel(object): wheel_file_re = re.compile( r"""^(?P<namever>(?P<name>.+?)-(?P<ver>.*?)) ((-(?P<build>\d[^-]*?))?-(?P<pyver>.+?)-(?P<abi>.+?)-(?P<plat>.+?) \.whl|\.dist-info)$""", re.VERBOSE, ) def __init__(self, filename): # type: (str) -> None wheel_info = self.wheel_file_re.match(filename) if not wheel_info: raise InvalidWheelFilename("%s is not a valid wheel filename." % filename) self.filename = filename self.name = wheel_info.group("name").replace("_", "-") # we'll assume "_" means "-" due to wheel naming scheme # (https://github.com/pypa/pip/issues/1150) self.version = wheel_info.group("ver").replace("_", "-") self.build_tag = wheel_info.group("build") self.pyversions = wheel_info.group("pyver").split(".") self.abis = wheel_info.group("abi").split(".") self.plats = wheel_info.group("plat").split(".") # All the tag combinations from this file self.file_tags = { (x, y, z) for x in self.pyversions for y in self.abis for z in self.plats }
[docs] def get_formatted_file_tags(self): # type: () -> List[str] """ Return the wheel's tags as a sorted list of strings. """ return sorted("-".join(tag) for tag in self.file_tags)
[docs] def support_index_min(self, tags): # type: (List[Any]) -> int """ Return the lowest index that one of the wheel's file_tag combinations achieves in the given list of supported tags. For example, if there are 8 supported tags and one of the file tags is first in the list, then return 0. :param tags: the PEP 425 tags to check the wheel against, in order with most preferred first. :raises ValueError: If none of the wheel's file tags match one of the supported tags. """ return min(tags.index(tag) for tag in self.file_tags if tag in tags)
[docs] def supported(self, tags): # type: (List[Any]) -> bool """ Return whether the wheel is compatible with one of the given tags. :param tags: the PEP 425 tags to check the wheel against. """ return not self.file_tags.isdisjoint(tags)
[docs]def resolve_possible_shim(target): # type: (TShimmedFunc) -> Optional[Union[Type, Callable]] if target is None: return target if getattr(target, "shim", None) and isinstance( target.shim, (types.MethodType, types.FunctionType) ): return target.shim() return target
[docs]@contextlib.contextmanager def temp_environ(): """Allow the ability to set os.environ temporarily""" environ = dict(os.environ) try: yield finally: os.environ.clear() os.environ.update(environ)
[docs]@contextlib.contextmanager def get_requirement_tracker(req_tracker_creator=None): # type: (Optional[Callable]) -> Generator[Optional[TReqTracker], None, None] root = os.environ.get("PIP_REQ_TRACKER") if not req_tracker_creator: yield None else: req_tracker_args = [] _, required_args = get_method_args(req_tracker_creator.__init__) # type: ignore with ExitStack() as ctx: if root is None: root = ctx.enter_context(TemporaryDirectory(prefix="req-tracker")) if root: root = str(root) ctx.enter_context(temp_environ()) os.environ["PIP_REQ_TRACKER"] = root if required_args is not None and "root" in required_args: req_tracker_args.append(root) with req_tracker_creator(*req_tracker_args) as tracker: yield tracker
[docs]@contextlib.contextmanager def ensure_resolution_dirs(**kwargs): # type: (Any) -> Iterator[Dict[str, Any]] """ Ensures that the proper directories are scaffolded and present in the provided kwargs for performing dependency resolution via pip. :return: A new kwargs dictionary with scaffolded directories for **build_dir**, **src_dir**, **download_dir**, and **wheel_download_dir** added to the key value pairs. :rtype: Dict[str, Any] """ keys = ("build_dir", "src_dir", "download_dir", "wheel_download_dir") if not any(kwargs.get(key) is None for key in keys): yield kwargs else: with TemporaryDirectory(prefix="pip-shims-") as base_dir: for key in keys: if kwargs.get(key) is not None: continue target = os.path.join(base_dir, key) os.makedirs(target) kwargs[key] = target yield kwargs
[docs]@contextlib.contextmanager def wheel_cache( cache_dir=None, # type: str format_control=None, # type: Any wheel_cache_provider=None, # type: TShimmedFunc format_control_provider=None, # type: Optional[TShimmedFunc] tempdir_manager_provider=None, # type: TShimmedFunc ): tempdir_manager_provider = resolve_possible_shim(tempdir_manager_provider) wheel_cache_provider = resolve_possible_shim(wheel_cache_provider) format_control_provider = resolve_possible_shim(format_control_provider) if not format_control and not format_control_provider: raise TypeError("Format control or provider needed for wheel cache!") if not format_control: format_control = format_control_provider(None, None) with ExitStack() as ctx: ctx.enter_context(tempdir_manager_provider()) wheel_cache = wheel_cache_provider(cache_dir, format_control) yield wheel_cache
[docs]def partial_command(shimmed_path, cmd_mapping=None): # type: (Type, Optional[TShimmedCmdDict]) -> Union[Type[TCommandInstance], functools.partial] """ Maps a default set of arguments across all members of a :class:`~pip_shims.models.ShimmedPath` instance, specifically for :class:`~pip._internal.command.Command` instances which need `summary` and `name` arguments. :param :class:`~pip_shims.models.ShimmedPath` shimmed_path: A :class:`~pip_shims.models.ShimmedCollection` instance :param Any cmd_mapping: A reference to use for mapping against, e.g. an import that depends on pip also :return: A dictionary mapping new arguments to their default values :rtype: Dict[str, str] """ basecls = shimmed_path.shim() resolved_cmd_mapping = None # type: Optional[Dict[str, Any]] cmd_mapping = resolve_possible_shim(cmd_mapping) if cmd_mapping is not None and isinstance(cmd_mapping, dict): resolved_cmd_mapping = cmd_mapping.copy() base_args = [] # type: List[str] for root_cls in basecls.mro(): if root_cls.__name__ == "Command": _, root_init_args = get_method_args(root_cls.__init__) if root_init_args is not None: base_args = root_init_args.args needs_name_and_summary = any(arg in base_args for arg in ("name", "summary")) if not needs_name_and_summary: basecls.name = shimmed_path.name return basecls elif ( not resolved_cmd_mapping and needs_name_and_summary and getattr(functools, "partialmethod", None) ): new_init = functools.partial( basecls.__init__, name=shimmed_path.name, summary="Summary" ) basecls.__init__ = new_init result = basecls assert resolved_cmd_mapping is not None for command_name, command_info in resolved_cmd_mapping.items(): if getattr(command_info, "class_name", None) == shimmed_path.name: summary = getattr(command_info, "summary", "Command summary") result = functools.partial(basecls, command_name, summary) break return result
[docs]def get_session( install_cmd_provider=None, # type: Optional[TShimmedFunc] install_cmd=None, # type: TCommandInstance options=None, # type: Optional[Values] ): # type: (...) -> TSession session = None # type: Optional[TSession] if install_cmd is None: assert install_cmd_provider is not None install_cmd_provider = resolve_possible_shim(install_cmd_provider) assert isinstance(install_cmd_provider, (type, functools.partial)) install_cmd = install_cmd_provider() if options is None: options, _ = install_cmd.parser.parse_args([]) # type: ignore session = install_cmd._build_session(options) # type: ignore assert session is not None atexit.register(session.close) return session
[docs]def populate_options( install_command=None, # type: TCommandInstance options=None, # type: Optional[Values] **kwargs # type: Any ): # (...) -> Tuple[Dict[str, Any], Values] results = {} if install_command is None and options is None: raise TypeError("Must pass either options or InstallCommand to populate options") if options is None and install_command is not None: options, _ = install_command.parser.parse_args([]) # type: ignore options_dict = options.__dict__ for provided_key, provided_value in kwargs.items(): if provided_key == "isolated": options_key = "isolated_mode" elif provided_key == "source_dir": options_key = "src_dir" else: options_key = provided_key if provided_key in options_dict and provided_value is not None: setattr(options, options_key, provided_value) results[provided_key] = provided_value elif getattr(options, options_key, None) is not None: results[provided_key] = getattr(options, options_key) else: results[provided_key] = provided_value return results, options
[docs]def get_requirement_set( install_command=None, # type: Optional[TCommandInstance] req_set_provider=None, # type: Optional[TShimmedFunc] build_dir=None, # type: Optional[str] src_dir=None, # type: Optional[str] download_dir=None, # type: Optional[str] wheel_download_dir=None, # type: Optional[str] session=None, # type: Optional[TSession] wheel_cache=None, # type: Optional[TWheelCache] upgrade=False, # type: bool upgrade_strategy=None, # type: Optional[str] ignore_installed=False, # type: bool ignore_dependencies=False, # type: bool force_reinstall=False, # type: bool use_user_site=False, # type: bool isolated=False, # type: bool ignore_requires_python=False, # type: bool require_hashes=None, # type: bool cache_dir=None, # type: Optional[str] options=None, # type: Optional[Values] install_cmd_provider=None, # type: Optional[TShimmedFunc] wheel_cache_provider=None, # type: Optional[TShimmedFunc] ): # (...) -> TRequirementSet """ Creates a requirement set from the supplied parameters. Not all parameters are passed through for all pip versions, but any invalid parameters will be ignored if they are not needed to generate a requirement set on the current pip version. :param :class:`~pip_shims.models.ShimmedPathCollection` wheel_cache_provider: A context manager provider which resolves to a `WheelCache` instance :param install_command: A :class:`~pip._internal.commands.install.InstallCommand` instance which is used to generate the finder. :param :class:`~pip_shims.models.ShimmedPathCollection` req_set_provider: A provider to build requirement set instances. :param str build_dir: The directory to build requirements in. Removed in pip 10, defeaults to None :param str source_dir: The directory to use for source requirements. Removed in pip 10, defaults to None :param str download_dir: The directory to download requirement artifacts to. Removed in pip 10, defaults to None :param str wheel_download_dir: The directory to download wheels to. Removed in pip 10, defaults ot None :param :class:`~requests.Session` session: The pip session to use. Removed in pip 10, defaults to None :param WheelCache wheel_cache: The pip WheelCache instance to use for caching wheels. Removed in pip 10, defaults to None :param bool upgrade: Whether to try to upgrade existing requirements. Removed in pip 10, defaults to False. :param str upgrade_strategy: The upgrade strategy to use, e.g. "only-if-needed". Removed in pip 10, defaults to None. :param bool ignore_installed: Whether to ignore installed packages when resolving. Removed in pip 10, defaults to False. :param bool ignore_dependencies: Whether to ignore dependencies of requirements when resolving. Removed in pip 10, defaults to False. :param bool force_reinstall: Whether to force reinstall of packages when resolving. Removed in pip 10, defaults to False. :param bool use_user_site: Whether to use user site packages when resolving. Removed in pip 10, defaults to False. :param bool isolated: Whether to resolve in isolation. Removed in pip 10, defaults to False. :param bool ignore_requires_python: Removed in pip 10, defaults to False. :param bool require_hashes: Whether to require hashes when resolving. Defaults to False. :param Values options: An :class:`~optparse.Values` instance from an install cmd :param install_cmd_provider: A shim for providing new install command instances. :type install_cmd_provider: :class:`~pip_shims.models.ShimmedPathCollection` :return: A new requirement set instance :rtype: :class:`~pip._internal.req.req_set.RequirementSet` """ wheel_cache_provider = resolve_possible_shim(wheel_cache_provider) req_set_provider = resolve_possible_shim(req_set_provider) if install_command is None: install_cmd_provider = resolve_possible_shim(install_cmd_provider) assert isinstance(install_cmd_provider, (type, functools.partial)) install_command = install_cmd_provider() required_args = inspect.getargs( req_set_provider.__init__.__code__ ).args # type: ignore results, options = populate_options( install_command, options, build_dir=build_dir, src_dir=src_dir, download_dir=download_dir, upgrade=upgrade, upgrade_strategy=upgrade_strategy, ignore_installed=ignore_installed, ignore_dependencies=ignore_dependencies, force_reinstall=force_reinstall, use_user_site=use_user_site, isolated=isolated, ignore_requires_python=ignore_requires_python, require_hashes=require_hashes, cache_dir=cache_dir, ) if session is None and "session" in required_args: session = get_session(install_cmd=install_command, options=options) with ExitStack() as stack: if wheel_cache is None: wheel_cache = stack.enter_context(wheel_cache_provider(cache_dir=cache_dir)) results["wheel_cache"] = wheel_cache results["session"] = session results["wheel_download_dir"] = wheel_download_dir return call_function_with_correct_args(req_set_provider, **results)
[docs]def get_package_finder( install_cmd=None, # type: Optional[TCommand] options=None, # type: Optional[Values] session=None, # type: Optional[TSession] platform=None, # type: Optional[str] python_versions=None, # type: Optional[Tuple[str, ...]] abi=None, # type: Optional[str] implementation=None, # type: Optional[str] target_python=None, # type: Optional[Any] ignore_requires_python=None, # type: Optional[bool] target_python_builder=None, # type: Optional[TShimmedFunc] install_cmd_provider=None, # type: Optional[TShimmedFunc] ): # type: (...) -> TFinder """Shim for compatibility to generate package finders. Build and return a :class:`~pip._internal.index.package_finder.PackageFinder` instance using the :class:`~pip._internal.commands.install.InstallCommand` helper method to construct the finder, shimmed with backports as needed for compatibility. :param install_cmd_provider: A shim for providing new install command instances. :type install_cmd_provider: :class:`~pip_shims.models.ShimmedPathCollection` :param install_cmd: A :class:`~pip._internal.commands.install.InstallCommand` instance which is used to generate the finder. :param optparse.Values options: An optional :class:`optparse.Values` instance generated by calling `install_cmd.parser.parse_args()` typically. :param session: An optional session instance, can be created by the `install_cmd`. :param Optional[str] platform: An optional platform string, e.g. linux_x86_64 :param Optional[Tuple[str, ...]] python_versions: A tuple of 2-digit strings representing python versions, e.g. ("27", "35", "36", "37"...) :param Optional[str] abi: The target abi to support, e.g. "cp38" :param Optional[str] implementation: An optional implementation string for limiting searches to a specific implementation, e.g. "cp" or "py" :param target_python: A :class:`~pip._internal.models.target_python.TargetPython` instance (will be translated to alternate arguments if necessary on incompatible pip versions). :param Optional[bool] ignore_requires_python: Whether to ignore `requires_python` on resulting candidates, only valid after pip version 19.3.1 :param target_python_builder: A 'TargetPython' builder (e.g. the class itself, uninstantiated) :return: A :class:`pip._internal.index.package_finder.PackageFinder` instance :rtype: :class:`pip._internal.index.package_finder.PackageFinder` :Example: >>> from pip_shims.shims import InstallCommand, get_package_finder >>> install_cmd = InstallCommand() >>> finder = get_package_finder( ... install_cmd, python_versions=("27", "35", "36", "37", "38"), implementation=" cp" ... ) >>> candidates = finder.find_all_candidates("requests") >>> requests_222 = next(iter(c for c in candidates if c.version.public == "2.22.0")) >>> requests_222 <InstallationCandidate('requests', <Version('2.22.0')>, <Link https://files.pythonhos ted.org/packages/51/bd/23c926cd341ea6b7dd0b2a00aba99ae0f828be89d72b2190f27c11d4b7fb/r equests-2.22.0-py2.py3-none-any.whl#sha256=9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9 a590f48c010551dc6c4b31 (from https://pypi.org/simple/requests/) (requires-python:>=2. 7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*)>)> """ if install_cmd is None: install_cmd_provider = resolve_possible_shim(install_cmd_provider) assert isinstance(install_cmd_provider, (type, functools.partial)) install_cmd = install_cmd_provider() if options is None: options, _ = install_cmd.parser.parse_args([]) # type: ignore if session is None: session = get_session(install_cmd=install_cmd, options=options) # type: ignore builder_args = inspect.getargs( install_cmd._build_package_finder.__code__ ) # type: ignore build_kwargs = {"options": options, "session": session} expects_targetpython = "target_python" in builder_args.args received_python = any(arg for arg in [platform, python_versions, abi, implementation]) if expects_targetpython and received_python and not target_python: if target_python_builder is None: target_python_builder = TargetPython py_version_info = None if python_versions: py_version_info_python = max(python_versions) py_version_info = tuple([int(part) for part in py_version_info_python]) target_python = target_python_builder( platform=platform, abi=abi, implementation=implementation, py_version_info=py_version_info, ) build_kwargs["target_python"] = target_python elif any( arg in builder_args.args for arg in ["platform", "python_versions", "abi", "implementation"] ): if target_python and not received_python: tags = target_python.get_tags() version_impl = {t[0] for t in tags} # impls = set([v[:2] for v in version_impl]) # impls.remove("py") # impl = next(iter(impls), "py") if not target_python versions = {v[2:] for v in version_impl} build_kwargs.update( { "platform": target_python.platform, "python_versions": versions, "abi": target_python.abi, "implementation": target_python.implementation, } ) if ( ignore_requires_python is not None and "ignore_requires_python" in builder_args.args ): build_kwargs["ignore_requires_python"] = ignore_requires_python return install_cmd._build_package_finder(**build_kwargs) # type: ignore
[docs]def shim_unpack( unpack_fn, # type: TShimmedFunc download_dir, # type str tempdir_manager_provider, # type: TShimmedFunc ireq=None, # type: Optional[Any] link=None, # type: Optional[Any] location=None, # type Optional[str], hashes=None, # type: Optional[Any] progress_bar="off", # type: str only_download=None, # type: Optional[bool] downloader_provider=None, # type: Optional[TShimmedFunc] session=None, # type: Optional[Any] ): # (...) -> None """ Accepts all parameters that have been valid to pass to :func:`pip._internal.download.unpack_url` and selects or drops parameters as needed before invoking the provided callable. :param unpack_fn: A callable or shim referring to the pip implementation :type unpack_fn: Callable :param str download_dir: The directory to download the file to :param TShimmedFunc tempdir_manager_provider: A callable or shim referring to `global_tempdir_manager` function from pip or a shimmed no-op context manager :param Optional[:class:`~pip._internal.req.req_install.InstallRequirement`] ireq: an Install Requirement instance, defaults to None :param Optional[:class:`~pip._internal.models.link.Link`] link: A Link instance, defaults to None. :param Optional[str] location: A location or source directory if the target is a VCS url, defaults to None. :param Optional[Any] hashes: A Hashes instance, defaults to None :param str progress_bar: Indicates progress par usage during download, defatuls to off. :param Optional[bool] only_download: Whether to skip install, defaults to None. :param Optional[ShimmedPathCollection] downloader_provider: A downloader class to instantiate, if applicable. :param Optional[`~requests.Session`] session: A PipSession instance, defaults to None. :return: The result of unpacking the url. :rtype: None """ unpack_fn = resolve_possible_shim(unpack_fn) downloader_provider = resolve_possible_shim(downloader_provider) tempdir_manager_provider = resolve_possible_shim(tempdir_manager_provider) required_args = inspect.getargs(unpack_fn.__code__).args # type: ignore unpack_kwargs = {"download_dir": download_dir} with tempdir_manager_provider(): if ireq: if not link and ireq.link: link = ireq.link if only_download is None: only_download = ireq.is_wheel if hashes is None: hashes = ireq.hashes(True) if location is None and getattr(ireq, "source_dir", None): location = ireq.source_dir unpack_kwargs.update({"link": link, "location": location}) if hashes is not None and "hashes" in required_args: unpack_kwargs["hashes"] = hashes if "progress_bar" in required_args: unpack_kwargs["progress_bar"] = progress_bar if only_download is not None and "only_download" in required_args: unpack_kwargs["only_download"] = only_download if session is not None and "session" in required_args: unpack_kwargs["session"] = session if "downloader" in required_args and downloader_provider is not None: assert session is not None assert progress_bar is not None unpack_kwargs["downloader"] = downloader_provider(session, progress_bar) return unpack_fn(**unpack_kwargs) # type: ignore
[docs]def _ensure_finder( finder=None, # type: Optional[TFinder] finder_provider=None, # type: Optional[Callable] install_cmd=None, # type: Optional[TCommandInstance] options=None, # type: Optional[Values] session=None, # type: Optional[TSession] ): if not any([finder, finder_provider, install_cmd]): raise TypeError( "RequirementPreparer requires a packagefinder but no InstallCommand" " was provided to build one and none was passed in." ) if finder is not None: return finder else: if session is None: session = get_session(install_cmd=install_cmd, options=options) if finder_provider is not None and options is not None: finder_provider(options=options, session=session) else: finder = get_package_finder(install_cmd, options=options, session=session) return finder
[docs]@contextlib.contextmanager def make_preparer( preparer_fn, # type: TShimmedFunc req_tracker_fn=None, # type: Optional[TShimmedFunc] build_dir=None, # type: Optional[str] src_dir=None, # type: Optional[str] download_dir=None, # type: Optional[str] wheel_download_dir=None, # type: Optional[str] progress_bar="off", # type: str build_isolation=False, # type: bool session=None, # type: Optional[TSession] finder=None, # type: Optional[TFinder] options=None, # type: Optional[Values] require_hashes=None, # type: Optional[bool] use_user_site=None, # type: Optional[bool] req_tracker=None, # type: Optional[Union[TReqTracker, TShimmedFunc]] install_cmd_provider=None, # type: Optional[TShimmedFunc] downloader_provider=None, # type: Optional[TShimmedFunc] install_cmd=None, # type: Optional[TCommandInstance] finder_provider=None, # type: Optional[TShimmedFunc] ): # (...) -> ContextManager """ Creates a requirement preparer for preparing pip requirements. Provides a compatibilty shim that accepts all previously valid arguments and discards any that are no longer used. :raises TypeError: No requirement tracker provided and one cannot be generated :raises TypeError: No valid sessions provided and one cannot be generated :raises TypeError: No valid finders provided and one cannot be generated :param TShimmedFunc preparer_fn: Callable or shim for generating preparers. :param Optional[TShimmedFunc] req_tracker_fn: Callable or shim for generating requirement trackers, defualts to None :param Optional[str] build_dir: Directory for building packages and wheels, defaults to None :param Optional[str] src_dir: Directory to find or extract source files, defaults to None :param Optional[str] download_dir: Target directory to download files, defaults to None :param Optional[str] wheel_download_dir: Target directoryto download wheels, defaults to None :param str progress_bar: Whether to display a progress bar, defaults to off :param bool build_isolation: Whether to build requirements in isolation, defaults to False :param Optional[TSession] session: Existing session to use for getting requirements, defaults to None :param Optional[TFinder] finder: The package finder to use during resolution, defaults to None :param Optional[Values] options: Pip options to use if needed, defaults to None :param Optional[bool] require_hashes: Whether to require hashes for preparation :param Optional[bool] use_user_site: Whether to use the user site directory for preparing requirements :param Optional[Union[TReqTracker, TShimmedFunc]] req_tracker: The requirement tracker to use for building packages, defaults to None :param Optional[TShimmedFunc] downloader_provider: A downloader provider :param Optional[TCommandInstance] install_cmd: The install command used to create the finder, session, and options if needed, defaults to None :param Optional[TShimmedFunc] finder_provider: A package finder provider :yield: A new requirement preparer instance :rtype: ContextManager[:class:`~pip._internal.operations.prepare.RequirementPreparer`] :Example: >>> from pip_shims.shims import ( ... InstallCommand, get_package_finder, make_preparer, get_requirement_tracker ... ) >>> install_cmd = InstallCommand() >>> pip_options, _ = install_cmd.parser.parse_args([]) >>> session = install_cmd._build_session(pip_options) >>> finder = get_package_finder( ... install_cmd, session=session, options=pip_options ... ) >>> with make_preparer( ... options=pip_options, finder=finder, session=session, install_cmd=ic ... ) as preparer: ... print(preparer) <pip._internal.operations.prepare.RequirementPreparer object at 0x7f8a2734be80> """ preparer_fn = resolve_possible_shim(preparer_fn) downloader_provider = resolve_possible_shim(downloader_provider) finder_provider = resolve_possible_shim(finder_provider) required_args, required_kwargs = get_allowed_args(preparer_fn) # type: ignore if not req_tracker and not req_tracker_fn and "req_tracker" in required_args: raise TypeError("No requirement tracker and no req tracker generator found!") if "downloader" in required_args and not downloader_provider: raise TypeError("no downloader provided, but one is required to continue!") req_tracker_fn = resolve_possible_shim(req_tracker_fn) pip_options_created = options is None session_is_required = "session" in required_args finder_is_required = "finder" in required_args downloader_is_required = "downloader" in required_args options_map = { "src_dir": src_dir, "download_dir": download_dir, "wheel_download_dir": wheel_download_dir, "build_dir": build_dir, "progress_bar": progress_bar, "build_isolation": build_isolation, "require_hashes": require_hashes, "use_user_site": use_user_site, } if install_cmd is None: assert install_cmd_provider is not None install_cmd_provider = resolve_possible_shim(install_cmd_provider) assert isinstance(install_cmd_provider, (type, functools.partial)) install_cmd = install_cmd_provider() preparer_args, options = populate_options(install_cmd, options, **options_map) if options is not None and pip_options_created: for k, v in options_map.items(): suppress_setattr(options, k, v, filter_none=True) if session_is_required: if session is None: session = get_session(install_cmd=install_cmd, options=options) preparer_args["session"] = session if finder_is_required: finder = _ensure_finder( finder=finder, finder_provider=finder_provider, install_cmd=install_cmd, options=options, session=session, ) preparer_args["finder"] = finder if downloader_is_required: preparer_args["downloader"] = downloader_provider(session, progress_bar) req_tracker_fn = nullcontext if not req_tracker_fn else req_tracker_fn with req_tracker_fn() as tracker_ctx: if "req_tracker" in required_args: req_tracker = tracker_ctx if req_tracker is None else req_tracker preparer_args["req_tracker"] = req_tracker preparer_args["lazy_wheel"] = True result = call_function_with_correct_args(preparer_fn, **preparer_args) yield result
[docs]@contextlib.contextmanager def _ensure_wheel_cache( wheel_cache=None, # type: Optional[Type[TWheelCache]] wheel_cache_provider=None, # type: Optional[Callable] format_control=None, # type: Optional[TFormatControl] format_control_provider=None, # type: Optional[Type[TShimmedFunc]] options=None, # type: Optional[Values] cache_dir=None, # type: Optional[str] ): if wheel_cache is not None: yield wheel_cache elif wheel_cache_provider is not None: with ExitStack() as stack: cache_dir = getattr(options, "cache_dir", cache_dir) format_control = getattr( options, "format_control", format_control_provider(None, None), # TFormatControl ) wheel_cache = stack.enter_context( wheel_cache_provider(cache_dir, format_control) ) yield wheel_cache
[docs]def get_ireq_output_path(wheel_cache, ireq): if getattr(wheel_cache, "get_path_for_link", None): return wheel_cache.get_path_for_link(ireq.link) elif getattr(wheel_cache, "cached_wheel", None): return wheel_cache.cached_wheel(ireq.link, ireq.name).url_without_fragment
[docs]def get_resolver( resolver_fn, # type: TShimmedFunc install_req_provider=None, # type: Optional[TShimmedFunc] format_control_provider=None, # type: Optional[TShimmedFunc] wheel_cache_provider=None, # type: Optional[TShimmedFunc] finder=None, # type: Optional[TFinder] upgrade_strategy="to-satisfy-only", # type: str force_reinstall=None, # type: Optional[bool] ignore_dependencies=None, # type: Optional[bool] ignore_requires_python=None, # type: Optional[bool] ignore_installed=True, # type: bool use_user_site=False, # type: bool isolated=None, # type: Optional[bool] wheel_cache=None, # type: Optional[TWheelCache] preparer=None, # type: Optional[TPreparer] session=None, # type: Optional[TSession] options=None, # type: Optional[Values] make_install_req=None, # type: Optional[Callable] install_cmd_provider=None, # type: Optional[TShimmedFunc] install_cmd=None, # type: Optional[TCommandInstance] use_pep517=True, # type: bool ): # (...) -> TResolver """ A resolver creation compatibility shim for generating a resolver. Consumes any argument that was previously used to instantiate a resolver, discards anything that is no longer valid. .. note:: This is only valid for **pip >= 10.0.0** :raises ValueError: A session is required but not provided and one cannot be created :raises ValueError: A finder is required but not provided and one cannot be created :raises ValueError: An install requirement provider is required and has not been provided :param TShimmedFunc resolver_fn: The resolver function used to create new resolver instances. :param TShimmedFunc install_req_provider: The provider function to use to generate install requirements if needed. :param TShimmedFunc format_control_provider: The provider function to use to generate a format_control instance if needed. :param TShimmedFunc wheel_cache_provider: The provider function to use to generate a wheel cache if needed. :param Optional[TFinder] finder: The package finder to use during resolution, defaults to None. :param str upgrade_strategy: Upgrade strategy to use, defaults to ``only-if-needed``. :param Optional[bool] force_reinstall: Whether to simulate or assume package reinstallation during resolution, defaults to None :param Optional[bool] ignore_dependencies: Whether to ignore package dependencies, defaults to None :param Optional[bool] ignore_requires_python: Whether to ignore indicated required_python versions on packages, defaults to None :param bool ignore_installed: Whether to ignore installed packages during resolution, defaults to True :param bool use_user_site: Whether to use the user site location during resolution, defaults to False :param Optional[bool] isolated: Whether to isolate the resolution process, defaults to None :param Optional[TWheelCache] wheel_cache: The wheel cache to use, defaults to None :param Optional[TPreparer] preparer: The requirement preparer to use, defaults to None :param Optional[TSession] session: Existing session to use for getting requirements, defaults to None :param Optional[Values] options: Pip options to use if needed, defaults to None :param Optional[functools.partial] make_install_req: The partial function to pass in to the resolver for actually generating install requirements, if necessary :param Optional[TCommandInstance] install_cmd: The install command used to create the finder, session, and options if needed, defaults to None. :param bool use_pep517: Whether to use the pep517 build process. :return: A new resolver instance. :rtype: :class:`~pip._internal.legacy_resolve.Resolver` :Example: >>> import os >>> from tempdir import TemporaryDirectory >>> from pip_shims.shims import ( ... InstallCommand, get_package_finder, make_preparer, get_requirement_tracker, ... get_resolver, InstallRequirement, RequirementSet ... ) >>> install_cmd = InstallCommand() >>> pip_options, _ = install_cmd.parser.parse_args([]) >>> session = install_cmd._build_session(pip_options) >>> finder = get_package_finder( ... install_cmd, session=session, options=pip_options ... ) >>> wheel_cache = WheelCache(USER_CACHE_DIR, FormatControl(None, None)) >>> with TemporaryDirectory() as temp_base: ... reqset = RequirementSet() ... ireq = InstallRequirement.from_line("requests") ... ireq.is_direct = True ... build_dir = os.path.join(temp_base, "build") ... src_dir = os.path.join(temp_base, "src") ... ireq.build_location(build_dir) ... with make_preparer( ... options=pip_options, finder=finder, session=session, ... build_dir=build_dir, install_cmd=install_cmd, ... ) as preparer: ... resolver = get_resolver( ... finder=finder, ignore_dependencies=False, ignore_requires_python=True, ... preparer=preparer, session=session, options=pip_options, ... install_cmd=install_cmd, wheel_cache=wheel_cache, ... ) ... resolver.require_hashes = False ... reqset.add_requirement(ireq) ... results = resolver.resolve(reqset) ... #reqset.cleanup_files() ... for result_req in reqset.requirements: ... print(result_req) requests chardet certifi urllib3 idna """ resolver_fn = resolve_possible_shim(resolver_fn) install_req_provider = resolve_possible_shim(install_req_provider) format_control_provider = resolve_possible_shim(format_control_provider) wheel_cache_provider = resolve_possible_shim(wheel_cache_provider) install_cmd_provider = resolve_possible_shim(install_cmd_provider) required_args = inspect.getargs(resolver_fn.__init__.__code__).args # type: ignore install_cmd_dependency_map = {"session": session, "finder": finder} resolver_kwargs = {} # type: Dict[str, Any] if install_cmd is None: assert isinstance(install_cmd_provider, (type, functools.partial)) install_cmd = install_cmd_provider() if options is None and install_cmd is not None: options, _ = install_cmd.parser.parse_args([]) # type: ignore for arg, val in install_cmd_dependency_map.items(): if arg not in required_args: continue elif val is None and install_cmd is None: raise TypeError( "Preparer requires a {} but did not receive one " "and cannot generate one".format(arg) ) elif arg == "session" and val is None: val = get_session(install_cmd=install_cmd, options=options) elif arg == "finder" and val is None: val = get_package_finder(install_cmd, options=options, session=session) resolver_kwargs[arg] = val if "make_install_req" in required_args: if make_install_req is None and install_req_provider is not None: make_install_req_kwargs = { "isolated": isolated, "wheel_cache": wheel_cache, "use_pep517": use_pep517, } factory_args, factory_kwargs = filter_allowed_args( install_req_provider, **make_install_req_kwargs ) make_install_req = functools.partial( install_req_provider, *factory_args, **factory_kwargs ) assert make_install_req is not None resolver_kwargs["make_install_req"] = make_install_req if "isolated" in required_args: resolver_kwargs["isolated"] = isolated resolver_kwargs.update( { "upgrade_strategy": upgrade_strategy, "force_reinstall": force_reinstall, "ignore_dependencies": ignore_dependencies, "ignore_requires_python": ignore_requires_python, "ignore_installed": ignore_installed, "use_user_site": use_user_site, "preparer": preparer, } ) if "wheel_cache" in required_args: with _ensure_wheel_cache( wheel_cache=wheel_cache, wheel_cache_provider=wheel_cache_provider, format_control_provider=format_control_provider, options=options, ) as wheel_cache: resolver_kwargs["wheel_cache"] = wheel_cache return resolver_fn(**resolver_kwargs) # type: ignore return resolver_fn(**resolver_kwargs) # type: ignore
[docs]def resolve( # noqa:C901 ireq, # type: TInstallRequirement reqset_provider=None, # type: Optional[TShimmedFunc] req_tracker_provider=None, # type: Optional[TShimmedFunc] install_cmd_provider=None, # type: Optional[TShimmedFunc] install_command=None, # type: Optional[TCommand] finder_provider=None, # type: Optional[TShimmedFunc] resolver_provider=None, # type: Optional[TShimmedFunc] wheel_cache_provider=None, # type: Optional[TShimmedFunc] format_control_provider=None, # type: Optional[TShimmedFunc] make_preparer_provider=None, # type: Optional[TShimmedFunc] tempdir_manager_provider=None, # type: Optional[TShimmedFunc] options=None, # type: Optional[Values] session=None, # type: Optional[TSession] resolver=None, # type: Optional[TResolver] finder=None, # type: Optional[TFinder] upgrade_strategy="to-satisfy-only", # type: str force_reinstall=None, # type: Optional[bool] ignore_dependencies=None, # type: Optional[bool] ignore_requires_python=None, # type: Optional[bool] ignore_installed=True, # type: bool use_user_site=False, # type: bool isolated=None, # type: Optional[bool] build_dir=None, # type: Optional[str] source_dir=None, # type: Optional[str] download_dir=None, # type: Optional[str] cache_dir=None, # type: Optional[str] wheel_download_dir=None, # type: Optional[str] wheel_cache=None, # type: Optional[TWheelCache] require_hashes=None, # type: bool check_supported_wheels=True, # type: bool ): # (...) -> Set[TInstallRequirement] """ Resolves the provided **InstallRequirement**, returning a dictionary. Maps a dictionary of names to corresponding ``InstallRequirement`` values. :param :class:`~pip._internal.req.req_install.InstallRequirement` ireq: An InstallRequirement to initiate the resolution process :param :class:`~pip_shims.models.ShimmedPathCollection` reqset_provider: A provider to build requirement set instances. :param :class:`~pip_shims.models.ShimmedPathCollection` req_tracker_provider: A provider to build requirement tracker instances :param install_cmd_provider: A shim for providing new install command instances. :type install_cmd_provider: :class:`~pip_shims.models.ShimmedPathCollection` :param Optional[TCommandInstance] install_command: The install command used to create the finder, session, and options if needed, defaults to None. :param :class:`~pip_shims.models.ShimmedPathCollection` finder_provider: A provider to package finder instances. :param :class:`~pip_shims.models.ShimmedPathCollection` resolver_provider: A provider to build resolver instances :param TShimmedFunc wheel_cache_provider: The provider function to use to generate a wheel cache if needed. :param TShimmedFunc format_control_provider: The provider function to use to generate a format_control instance if needed. :param TShimmedFunc make_preparer_provider: Callable or shim for generating preparers. :param Optional[TShimmedFunc] tempdir_manager_provider: Shim for generating tempdir manager for pip temporary directories :param Optional[Values] options: Pip options to use if needed, defaults to None :param Optional[TSession] session: Existing session to use for getting requirements, defaults to None :param :class:`~pip._internal.legacy_resolve.Resolver` resolver: A pre-existing resolver instance to use for resolution :param Optional[TFinder] finder: The package finder to use during resolution, defaults to None. :param str upgrade_strategy: Upgrade strategy to use, defaults to ``only-if-needed``. :param Optional[bool] force_reinstall: Whether to simulate or assume package reinstallation during resolution, defaults to None :param Optional[bool] ignore_dependencies: Whether to ignore package dependencies, defaults to None :param Optional[bool] ignore_requires_python: Whether to ignore indicated required_python versions on packages, defaults to None :param bool ignore_installed: Whether to ignore installed packages during resolution, defaults to True :param bool use_user_site: Whether to use the user site location during resolution, defaults to False :param Optional[bool] isolated: Whether to isolate the resolution process, defaults to None :param Optional[str] build_dir: Directory for building packages and wheels, defaults to None :param str source_dir: The directory to use for source requirements. Removed in pip 10, defaults to None :param Optional[str] download_dir: Target directory to download files, defaults to None :param str cache_dir: The cache directory to use for caching artifacts during resolution :param Optional[str] wheel_download_dir: Target directoryto download wheels, defaults to None :param Optional[TWheelCache] wheel_cache: The wheel cache to use, defaults to None :param bool require_hashes: Whether to require hashes when resolving. Defaults to False. :param bool check_supported_wheels: Whether to check support of wheels before including them in resolution. :return: A dictionary mapping requirements to corresponding :class:`~pip._internal.req.req_install.InstallRequirement`s :rtype: :class:`~pip._internal.req.req_install.InstallRequirement` :Example: >>> from pip_shims.shims import resolve, InstallRequirement >>> ireq = InstallRequirement.from_line("requests>=2.20") >>> results = resolve(ireq) >>> for k, v in results.items(): ... print("{0}: {1!r}".format(k, v)) requests: <InstallRequirement object: requests>=2.20 from https://files.pythonhosted. org/packages/51/bd/23c926cd341ea6b7dd0b2a00aba99ae0f828be89d72b2190f27c11d4b7fb/reque sts-2.22.0-py2.py3-none-any.whl#sha256=9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590 f48c010551dc6c4b31 editable=False> idna: <InstallRequirement object: idna<2.9,>=2.5 from https://files.pythonhosted.org/ packages/14/2c/cd551d81dbe15200be1cf41cd03869a46fe7226e7450af7a6545bfc474c9/idna-2.8- py2.py3-none-any.whl#sha256=ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432 f7e4a3c (from requests>=2.20) editable=False> urllib3: <InstallRequirement object: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 from htt ps://files.pythonhosted.org/packages/b4/40/a9837291310ee1ccc242ceb6ebfd9eb21539649f19 3a7c8c86ba15b98539/urllib3-1.25.7-py2.py3-none-any.whl#sha256=a8a318824cc77d1fd4b2bec 2ded92646630d7fe8619497b142c84a9e6f5a7293 (from requests>=2.20) editable=False> chardet: <InstallRequirement object: chardet<3.1.0,>=3.0.2 from https://files.pythonh osted.org/packages/bc/a9/01ffebfb562e4274b6487b4bb1ddec7ca55ec7510b22e4c51f14098443b8 /chardet-3.0.4-py2.py3-none-any.whl#sha256=fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed 4531e3e15460124c106691 (from requests>=2.20) editable=False> certifi: <InstallRequirement object: certifi>=2017.4.17 from https://files.pythonhost ed.org/packages/18/b0/8146a4f8dd402f60744fa380bc73ca47303cccf8b9190fd16a827281eac2/ce rtifi-2019.9.11-py2.py3-none-any.whl#sha256=fd7c7c74727ddcf00e9acd26bba8da604ffec95bf 1c2144e67aff7a8b50e6cef (from requests>=2.20) editable=False> """ reqset_provider = resolve_possible_shim(reqset_provider) finder_provider = resolve_possible_shim(finder_provider) resolver_provider = resolve_possible_shim(resolver_provider) wheel_cache_provider = resolve_possible_shim(wheel_cache_provider) format_control_provider = resolve_possible_shim(format_control_provider) make_preparer_provider = resolve_possible_shim(make_preparer_provider) req_tracker_provider = resolve_possible_shim(req_tracker_provider) install_cmd_provider = resolve_possible_shim(install_cmd_provider) tempdir_manager_provider = resolve_possible_shim(tempdir_manager_provider) if install_command is None: assert isinstance(install_cmd_provider, (type, functools.partial)) install_command = install_cmd_provider() kwarg_map = { "upgrade_strategy": upgrade_strategy, "force_reinstall": force_reinstall, "ignore_dependencies": ignore_dependencies, "ignore_requires_python": ignore_requires_python, "ignore_installed": ignore_installed, "use_user_site": use_user_site, "isolated": isolated, "build_dir": build_dir, "src_dir": source_dir, "download_dir": download_dir, "require_hashes": require_hashes, "cache_dir": cache_dir, } kwargs, options = populate_options(install_command, options, **kwarg_map) with ExitStack() as ctx: ctx.enter_context(tempdir_manager_provider()) kwargs = ctx.enter_context( ensure_resolution_dirs(wheel_download_dir=wheel_download_dir, **kwargs) ) wheel_download_dir = kwargs.pop("wheel_download_dir") if session is None: session = get_session(install_cmd=install_command, options=options) if finder is None: finder = finder_provider( install_command, options=options, session=session ) # type: ignore format_control = getattr(options, "format_control", None) if not format_control: format_control = format_control_provider(None, None) # type: ignore wheel_cache = ctx.enter_context( wheel_cache_provider(kwargs["cache_dir"], format_control) ) # type: ignore ireq.is_direct = True # type: ignore build_location_kwargs = { "build_dir": kwargs["build_dir"], "autodelete": True, "parallel_builds": False } call_function_with_correct_args(ireq.build_location, **build_location_kwargs) if reqset_provider is None: raise TypeError( "cannot resolve without a requirement set provider... failed!" ) reqset = reqset_provider( install_command, options=options, session=session, wheel_download_dir=wheel_download_dir, **kwargs ) # type: ignore if getattr(reqset, "prepare_files", None): reqset.add_requirement(ireq) results = reqset.prepare_files(finder) result = reqset.requirements reqset.cleanup_files() return result if make_preparer_provider is None: raise TypeError("Cannot create requirement preparer, cannot resolve!") preparer_args = { "build_dir": kwargs["build_dir"], "src_dir": kwargs["src_dir"], "download_dir": kwargs["download_dir"], "wheel_download_dir": wheel_download_dir, "build_isolation": kwargs["isolated"], "install_cmd": install_command, "options": options, "finder": finder, "session": session, "use_user_site": use_user_site, "require_hashes": require_hashes, } if isinstance(req_tracker_provider, (types.FunctionType, functools.partial)): preparer_args["req_tracker"] = ctx.enter_context(req_tracker_provider()) resolver_keys = [ "upgrade_strategy", "force_reinstall", "ignore_dependencies", "ignore_installed", "use_user_site", "isolated", "use_user_site", ] resolver_args = {key: kwargs[key] for key in resolver_keys if key in kwargs} if resolver_provider is None: raise TypeError("Cannot resolve without a resolver provider... failed!") preparer = ctx.enter_context(make_preparer_provider(**preparer_args)) resolver = resolver_provider( finder=finder, preparer=preparer, session=session, options=options, install_cmd=install_command, wheel_cache=wheel_cache, **resolver_args ) # type: ignore resolver.require_hashes = kwargs.get("require_hashes", False) # type: ignore _, required_resolver_args = get_method_args(resolver.resolve) resolver_args = [] if "requirement_set" in required_resolver_args.args: reqset.add_requirement(ireq) resolver_args.append(reqset) elif "root_reqs" in required_resolver_args.args: resolver_args.append([ireq]) if "check_supported_wheels" in required_resolver_args.args: resolver_args.append(check_supported_wheels) result_reqset = resolver.resolve(*resolver_args) # type: ignore if result_reqset is None: result_reqset = reqset results = result_reqset.requirements cleanup_fn = getattr(reqset, "cleanup_files", None) if cleanup_fn is not None: cleanup_fn() return results
[docs]def build_wheel( # noqa:C901 req=None, # type: Optional[TInstallRequirement] reqset=None, # type: Optional[Union[TReqSet, Iterable[TInstallRequirement]]] output_dir=None, # type: Optional[str] preparer=None, # type: Optional[TPreparer] wheel_cache=None, # type: Optional[TWheelCache] build_options=None, # type: Optional[List[str]] global_options=None, # type: Optional[List[str]] check_binary_allowed=None, # type: Optional[Callable[TInstallRequirement, bool]] no_clean=False, # type: bool session=None, # type: Optional[TSession] finder=None, # type: Optional[TFinder] install_command=None, # type: Optional[TCommand] req_tracker=None, # type: Optional[TReqTracker] build_dir=None, # type: Optional[str] src_dir=None, # type: Optional[str] download_dir=None, # type: Optional[str] wheel_download_dir=None, # type: Optional[str] cache_dir=None, # type: Optional[str] use_user_site=False, # type: bool use_pep517=None, # type: Optional[bool] format_control_provider=None, # type: Optional[TShimmedFunc] wheel_cache_provider=None, # type: Optional[TShimmedFunc] preparer_provider=None, # type: Optional[TShimmedFunc] wheel_builder_provider=None, # type: Optional[TShimmedFunc] build_one_provider=None, # type: Optional[TShimmedFunc] build_one_inside_env_provider=None, # type: Optional[TShimmedFunc] build_many_provider=None, # type: Optional[TShimmedFunc] install_command_provider=None, # type: Optional[TShimmedFunc] finder_provider=None, # type: Optional[TShimmedFunc] reqset_provider=None, # type: Optional[TShimmedFunc] ): # type: (...) -> Generator[Union[str, Tuple[List[TInstallRequirement], ...]], None, None] """ Build a wheel or a set of wheels :raises TypeError: Raised when no requirements are provided :param Optional[TInstallRequirement] req: An `InstallRequirement` to build :param Optional[TReqSet] reqset: A `RequirementSet` instance (`pip<10`) or an iterable of `InstallRequirement` instances (`pip>=10`) to build :param Optional[str] output_dir: Target output directory, only useful when building one wheel using pip>=20.0 :param Optional[TPreparer] preparer: A preparer instance, defaults to None :param Optional[TWheelCache] wheel_cache: A wheel cache instance, defaults to None :param Optional[List[str]] build_options: A list of build options to pass in :param Optional[List[str]] global_options: A list of global options to pass in :param Optional[Callable[TInstallRequirement, bool]] check_binary_allowed: A callable to check whether we are allowed to build and cache wheels for an ireq :param bool no_clean: Whether to avoid cleaning up wheels :param Optional[TSession] session: A `PipSession` instance to pass to create a `finder` if necessary :param Optional[TFinder] finder: A `PackageFinder` instance to use for generating a `WheelBuilder` instance on `pip<20` :param Optional[TCommandInstance] install_command: The install command used to create the finder, session, and options if needed, defaults to None. :param Optional[TReqTracker] req_tracker: An optional requirement tracker instance, if one already exists :param Optional[str] build_dir: Passthrough parameter for building preparer :param Optional[str] src_dir: Passthrough parameter for building preparer :param Optional[str] download_dir: Passthrough parameter for building preparer :param Optional[str] wheel_download_dir: Passthrough parameter for building preparer :param Optional[str] cache_dir: Passthrough cache directory for wheel cache options :param bool use_user_site: Whether to use the user site directory when preparing install requirements on `pip<20` :param Optional[bool] use_pep517: When set to *True* or *False*, prefers building with or without pep517 as specified, otherwise uses requirement preference. Only works for single requirements. :param Optional[TShimmedFunc] format_control_provider: A provider for the `FormatControl` class :param Optional[TShimmedFunc] wheel_cache_provider: A provider for the `WheelCache` class :param Optional[TShimmedFunc] preparer_provider: A provider for the `RequirementPreparer` class :param Optional[TShimmedFunc] wheel_builder_provider: A provider for the `WheelBuilder` class, if it exists :param Optional[TShimmedFunc] build_one_provider: A provider for the `_build_one` function, if it exists :param Optional[TShimmedFunc] build_one_inside_env_provider: A provider for the `_build_one_inside_env` function, if it exists :param Optional[TShimmedFunc] build_many_provider: A provider for the `build` function, if it exists :param Optional[TShimmedFunc] install_command_provider: A shim for providing new install command instances :param TShimmedFunc finder_provider: A provider to package finder instances :param TShimmedFunc reqset_provider: A provider for requirement set generation :return: A tuple of successful and failed install requirements or else a path to a wheel :rtype: Optional[Union[str, Tuple[List[TInstallRequirement], List[TInstallRequirement]]]] """ wheel_cache_provider = resolve_possible_shim(wheel_cache_provider) preparer_provider = resolve_possible_shim(preparer_provider) wheel_builder_provider = resolve_possible_shim(wheel_builder_provider) build_one_provider = resolve_possible_shim(build_one_provider) build_one_inside_env_provider = resolve_possible_shim(build_one_inside_env_provider) build_many_provider = resolve_possible_shim(build_many_provider) install_cmd_provider = resolve_possible_shim(install_command_provider) format_control_provider = resolve_possible_shim(format_control_provider) finder_provider = resolve_possible_shim(finder_provider) or get_package_finder reqset_provider = resolve_possible_shim(reqset_provider) global_options = [] if global_options is None else global_options build_options = [] if build_options is None else build_options options = None kwarg_map = { "cache_dir": cache_dir, "src_dir": src_dir, "download_dir": download_dir, "wheel_download_dir": wheel_download_dir, "build_dir": build_dir, "use_user_site": use_user_site, } if not req and not reqset: raise TypeError("Must provide either a requirement or requirement set to build") with ExitStack() as ctx: kwargs = kwarg_map.copy() if wheel_cache is None and (reqset is not None or output_dir is None): if install_command is None: assert isinstance(install_cmd_provider, (type, functools.partial)) install_command = install_cmd_provider() kwargs, options = populate_options(install_command, options, **kwarg_map) format_control = getattr(options, "format_control", None) if not format_control: format_control = format_control_provider(None, None) # type: ignore wheel_cache = ctx.enter_context( wheel_cache_provider(options.cache_dir, format_control) ) if req and not reqset and not output_dir: output_dir = get_ireq_output_path(wheel_cache, req) if not reqset and build_one_provider: yield build_one_provider(req, output_dir, build_options, global_options) elif build_many_provider: yield build_many_provider( reqset, wheel_cache, build_options, global_options, check_binary_allowed ) else: builder_args, builder_kwargs = get_allowed_args(wheel_builder_provider) if "requirement_set" in builder_args and not reqset: reqset = reqset_provider() if session is None and finder is None: session = get_session(install_cmd=install_command, options=options) finder = finder_provider( install_command, options=options, session=session ) if preparer is None: preparer_kwargs = { "build_dir": kwargs["build_dir"], "src_dir": kwargs["src_dir"], "download_dir": kwargs["download_dir"], "wheel_download_dir": kwargs["wheel_download_dir"], "finder": finder, "session": session if session else get_session(install_cmd=install_command, options=options), "install_cmd": install_command, "options": options, "use_user_site": use_user_site, "req_tracker": req_tracker, } preparer = ctx.enter_context(preparer_provider(**preparer_kwargs)) check_bin = check_binary_allowed if check_binary_allowed else lambda x: True builder_kwargs = { "requirement_set": reqset, "finder": finder, "preparer": preparer, "wheel_cache": wheel_cache, "no_clean": no_clean, "build_options": build_options, "global_options": global_options, "check_binary_allowed": check_bin, } builder = call_function_with_correct_args( wheel_builder_provider, **builder_kwargs ) if req and not reqset: if not output_dir: output_dir = get_ireq_output_path(wheel_cache, req) if use_pep517 is not None: req.use_pep517 = use_pep517 yield builder._build_one(req, output_dir) else: yield builder.build(reqset)