diff --git a/pipenv/vendor/pip_shims/__init__.py b/pipenv/vendor/pip_shims/__init__.py index 93f3a472..7feca147 100644 --- a/pipenv/vendor/pip_shims/__init__.py +++ b/pipenv/vendor/pip_shims/__init__.py @@ -5,7 +5,7 @@ import sys from . import shims -__version__ = "0.4.0" +__version__ = "0.5.1" if "pip_shims" in sys.modules: diff --git a/pipenv/vendor/pip_shims/compat.py b/pipenv/vendor/pip_shims/compat.py new file mode 100644 index 00000000..ed99d970 --- /dev/null +++ b/pipenv/vendor/pip_shims/compat.py @@ -0,0 +1,1511 @@ +# -*- 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, + get_method_args, + nullcontext, + suppress_setattr, +) + +if sys.version_info[:2] < (3, 5): + from pipenv.vendor.vistir.compat import TemporaryDirectory +else: + from tempfile import TemporaryDirectory + +if six.PY3: + from contextlib import ExitStack +else: + from pipenv.vendor.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") + TShimmedCmdDict = Union[TShim, TCmdDict] + TWheelCache = TypeVar("TWheelCache") + TPreparer = TypeVar("TPreparer") + + +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 + + @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) + + +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 + + +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 + + 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 + + +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 + + +class LinkCollector(object): + def __init__(self, session=None, search_scope=None): + self.session = session + self.search_scope = search_scope + + +class CandidateEvaluator(object): + @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 + + +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 + + +class InvalidWheelFilename(Exception): + """Wheel Filename is Invalid""" + + +class Wheel(object): + wheel_file_re = re.compile( + r"""^(?P(?P.+?)-(?P.*?)) + ((-(?P\d[^-]*?))?-(?P.+?)-(?P.+?)-(?P.+?) + \.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 + } + + 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) + + 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) + + 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) + + +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 + + +@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) + + +@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 + + +@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 + + +@contextlib.contextmanager +def wheel_cache( + wheel_cache_provider, # type: TShimmedFunc + tempdir_manager_provider, # type: TShimmedFunc + cache_dir, # type: str + format_control=None, # type: Any + format_control_provider=None, # type: Optional[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 + + +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 + + +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 + + +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 + + +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] +): + # (...) -> 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 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` + """ + 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) + 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) + + +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 + , =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 = set([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 = set([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 + + +def shim_unpack( + unpack_fn, # type: TShimmedFunc + download_dir, # type str + 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 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) + required_args = inspect.getargs(unpack_fn.__code__).args # type: ignore + unpack_kwargs = {"download_dir": download_dir} + 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 + + +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 + + +@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) + + """ + preparer_fn = resolve_possible_shim(preparer_fn) + downloader_provider = resolve_possible_shim(downloader_provider) + finder_provider = resolve_possible_shim(finder_provider) + required_args = inspect.getargs(preparer_fn.__init__.__code__).args # 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 all([session is None, install_cmd is None, session_is_required]): + raise TypeError( + "Preparer requires a session instance which was not supplied and cannot be " + "created without an InstallCommand." + ) + elif all([session is None, session_is_required]): + 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 + + result = call_function_with_correct_args(preparer_fn, **preparer_args) + yield result + + +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] +): + # (...) -> 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. + :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 {0} 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 = functools.partial( + install_req_provider, + isolated=isolated, + wheel_cache=wheel_cache, + # use_pep517=use_pep517, + ) + assert make_install_req is not None + resolver_kwargs["make_install_req"] = make_install_req + if "isolated" in required_args: + resolver_kwargs["isolated"] = isolated + if "wheel_cache" in required_args: + if wheel_cache is None and wheel_cache_provider is not None: + cache_dir = getattr(options, "cache_dir", None) + format_control = getattr( + options, + "format_control", + format_control_provider(None, None), # type: ignore + ) + wheel_cache = wheel_cache_provider(cache_dir, format_control) + resolver_kwargs["wheel_cache"] = wheel_cache + 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, + } + ) + return resolver_fn(**resolver_kwargs) # type: ignore + + +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: =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: =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: =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: =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: =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 = 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} + call_function_with_correct_args(ireq.build_location, **build_location_kwargs) + # ireq.build_location(kwargs["build_dir"]) # type: ignore + 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, + } + # with req_tracker_provider() as req_tracker: + 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 + + +def build_wheel( + 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] +): + # type: (...) -> Optional[Union[str, Tuple[List[TInstallRequirement], List[TInstallRequirement]]]] + """ + 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 + :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 = resolve_possible_shim(preparer) + 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) + 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") + 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 = wheel_cache_provider(options.cache_dir, format_control) + if req and not reqset and not output_dir: + output_dir = wheel_cache.get_path_for_link(req.link) + 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: + with ExitStack() as ctx: + 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 = wheel_cache.get_path_for_link(req.link) + if use_pep517 is not None: + req.use_pep517 = use_pep517 + yield builder._build_one(req, output_dir) + else: + yield builder.build(reqset) diff --git a/pipenv/vendor/pip_shims/environment.py b/pipenv/vendor/pip_shims/environment.py index 1fa7df45..2268ea26 100644 --- a/pipenv/vendor/pip_shims/environment.py +++ b/pipenv/vendor/pip_shims/environment.py @@ -1,4 +1,9 @@ # -*- coding=utf-8 -*- +""" +Module with functionality to learn about the environment. +""" +from __future__ import absolute_import + import importlib import os diff --git a/pipenv/vendor/pip_shims/models.py b/pipenv/vendor/pip_shims/models.py index f3fc0642..d641c6dd 100644 --- a/pipenv/vendor/pip_shims/models.py +++ b/pipenv/vendor/pip_shims/models.py @@ -1,4 +1,7 @@ # -*- coding: utf-8 -*- +""" +Helper module for shimming functionality across pip versions. +""" from __future__ import absolute_import, print_function import collections @@ -12,7 +15,7 @@ import weakref import six -from . import backports +from . import compat from .environment import BASE_IMPORT_PATH, MYPY_RUNNING, get_pip_version from .utils import ( add_mixin_to_class, @@ -801,7 +804,7 @@ ConfigOptionParser.create_path("baseparser.ConfigOptionParser", "7.0.0", "18.0") InstallCommand = ShimmedPathCollection("InstallCommand", ImportTypes.CLASS) InstallCommand.pre_shim( - functools.partial(backports.partial_command, cmd_mapping=commands_dict) + functools.partial(compat.partial_command, cmd_mapping=commands_dict) ) InstallCommand.create_path("commands.install.InstallCommand", "7.0.0", "9999") @@ -911,12 +914,19 @@ is_file_url = ShimmedPathCollection("is_file_url", ImportTypes.FUNCTION) is_file_url.set_default(fallback_is_file_url) is_file_url.create_path("download.is_file_url", "7.0.0", "19.2.3") +Downloader = ShimmedPathCollection("Downloader", ImportTypes.CLASS) +Downloader.create_path("network.download.Downloader", "19.3.9", "9999") + unpack_url = ShimmedPathCollection("unpack_url", ImportTypes.FUNCTION) unpack_url.create_path("download.unpack_url", "7.0.0", "19.3.9") unpack_url.create_path("operations.prepare.unpack_url", "20.0", "9999") shim_unpack = ShimmedPathCollection("shim_unpack", ImportTypes.FUNCTION) -shim_unpack.set_default(functools.partial(backports.shim_unpack, unpack_fn=unpack_url)) +shim_unpack.set_default( + functools.partial( + compat.shim_unpack, unpack_fn=unpack_url, downloader_provider=Downloader + ) +) is_installable_dir = ShimmedPathCollection("is_installable_dir", ImportTypes.FUNCTION) is_installable_dir.create_path("utils.misc.is_installable_dir", "10.0.0", "9999") @@ -930,7 +940,10 @@ Link.create_path("index.Link", "7.0.0", "18.1") make_abstract_dist = ShimmedPathCollection("make_abstract_dist", ImportTypes.FUNCTION) make_abstract_dist.create_path( - "distributions.make_distribution_for_install_requirement", "19.1.2", "9999" + "distributions.make_distribution_for_install_requirement", "20.0.0", "9999" +) +make_abstract_dist.create_path( + "distributions.make_distribution_for_install_requirement", "19.1.2", "19.3.9" ) make_abstract_dist.create_path( "operations.prepare.make_abstract_dist", "10.0.0", "19.1.1" @@ -938,10 +951,13 @@ make_abstract_dist.create_path( make_abstract_dist.create_path("req.req_set.make_abstract_dist", "7.0.0", "9.0.3") make_distribution_for_install_requirement = ShimmedPathCollection( - "make_distribution_for_install_requirement", ImportTypes.CLASS + "make_distribution_for_install_requirement", ImportTypes.FUNCTION ) make_distribution_for_install_requirement.create_path( - "distributions.make_distribution_for_install_requirement", "19.1.2", "9999" + "distributions.make_distribution_for_install_requirement", "20.0.0", "9999" +) +make_distribution_for_install_requirement.create_path( + "distributions.make_distribution_for_install_requirement", "19.1.2", "19.9.9" ) make_option_group = ShimmedPathCollection("make_option_group", ImportTypes.FUNCTION) @@ -953,38 +969,38 @@ PackageFinder.create_path("index.PackageFinder", "7.0.0", "19.9") PackageFinder.create_path("index.package_finder.PackageFinder", "20.0", "9999") CandidateEvaluator = ShimmedPathCollection("CandidateEvaluator", ImportTypes.CLASS) -CandidateEvaluator.set_default(backports.CandidateEvaluator) +CandidateEvaluator.set_default(compat.CandidateEvaluator) CandidateEvaluator.create_path("index.CandidateEvaluator", "19.1.0", "19.3.9") CandidateEvaluator.create_path("index.package_finder.CandidateEvaluator", "20.0", "9999") CandidatePreferences = ShimmedPathCollection("CandidatePreferences", ImportTypes.CLASS) -CandidatePreferences.set_default(backports.CandidatePreferences) +CandidatePreferences.set_default(compat.CandidatePreferences) CandidatePreferences.create_path("index.CandidatePreferences", "19.2.0", "19.9") CandidatePreferences.create_path( "index.package_finder.CandidatePreferences", "20.0", "9999" ) LinkCollector = ShimmedPathCollection("LinkCollector", ImportTypes.CLASS) -LinkCollector.set_default(backports.LinkCollector) +LinkCollector.set_default(compat.LinkCollector) LinkCollector.create_path("collector.LinkCollector", "19.3.0", "19.9") LinkCollector.create_path("index.collector.LinkCollector", "20.0", "9999") LinkEvaluator = ShimmedPathCollection("LinkEvaluator", ImportTypes.CLASS) -LinkEvaluator.set_default(backports.LinkEvaluator) +LinkEvaluator.set_default(compat.LinkEvaluator) LinkEvaluator.create_path("index.LinkEvaluator", "19.2.0", "19.9") LinkEvaluator.create_path("index.package_finder.LinkEvaluator", "20.0", "9999") TargetPython = ShimmedPathCollection("TargetPython", ImportTypes.CLASS) -backports.TargetPython.fallback_get_tags = get_tags -TargetPython.set_default(backports.TargetPython) +compat.TargetPython.fallback_get_tags = get_tags +TargetPython.set_default(compat.TargetPython) TargetPython.create_path("models.target_python.TargetPython", "19.2.0", "9999") SearchScope = ShimmedPathCollection("SearchScope", ImportTypes.CLASS) -SearchScope.set_default(backports.SearchScope) +SearchScope.set_default(compat.SearchScope) SearchScope.create_path("models.search_scope.SearchScope", "19.2.0", "9999") SelectionPreferences = ShimmedPathCollection("SelectionPreferences", ImportTypes.CLASS) -SelectionPreferences.set_default(backports.SelectionPreferences) +SelectionPreferences.set_default(compat.SelectionPreferences) SelectionPreferences.create_path( "models.selection_prefs.SelectionPreferences", "19.2.0", "9999" ) @@ -1013,11 +1029,18 @@ RequirementTracker.create_path("req.req_tracker.RequirementTracker", "7.0.0", "9 TempDirectory = ShimmedPathCollection("TempDirectory", ImportTypes.CLASS) TempDirectory.create_path("utils.temp_dir.TempDirectory", "7.0.0", "9999") +global_tempdir_manager = ShimmedPathCollection( + "global_tempdir_manager", ImportTypes.CONTEXTMANAGER +) +global_tempdir_manager.create_path( + "utils.temp_dir.global_tempdir_manager", "7.0.0", "9999" +) + get_requirement_tracker = ShimmedPathCollection( "get_requirement_tracker", ImportTypes.CONTEXTMANAGER ) get_requirement_tracker.set_default( - functools.partial(backports.get_requirement_tracker, RequirementTracker.shim()) + functools.partial(compat.get_requirement_tracker, RequirementTracker.shim()) ) get_requirement_tracker.create_path( "req.req_tracker.get_requirement_tracker", "7.0.0", "9999" @@ -1025,7 +1048,8 @@ get_requirement_tracker.create_path( Resolver = ShimmedPathCollection("Resolver", ImportTypes.CLASS) Resolver.create_path("resolve.Resolver", "7.0.0", "19.1.1") -Resolver.create_path("legacy_resolve.Resolver", "19.1.2", "9999") +Resolver.create_path("legacy_resolve.Resolver", "19.1.2", "20.0.89999") +Resolver.create_path("resolution.legacy.resolver.Resolver", "20.0.99999", "99999") SafeFileCache = ShimmedPathCollection("SafeFileCache", ImportTypes.CLASS) SafeFileCache.create_path("network.cache.SafeFileCache", "19.3.0", "9999") @@ -1046,7 +1070,8 @@ VcsSupport.create_path("vcs.VcsSupport", "7.0.0", "19.1.1") VcsSupport.create_path("vcs.versioncontrol.VcsSupport", "19.2", "9999") Wheel = ShimmedPathCollection("Wheel", ImportTypes.CLASS) -Wheel.create_path("wheel.Wheel", "7.0.0", "9999") +Wheel.create_path("wheel.Wheel", "7.0.0", "19.3.9") +Wheel.set_default(compat.Wheel) WheelCache = ShimmedPathCollection("WheelCache", ImportTypes.CLASS) WheelCache.create_path("cache.WheelCache", "10.0.0", "9999") @@ -1054,7 +1079,15 @@ WheelCache.create_path("wheel.WheelCache", "7", "9.0.3") WheelBuilder = ShimmedPathCollection("WheelBuilder", ImportTypes.CLASS) WheelBuilder.create_path("wheel.WheelBuilder", "7.0.0", "19.9") -WheelBuilder.create_path("wheel_builder.WheelBuilder", "20.0", "9999") + +build = ShimmedPathCollection("build", ImportTypes.FUNCTION) +build.create_path("wheel_builder.build", "19.9", "9999") + +build_one = ShimmedPathCollection("build_one", ImportTypes.FUNCTION) +build_one.create_path("wheel_builder._build_one", "19.9", "9999") + +build_one_inside_env = ShimmedPathCollection("build_one_inside_env", ImportTypes.FUNCTION) +build_one_inside_env.create_path("wheel_builder._build_one_inside_env", "19.9", "9999") AbstractDistribution = ShimmedPathCollection("AbstractDistribution", ImportTypes.CLASS) AbstractDistribution.create_path( @@ -1075,11 +1108,14 @@ SourceDistribution.create_path( SourceDistribution.create_path( "distributions.source.legacy.SourceDistribution", "19.3.0", "19.9" ) -SourceDistribution.create_path("distributions.source.SourceDistribution", "20.0", "9999") +SourceDistribution.create_path("distributions.sdist.SourceDistribution", "20.0", "9999") WheelDistribution = ShimmedPathCollection("WheelDistribution", ImportTypes.CLASS) WheelDistribution.create_path("distributions.wheel.WheelDistribution", "19.1.2", "9999") +Downloader = ShimmedPathCollection("Downloader", ImportTypes.CLASS) +Downloader.create_path("network.download.Downloader", "20.0.0", "9999") + PyPI = ShimmedPathCollection("PyPI", ImportTypes.ATTRIBUTE) PyPI.create_path("models.index.PyPI", "7.0.0", "9999") @@ -1095,7 +1131,7 @@ DEV_PKGS.set_default({"setuptools", "pip", "distribute", "wheel"}) get_package_finder = ShimmedPathCollection("get_package_finder", ImportTypes.FUNCTION) get_package_finder.set_default( functools.partial( - backports.get_package_finder, + compat.get_package_finder, install_cmd_provider=InstallCommand, target_python_builder=TargetPython.shim(), ) @@ -1105,10 +1141,12 @@ get_package_finder.set_default( make_preparer = ShimmedPathCollection("make_preparer", ImportTypes.FUNCTION) make_preparer.set_default( functools.partial( - backports.make_preparer, + compat.make_preparer, install_cmd_provider=InstallCommand, preparer_fn=RequirementPreparer, + downloader_provider=Downloader, req_tracker_fn=get_requirement_tracker, + finder_provider=get_package_finder, ) ) @@ -1116,7 +1154,7 @@ make_preparer.set_default( get_resolver = ShimmedPathCollection("get_resolver", ImportTypes.FUNCTION) get_resolver.set_default( functools.partial( - backports.get_resolver, + compat.get_resolver, install_cmd_provider=InstallCommand, resolver_fn=Resolver, install_req_provider=install_req_from_req_string, @@ -1129,7 +1167,7 @@ get_resolver.set_default( get_requirement_set = ShimmedPathCollection("get_requirement_set", ImportTypes.FUNCTION) get_requirement_set.set_default( functools.partial( - backports.get_requirement_set, + compat.get_requirement_set, install_cmd_provider=InstallCommand, req_set_provider=RequirementSet, ) @@ -1139,7 +1177,7 @@ get_requirement_set.set_default( resolve = ShimmedPathCollection("resolve", ImportTypes.FUNCTION) resolve.set_default( functools.partial( - backports.resolve, + compat.resolve, install_cmd_provider=InstallCommand, reqset_provider=get_requirement_set, finder_provider=get_package_finder, @@ -1148,5 +1186,22 @@ resolve.set_default( format_control_provider=FormatControl, make_preparer_provider=make_preparer, req_tracker_provider=get_requirement_tracker, + tempdir_manager_provider=global_tempdir_manager, + ) +) + + +build_wheel = ShimmedPathCollection("build_wheel", ImportTypes.FUNCTION) +build_wheel.set_default( + functools.partial( + compat.build_wheel, + install_command_provider=InstallCommand, + wheel_cache_provider=WheelCache, + wheel_builder_provider=WheelBuilder, + build_one_provider=build_one, + build_one_inside_env_provider=build_one_inside_env, + build_many_provider=build, + preparer_provider=make_preparer, + format_control_provider=FormatControl, ) ) diff --git a/pipenv/vendor/pip_shims/shims.py b/pipenv/vendor/pip_shims/shims.py index d5a11f01..fb029378 100644 --- a/pipenv/vendor/pip_shims/shims.py +++ b/pipenv/vendor/pip_shims/shims.py @@ -1,4 +1,7 @@ # -*- coding=utf-8 -*- +""" +Main module with magic self-replacement mechanisms to handle import speedups. +""" from __future__ import absolute_import import sys diff --git a/pipenv/vendor/pip_shims/utils.py b/pipenv/vendor/pip_shims/utils.py index 931ff137..76661ecc 100644 --- a/pipenv/vendor/pip_shims/utils.py +++ b/pipenv/vendor/pip_shims/utils.py @@ -1,4 +1,7 @@ # -*- coding=utf-8 -*- +""" +Shared utility functions which are not specific to any particular module. +""" from __future__ import absolute_import import contextlib diff --git a/pipenv/vendor/pythonfinder/__init__.py b/pipenv/vendor/pythonfinder/__init__.py index 428599bd..6ba8a67d 100644 --- a/pipenv/vendor/pythonfinder/__init__.py +++ b/pipenv/vendor/pythonfinder/__init__.py @@ -10,7 +10,7 @@ from .exceptions import InvalidPythonVersion from .models import SystemPath, WindowsFinder from .pythonfinder import Finder -__version__ = "1.2.2.dev0" +__version__ = "1.2.2" logger = logging.getLogger(__name__) diff --git a/pipenv/vendor/pythonfinder/cli.py b/pipenv/vendor/pythonfinder/cli.py index eb2e603a..fc86abd0 100644 --- a/pipenv/vendor/pythonfinder/cli.py +++ b/pipenv/vendor/pythonfinder/cli.py @@ -1,10 +1,7 @@ # -*- coding=utf-8 -*- from __future__ import absolute_import, print_function, unicode_literals -import sys - import click -import crayons from . import __version__ from .pythonfinder import Finder @@ -32,10 +29,11 @@ def cli( if version: click.echo( "{0} version {1}".format( - crayons.white("PythonFinder", bold=True), crayons.yellow(__version__) + click.style("PythonFinder", fg="white", bold=True), + click.style(str(__version__), fg="yellow") ) ) - sys.exit(0) + ctx.exit() finder = Finder(ignore_unsupported=ignore_unsupported) if findall: versions = [v for v in finder.find_all_python_versions()] @@ -54,7 +52,7 @@ def cli( ), fg="yellow", ) - sys.exit(0) + ctx.exit() else: click.secho( "ERROR: No valid python versions found! Check your path and try again.", @@ -78,22 +76,22 @@ def cli( ), fg="yellow", ) - sys.exit(0) + ctx.exit() else: click.secho("Failed to find matching executable...", fg="yellow") - sys.exit(1) + ctx.exit(1) elif which: found = finder.system_path.which(which.strip()) if found: click.secho("Found Executable: {0}".format(found), fg="white") - sys.exit(0) + ctx.exit() else: click.secho("Failed to find matching executable...", fg="yellow") - sys.exit(1) + ctx.exit(1) else: click.echo("Please provide a command", color="red") - sys.exit(1) - sys.exit() + ctx.exit(1) + ctx.exit() if __name__ == "__main__": diff --git a/pipenv/vendor/pythonfinder/compat.py b/pipenv/vendor/pythonfinder/compat.py new file mode 100644 index 00000000..d76c4efc --- /dev/null +++ b/pipenv/vendor/pythonfinder/compat.py @@ -0,0 +1,42 @@ +# -*- coding=utf-8 -*- +import sys + +import six + +if sys.version_info[:2] <= (3, 4): + from pipenv.vendor.pathlib2 import Path # type: ignore # noqa +else: + from pathlib import Path + +if six.PY3: + from functools import lru_cache + from builtins import TimeoutError +else: + from backports.functools_lru_cache import lru_cache # type: ignore # noqa + + class TimeoutError(OSError): + pass + + +def getpreferredencoding(): + import locale + # Borrowed from Invoke + # (see https://github.com/pyinvoke/invoke/blob/93af29d/invoke/runners.py#L881) + _encoding = locale.getpreferredencoding(False) + if six.PY2 and not sys.platform == "win32": + _default_encoding = locale.getdefaultlocale()[1] + if _default_encoding is not None: + _encoding = _default_encoding + return _encoding + + +DEFAULT_ENCODING = getpreferredencoding() + + +def fs_str(string): + """Encodes a string into the proper filesystem encoding""" + + if isinstance(string, str): + return string + assert not isinstance(string, bytes) + return string.encode(DEFAULT_ENCODING) diff --git a/pipenv/vendor/pythonfinder/models/mixins.py b/pipenv/vendor/pythonfinder/models/mixins.py index 4c473b18..76327115 100644 --- a/pipenv/vendor/pythonfinder/models/mixins.py +++ b/pipenv/vendor/pythonfinder/models/mixins.py @@ -7,8 +7,8 @@ from collections import defaultdict import attr import six -from vistir.compat import fs_str +from ..compat import fs_str from ..environment import MYPY_RUNNING from ..exceptions import InvalidPythonVersion from ..utils import ( @@ -35,7 +35,7 @@ if MYPY_RUNNING: TypeVar, Type, ) - from vistir.compat import Path + from ..compat import Path # noqa BaseFinderType = TypeVar("BaseFinderType") diff --git a/pipenv/vendor/pythonfinder/models/path.py b/pipenv/vendor/pythonfinder/models/path.py index f46677e9..b855a05d 100644 --- a/pipenv/vendor/pythonfinder/models/path.py +++ b/pipenv/vendor/pythonfinder/models/path.py @@ -10,8 +10,7 @@ from itertools import chain import attr import six from cached_property import cached_property -from vistir.compat import Path, fs_str -from vistir.misc import dedup +from ..compat import Path, fs_str from ..environment import ( ASDF_DATA_DIR, @@ -26,6 +25,7 @@ from ..exceptions import InvalidPythonVersion from ..utils import ( Iterable, Sequence, + dedup, ensure_path, expand_paths, filter_pythons, diff --git a/pipenv/vendor/pythonfinder/models/python.py b/pipenv/vendor/pythonfinder/models/python.py index 3c859980..619e7761 100644 --- a/pipenv/vendor/pythonfinder/models/python.py +++ b/pipenv/vendor/pythonfinder/models/python.py @@ -10,8 +10,8 @@ from collections import defaultdict import attr import six from packaging.version import Version -from vistir.compat import Path, lru_cache +from ..compat import Path, lru_cache from ..environment import ASDF_DATA_DIR, MYPY_RUNNING, PYENV_ROOT, SYSTEM_ARCH from ..exceptions import InvalidPythonVersion from ..utils import ( diff --git a/pipenv/vendor/pythonfinder/pythonfinder.py b/pipenv/vendor/pythonfinder/pythonfinder.py index 400a3170..96737355 100644 --- a/pipenv/vendor/pythonfinder/pythonfinder.py +++ b/pipenv/vendor/pythonfinder/pythonfinder.py @@ -7,9 +7,9 @@ import os import six from click import secho -from vistir.compat import lru_cache from . import environment +from .compat import lru_cache from .exceptions import InvalidPythonVersion from .utils import Iterable, filter_pythons, version_re @@ -51,7 +51,8 @@ class Finder(object): :param system: bool, optional :param global_search: Whether to search the global path from os.environ, defaults to True :param global_search: bool, optional - :param ignore_unsupported: Whether to ignore unsupported python versions, if False, an error is raised, defaults to True + :param ignore_unsupported: Whether to ignore unsupported python versions, if False, an + error is raised, defaults to True :param ignore_unsupported: bool, optional :param bool sort_by_path: Whether to always sort by path :returns: a :class:`~pythonfinder.pythonfinder.Finder` object. @@ -133,8 +134,16 @@ class Finder(object): return self.system_path.which(exe) @classmethod - def parse_major(cls, major, minor=None, patch=None, pre=None, dev=None, arch=None): - # type: (Optional[str], Optional[int], Optional[int], Optional[bool], Optional[bool], Optional[str]) -> Dict[str, Union[int, str, bool, None]] + def parse_major( + cls, + major, # type: Optional[str] + minor=None, # type: Optional[int] + patch=None, # type: Optional[int] + pre=None, # type: Optional[bool] + dev=None, # type: Optional[bool] + arch=None, # type: Optional[str] + ): + # type: (...) -> Dict[str, Union[int, str, bool, None]] from .models import PythonVersion major_is_str = major and isinstance(major, six.string_types) @@ -289,11 +298,18 @@ class Finder(object): @lru_cache(maxsize=1024) def find_all_python_versions( - self, major=None, minor=None, patch=None, pre=None, dev=None, arch=None, name=None + self, + major=None, # type: Optional[Union[str, int]] + minor=None, # type: Optional[int] + patch=None, # type: Optional[int] + pre=None, # type: Optional[bool] + dev=None, # type: Optional[bool] + arch=None, # type: Optional[str] + name=None, # type: Optional[str] ): - # type: (Optional[Union[str, int]], Optional[int], Optional[int], Optional[bool], Optional[bool], Optional[str], Optional[str]) -> List[PathEntry] + # type: (...) -> List[PathEntry] version_sort = operator.attrgetter("as_python.version_sort") - python_version_dict = getattr(self.system_path, "python_version_dict") + python_version_dict = getattr(self.system_path, "python_version_dict", {}) if python_version_dict: paths = ( path diff --git a/pipenv/vendor/pythonfinder/utils.py b/pipenv/vendor/pythonfinder/utils.py index 1c190b01..8150545c 100644 --- a/pipenv/vendor/pythonfinder/utils.py +++ b/pipenv/vendor/pythonfinder/utils.py @@ -5,14 +5,16 @@ import io import itertools import os import re +import subprocess +from collections import OrderedDict from fnmatch import fnmatch from threading import Timer import attr import six -import vistir from packaging.version import LegacyVersion, Version +from .compat import Path, lru_cache, TimeoutError # noqa from .environment import MYPY_RUNNING, PYENV_ROOT, SUBPROCESS_TIMEOUT from .exceptions import InvalidPythonVersion @@ -27,11 +29,6 @@ from six.moves import Iterable # type: ignore # noqa # isort:skip from six.moves import Sequence # type: ignore # noqa # isort:skip # fmt: on -try: - from functools import lru_cache -except ImportError: - from backports.functools_lru_cache import lru_cache # type: ignore # noqa - if MYPY_RUNNING: from typing import Any, Union, List, Callable, Set, Tuple, Dict, Optional, Iterator from attr.validators import _OptionalValidator # type: ignore @@ -98,21 +95,26 @@ def get_python_version(path): "-c", "import sys; print('.'.join([str(i) for i in sys.version_info[:3]]))", ] + subprocess_kwargs = { + "env": os.environ.copy(), + "universal_newlines": True, + "stdout": subprocess.PIPE, + "stderr": subprocess.PIPE, + "shell": False, + } + c = subprocess.Popen(version_cmd, **subprocess_kwargs) + timer = Timer(SUBPROCESS_TIMEOUT, c.kill) try: - c = vistir.misc.run( - version_cmd, - block=True, - nospin=True, - return_object=True, - combine_stderr=False, - write_to_stdout=False, - ) - timer = Timer(SUBPROCESS_TIMEOUT, c.kill) + out, _ = c.communicate() + except (SystemExit, KeyboardInterrupt, TimeoutError): + c.terminate() + out, _ = c.communicate() + raise except OSError: raise InvalidPythonVersion("%s is not a valid python path" % path) - if not c.out: + if not out: raise InvalidPythonVersion("%s is not a valid python path" % path) - return c.out.strip() + return out.strip() @lru_cache(maxsize=1024) @@ -190,13 +192,13 @@ def path_is_executable(path): @lru_cache(maxsize=1024) def path_is_known_executable(path): - # type: (vistir.compat.Path) -> bool + # type: (Path) -> bool """ Returns whether a given path is a known executable from known executable extensions or has the executable bit toggled. :param path: The path to the target executable. - :type path: :class:`~vistir.compat.Path` + :type path: :class:`~Path` :return: True if the path has chmod +x, or is a readable, known executable extension. :rtype: bool """ @@ -229,12 +231,12 @@ def looks_like_python(name): @lru_cache(maxsize=1024) def path_is_python(path): - # type: (vistir.compat.Path) -> bool + # type: (Path) -> bool """ Determine whether the supplied path is executable and looks like a possible path to python. :param path: The path to an executable. - :type path: :class:`~vistir.compat.Path` + :type path: :class:`~Path` :return: Whether the provided path is an executable path to python. :rtype: bool """ @@ -278,7 +280,7 @@ def path_is_pythoncore(path): @lru_cache(maxsize=1024) def ensure_path(path): - # type: (Union[vistir.compat.Path, str]) -> vistir.compat.Path + # type: (Union[Path, str]) -> Path """ Given a path (either a string or a Path object), expand variables and return a Path object. @@ -288,9 +290,9 @@ def ensure_path(path): :rtype: :class:`~pathlib.Path` """ - if isinstance(path, vistir.compat.Path): + if isinstance(path, Path): return path - path = vistir.compat.Path(os.path.expandvars(path)) + path = Path(os.path.expandvars(path)) return path.absolute() @@ -313,10 +315,10 @@ def normalize_path(path): @lru_cache(maxsize=1024) def filter_pythons(path): - # type: (Union[str, vistir.compat.Path]) -> Iterable + # type: (Union[str, Path]) -> Iterable """Return all valid pythons in a given path""" - if not isinstance(path, vistir.compat.Path): - path = vistir.compat.Path(str(path)) + if not isinstance(path, Path): + path = Path(str(path)) if not path.is_dir(): return path if path_is_python(path) else None return filter(path_is_python, path.iterdir()) @@ -377,7 +379,7 @@ def split_version_and_name( patch=None, # type: Optional[Union[str, int]] name=None, # type: Optional[str] ): - # type: (...) -> Tuple[Optional[Union[str, int]], Optional[Union[str, int]], Optional[Union[str, int]], Optional[str]] + # type: (...) -> Tuple[Optional[Union[str, int]], Optional[Union[str, int]], Optional[Union[str, int]], Optional[str]] # noqa if isinstance(major, six.string_types) and not minor and not patch: # Only proceed if this is in the format "x.y.z" or similar if major.isdigit() or (major.count(".") > 0 and major[0].isdigit()): @@ -437,3 +439,11 @@ def expand_paths(path, only_python=True): else: if path is not None and path.is_python and path.as_python is not None: yield path + + +def dedup(iterable): + # type: (Iterable) -> Iterable + """Deduplicate an iterable object like iter(set(iterable)) but + order-reserved. + """ + return iter(OrderedDict.fromkeys(iterable)) diff --git a/pipenv/vendor/requirementslib/__init__.py b/pipenv/vendor/requirementslib/__init__.py index 8182d2ea..488da849 100644 --- a/pipenv/vendor/requirementslib/__init__.py +++ b/pipenv/vendor/requirementslib/__init__.py @@ -10,7 +10,7 @@ from .models.lockfile import Lockfile from .models.pipfile import Pipfile from .models.requirements import Requirement -__version__ = "1.5.4.dev0" +__version__ = "1.5.4" logger = logging.getLogger(__name__) diff --git a/pipenv/vendor/requirementslib/models/dependencies.py b/pipenv/vendor/requirementslib/models/dependencies.py index b8af28e9..78c78ace 100644 --- a/pipenv/vendor/requirementslib/models/dependencies.py +++ b/pipenv/vendor/requirementslib/models/dependencies.py @@ -32,6 +32,11 @@ from .utils import ( version_from_ireq, ) +try: + from contextlib import ExitStack +except ImportError: + from contextlib2 import ExitStack + if MYPY_RUNNING: from typing import ( Any, @@ -575,18 +580,22 @@ def start_resolver(finder=None, session=None, wheel_cache=None): _build_dir = create_tracked_tempdir(fs_str("build")) _source_dir = create_tracked_tempdir(fs_str("source")) try: - with pip_shims.shims.make_preparer( - options=pip_options, - finder=finder, - session=session, - build_dir=_build_dir, - src_dir=_source_dir, - download_dir=download_dir, - wheel_download_dir=WHEEL_DOWNLOAD_DIR, - progress_bar="off", - build_isolation=False, - install_cmd=pip_command, - ) as preparer: + with ExitStack() as ctx: + ctx.enter_context(pip_shims.shims.global_tempdir_manager()) + preparer = ctx.enter_context( + pip_shims.shims.make_preparer( + options=pip_options, + finder=finder, + session=session, + build_dir=_build_dir, + src_dir=_source_dir, + download_dir=download_dir, + wheel_download_dir=WHEEL_DOWNLOAD_DIR, + progress_bar="off", + build_isolation=False, + install_cmd=pip_command, + ) + ) resolver = pip_shims.shims.get_resolver( finder=finder, ignore_dependencies=False, diff --git a/pipenv/vendor/requirementslib/models/markers.py b/pipenv/vendor/requirementslib/models/markers.py index 6e46b518..8dda0495 100644 --- a/pipenv/vendor/requirementslib/models/markers.py +++ b/pipenv/vendor/requirementslib/models/markers.py @@ -196,7 +196,6 @@ def _get_specs(specset): return sorted(result, key=operator.itemgetter(1)) -# TODO: Rename this to something meaningful def _group_by_op(specs): # type: (Union[Set[Specifier], SpecifierSet]) -> Iterator specs = [_get_specs(x) for x in list(specs)] @@ -206,7 +205,6 @@ def _group_by_op(specs): return grouping -# TODO: rename this to something meaningful def normalize_specifier_set(specs): # type: (Union[str, SpecifierSet]) -> Optional[Set[Specifier]] """Given a specifier set, a string, or an iterable, normalize the specifiers @@ -237,8 +235,6 @@ def normalize_specifier_set(specs): return normalize_specifier_set(SpecifierSet(",".join(spec_list))) -# TODO: Check if this is used by anything public otherwise make it private -# And rename it to something meaningful def get_sorted_version_string(version_set): # type: (Set[AnyStr]) -> AnyStr version_list = sorted( @@ -248,9 +244,6 @@ def get_sorted_version_string(version_set): return version -# TODO: Rename this to something meaningful -# TODO: Add a deprecation decorator and deprecate this -- i'm sure it's used -# in other libraries @lru_cache(maxsize=1024) def cleanup_pyspecs(specs, joiner="or"): specs = normalize_specifier_set(specs) @@ -295,7 +288,6 @@ def cleanup_pyspecs(specs, joiner="or"): return sorted([(k, v) for k, v in results.items()], key=operator.itemgetter(1)) -# TODO: Rename this to something meaningful @lru_cache(maxsize=1024) def fix_version_tuple(version_tuple): # type: (Tuple[AnyStr, AnyStr]) -> Tuple[AnyStr, AnyStr] @@ -310,7 +302,6 @@ def fix_version_tuple(version_tuple): return (op, version) -# TODO: Rename this to something meaningful, deprecate it (See prior function) @lru_cache(maxsize=128) def get_versions(specset, group_by_operator=True): # type: (Union[Set[Specifier], SpecifierSet], bool) -> List[Tuple[STRING_TYPE, STRING_TYPE]] @@ -599,7 +590,6 @@ def get_specset(marker_list): return specifiers -# TODO: Refactor this (reduce complexity) def parse_marker_dict(marker_dict): op = marker_dict["op"] lhs = marker_dict["lhs"] @@ -709,16 +699,3 @@ def marker_from_specifier(spec): marker_segments.append(format_pyversion(marker_segment)) marker_str = " and ".join(marker_segments).replace('"', "'") return Marker(marker_str) - - -def merge_markers(m1, m2): - # type: (Marker, Marker) -> Optional[Marker] - if not all((m1, m2)): - return next(iter(v for v in (m1, m2) if v), None) - m1 = _ensure_marker(m1) - m2 = _ensure_marker(m2) - _markers = [] # type: List[Marker] - for marker in (m1, m2): - _markers.append(str(marker)) - marker_str = " and ".join([normalize_marker_str(m) for m in _markers if m]) - return _ensure_marker(normalize_marker_str(marker_str)) diff --git a/pipenv/vendor/requirementslib/models/setup_info.py b/pipenv/vendor/requirementslib/models/setup_info.py index 91f28615..38fffd4f 100644 --- a/pipenv/vendor/requirementslib/models/setup_info.py +++ b/pipenv/vendor/requirementslib/models/setup_info.py @@ -19,7 +19,6 @@ import packaging.utils import packaging.version import pep517.envbuild import pep517.wrappers -import pkg_resources.extern.packaging.requirements as pkg_resources_requirements import six from appdirs import user_cache_dir from distlib.wheel import Wheel @@ -43,6 +42,11 @@ from .utils import ( strip_extras_markers_from_requirement, ) +try: + import pkg_resources.extern.packaging.requirements as pkg_resources_requirements +except ImportError: + pkg_resources_requirements = None + try: from setuptools.dist import distutils, Distribution except ImportError: @@ -76,6 +80,7 @@ if MYPY_RUNNING: AnyStr, Sequence, ) + import requests from pip_shims.shims import InstallRequirement, PackageFinder from pkg_resources import ( PathMetadata, @@ -200,7 +205,9 @@ def make_base_requirements(reqs): for req in reqs: if isinstance(req, BaseRequirement): requirements.add(req) - elif isinstance(req, pkg_resources_requirements.Requirement): + elif pkg_resources_requirements is not None and isinstance( + req, pkg_resources_requirements.Requirement + ): requirements.add(BaseRequirement.from_req(req)) elif req and isinstance(req, six.string_types) and not req.startswith("#"): requirements.add(BaseRequirement.from_string(req)) @@ -287,8 +294,11 @@ def get_extras_from_setupcfg(parser): return extras -def parse_setup_cfg(setup_cfg_contents, base_dir): - # type: (S, S) -> Dict[S, Union[S, None, Set[BaseRequirement], List[S], Dict[STRING_TYPE, Tuple[BaseRequirement]]]] +def parse_setup_cfg( + setup_cfg_contents, # type: S + base_dir, # type: S +): + # type: (...) -> Dict[S, Union[S, None, Set[BaseRequirement], List[S], Dict[STRING_TYPE, Tuple[BaseRequirement]]]] default_opts = { "metadata": {"name": "", "version": ""}, "options": { @@ -639,21 +649,42 @@ def get_metadata_from_dist(dist): } -class Analyzer(ast.NodeVisitor): - OP_MAP = { - ast.Add: operator.add, - ast.Sub: operator.sub, - ast.Mult: operator.mul, - ast.Div: operator.floordiv, - ast.Mod: operator.mod, - ast.Pow: operator.pow, - ast.LShift: operator.lshift, - ast.RShift: operator.rshift, - ast.BitAnd: operator.and_, - ast.BitOr: operator.or_, - ast.BitXor: operator.xor - } +AST_BINOP_MAP = dict( + ( + (ast.Add, operator.add), + (ast.Sub, operator.sub), + (ast.Mult, operator.mul), + (ast.Div, operator.floordiv), + (ast.Mod, operator.mod), + (ast.Pow, operator.pow), + (ast.LShift, operator.lshift), + (ast.RShift, operator.rshift), + (ast.BitAnd, operator.and_), + (ast.BitOr, operator.or_), + (ast.BitXor, operator.xor), + ) +) + +AST_COMPARATORS = dict( + ( + (ast.Lt, operator.lt), + (ast.LtE, operator.le), + (ast.Eq, operator.eq), + (ast.Gt, operator.gt), + (ast.GtE, operator.ge), + (ast.NotEq, operator.ne), + (ast.Is, operator.is_), + (ast.IsNot, operator.is_not), + (ast.And, operator.and_), + (ast.Or, operator.or_), + (ast.Not, operator.not_), + (ast.In, operator.contains), + ) +) + + +class Analyzer(ast.NodeVisitor): def __init__(self): self.name_types = [] self.function_map = {} # type: Dict[Any, Any] @@ -677,12 +708,7 @@ class Analyzer(ast.NodeVisitor): super(Analyzer, self).generic_visit(node) def visit_BinOp(self, node): - left = ast_unparse(node.left, initial_mapping=True) - right = ast_unparse(node.right, initial_mapping=True) - op = ast_unparse(node.op, initial_mapping=True) - node.left = left - node.right = right - node.op = op + node = ast_unparse(node, initial_mapping=True) self.binOps.append(node) def unmap_binops(self): @@ -705,6 +731,11 @@ def ast_unparse(item, initial_mapping=False, analyzer=None, recurse=True): # no unparse = partial( ast_unparse, initial_mapping=initial_mapping, analyzer=analyzer, recurse=recurse ) + if getattr(ast, "Constant", None): + constant = (ast.Constant, ast.Ellipsis) + else: + constant = ast.Ellipsis + unparsed = item if isinstance(item, ast.Dict): unparsed = dict(zip(unparse(item.keys), unparse(item.values))) elif isinstance(item, ast.List): @@ -715,37 +746,27 @@ def ast_unparse(item, initial_mapping=False, analyzer=None, recurse=True): # no unparsed = item.s elif isinstance(item, ast.Subscript): unparsed = unparse(item.value) + elif any(isinstance(item, k) for k in AST_BINOP_MAP.keys()): + unparsed = AST_BINOP_MAP[type(item)] + elif isinstance(item, ast.Num): + unparsed = item.n elif isinstance(item, ast.BinOp): if analyzer and item in analyzer.binOps_map: unparsed = analyzer.binOps_map[item] else: right_item = unparse(item.right) left_item = unparse(item.left) - if type(item.op) in Analyzer.OP_MAP: - item.op = Analyzer.OP_MAP[type(item.op)] + op = getattr(item, "op", None) + op_func = unparse(op) if op is not None else op if not initial_mapping: - if not all( - isinstance(side, (six.string_types, int, float, list, tuple)) - for side in (left_item, right_item) - ): - if type(item.op) in Analyzer.OP_MAP: - item = Analyzer.OP_MAP[type(item.op)](left_item, right_item) - else: - item.left = left_item - item.right = right_item - item.op = unparse(item.op) - try: - unparsed = item.op(left_item, right_item) - except Exception: - unparsed = item - else: - if type(item.op) in Analyzer.OP_MAP: - item.op = Analyzer.OP_MAP[type(item.op)] - try: - unparsed = item.op(left_item, right_item) - except Exception: - unparsed = item + try: + unparsed = op_func(left_item, right_item) + except Exception: + unparsed = (left_item, op_func, right_item) else: + item.left = left_item + item.right = right_item + item.op = op_func unparsed = item elif isinstance(item, ast.Name): if not initial_mapping: @@ -763,6 +784,48 @@ def ast_unparse(item, initial_mapping=False, analyzer=None, recurse=True): # no unparsed = item elif six.PY3 and isinstance(item, ast.NameConstant): unparsed = item.value + elif any(isinstance(item, k) for k in AST_COMPARATORS.keys()): + unparsed = AST_COMPARATORS[type(item)] + elif isinstance(item, constant): + unparsed = item.value + elif isinstance(item, ast.Compare): + if isinstance(item.left, ast.Attribute): + import importlib + + left = unparse(item.left) + if "." in left: + name, _, val = left.rpartition(".") + left = getattr(importlib.import_module(name), val, left) + comparators = [] + for comparator in item.comparators: + right = unparse(comparator) + if isinstance(comparator, ast.Attribute) and "." in right: + name, _, val = right.rpartition(".") + right = getattr(importlib.import_module(name), val, right) + comparators.append(right) + unparsed = (left, unparse(item.ops), comparators) + elif isinstance(item, ast.IfExp): + if initial_mapping: + unparsed = item + else: + ops, truth_vals = [], [] + if isinstance(item.test, ast.Compare): + left, ops, right = unparse(item.test) + else: + result = ast_unparse(item.test) + if isinstance(result, dict): + k, v = result.popitem() + if not v: + truth_vals = [False] + for i, op in enumerate(ops): + if i == 0: + truth_vals.append(op(left, right[i])) + else: + truth_vals.append(op(right[i - 1], right[i])) + if all(truth_vals): + unparsed = unparse(item.body) + else: + unparsed = unparse(item.orelse) elif isinstance(item, ast.Attribute): attr_name = getattr(item, "value", None) attr_attr = getattr(item, "attr", None) @@ -791,9 +854,14 @@ def ast_unparse(item, initial_mapping=False, analyzer=None, recurse=True): # no func_name = unparse(item.func) except Exception: func_name = None - if func_name: + if isinstance(func_name, dict): + unparsed.update(func_name) + func_name = next(iter(func_name.keys())) + for keyword in getattr(item, "keywords", []): + unparsed[func_name].update(unparse(keyword)) + elif func_name: unparsed[func_name] = {} - for keyword in item.keywords: + for keyword in getattr(item, "keywords", []): unparsed[func_name].update(unparse(keyword)) elif isinstance(item, ast.keyword): unparsed = {unparse(item.arg): unparse(item.value)} @@ -822,8 +890,6 @@ def ast_unparse(item, initial_mapping=False, analyzer=None, recurse=True): # no unparsed = type(item)([unparse(el) for el in item]) elif isinstance(item, six.string_types): unparsed = item - else: - return item return unparsed @@ -1532,17 +1598,17 @@ build-backend = "{1}" build_location_func(kwargs["build_dir"]) ireq.ensure_has_source_dir(kwargs["src_dir"]) src_dir = ireq.source_dir - - ireq.populate_link(finder, False, False) - pip_shims.shims.shim_unpack( - link=ireq.link, - location=kwargs["src_dir"], - download_dir=download_dir, - only_download=only_download, - session=session, - hashes=ireq.hashes(False), - progress_bar="off", - ) + with pip_shims.shims.global_tempdir_manager(): + ireq.populate_link(finder, False, False) + pip_shims.shims.shim_unpack( + link=ireq.link, + location=kwargs["src_dir"], + download_dir=download_dir, + only_download=only_download, + session=session, + hashes=ireq.hashes(False), + progress_bar="off", + ) created = cls.create(src_dir, subdirectory=subdir, ireq=ireq, kwargs=kwargs) return created diff --git a/pipenv/vendor/requirementslib/models/utils.py b/pipenv/vendor/requirementslib/models/utils.py index 6c3b7de8..9b6beb64 100644 --- a/pipenv/vendor/requirementslib/models/utils.py +++ b/pipenv/vendor/requirementslib/models/utils.py @@ -723,7 +723,7 @@ def get_pinned_version(ireq): except AttributeError: raise TypeError("Expected InstallRequirement, not {}".format(type(ireq).__name__)) - if getattr(ireq, "editable", False): + if ireq.editable: raise ValueError("InstallRequirement is editable") if not specifier: raise ValueError("InstallRequirement has no version specification") diff --git a/pipenv/vendor/requirementslib/models/vcs.py b/pipenv/vendor/requirementslib/models/vcs.py index 447e54e4..2cd62249 100644 --- a/pipenv/vendor/requirementslib/models/vcs.py +++ b/pipenv/vendor/requirementslib/models/vcs.py @@ -61,15 +61,17 @@ class VCSRepository(object): def obtain(self): # type: () -> None - lte_pip_19 = ( - pip_shims.parsed_pip_version.parsed_version < pip_shims.parse_version("19.0") + lt_pip_19_2 = ( + pip_shims.parsed_pip_version.parsed_version < pip_shims.parse_version("19.2") ) + if lt_pip_19_2: + self.repo_backend = self.repo_backend(self.url) if os.path.exists( self.checkout_directory ) and not self.repo_backend.is_repository_directory(self.checkout_directory): self.repo_backend.unpack(self.checkout_directory) elif not os.path.exists(self.checkout_directory): - if lte_pip_19: + if lt_pip_19_2: self.repo_backend.obtain(self.checkout_directory) else: self.repo_backend.obtain(self.checkout_directory, self.parsed_url) diff --git a/pipenv/vendor/vendor.txt b/pipenv/vendor/vendor.txt index 7ce6da70..27caa4d3 100644 --- a/pipenv/vendor/vendor.txt +++ b/pipenv/vendor/vendor.txt @@ -1,45 +1,45 @@ appdirs==1.4.3 backports.shutil_get_terminal_size==1.0.0 backports.weakref==1.0.post1 -click==7.0 +click==7.1.1 click-completion==0.5.2 click-didyoumean==0.0.3 -colorama==0.4.1 +colorama==0.4.3 delegator.py==0.1.1 - pexpect==4.7.0 + pexpect==4.8.0 ptyprocess==0.6.0 python-dotenv==0.10.3 first==2.0.1 iso8601==0.1.12 -jinja2==2.10.3 +jinja2==2.11.1 markupsafe==1.1.1 -parse==1.13.0 +parse==1.15.0 pathlib2==2.3.5 scandir==1.10 pipdeptree==0.13.2 pipreqs==0.4.10 docopt==0.6.2 yarg==0.1.9 -pythonfinder==1.2.1 -requests==2.22.0 +pythonfinder==1.2.2 +requests==2.23.0 chardet==3.0.4 - idna==2.8 - urllib3==1.25.7 + idna==2.9 + urllib3==1.25.8 certifi==2019.11.28 -requirementslib==1.5.3 +requirementslib==1.5.4 attrs==19.3.0 distlib==0.3.0 - packaging==19.2 - pyparsing==2.4.5 + packaging==20.3 + pyparsing==2.4.6 git+https://github.com/sarugaku/plette.git@master#egg=plette tomlkit==0.5.8 -shellingham==1.3.1 -six==1.13.0 +shellingham==1.3.2 +six==1.14.0 semver==2.9.0 toml==0.10.0 cached-property==1.5.1 -vistir==0.4.3 -pip-shims==0.4.0 +vistir==0.5.0 +pip-shims==0.5.1 contextlib2==0.6.0.post1 funcsigs==1.0.2 enum34==1.1.6 @@ -50,7 +50,8 @@ resolvelib==0.2.2 backports.functools_lru_cache==1.5 pep517==0.8.1 zipp==0.6.0 - importlib_metadata==1.3.0 + importlib_metadata==1.5.1 + importlib-resources==1.4.0 more-itertools==5.0.0 git+https://github.com/sarugaku/passa.git@master#egg=passa orderedmultidict==1.0.1 diff --git a/pipenv/vendor/vistir/__init__.py b/pipenv/vendor/vistir/__init__.py index 09af1854..53c1dc43 100644 --- a/pipenv/vendor/vistir/__init__.py +++ b/pipenv/vendor/vistir/__init__.py @@ -36,7 +36,7 @@ from .misc import ( from .path import create_tracked_tempdir, create_tracked_tempfile, mkdir_p, rmtree from .spin import create_spinner -__version__ = "0.4.3" +__version__ = "0.5.1" __all__ = [ diff --git a/pipenv/vendor/vistir/_winconsole.py b/pipenv/vendor/vistir/_winconsole.py index a29c22d8..a8be4772 100644 --- a/pipenv/vendor/vistir/_winconsole.py +++ b/pipenv/vendor/vistir/_winconsole.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# This Module is taken in full from the click project +# This Module is taken in part from the click project and expanded # see https://github.com/pallets/click/blob/6cafd32/click/_winconsole.py # Copyright © 2014 by the Pallets team. diff --git a/pipenv/vendor/vistir/contextmanagers.py b/pipenv/vendor/vistir/contextmanagers.py index 49ec964f..66fde577 100644 --- a/pipenv/vendor/vistir/contextmanagers.py +++ b/pipenv/vendor/vistir/contextmanagers.py @@ -5,7 +5,7 @@ import io import os import stat import sys -from contextlib import contextmanager +from contextlib import closing, contextmanager import six @@ -285,20 +285,27 @@ def open_file(link, session=None, stream=True): # Remote URL headers = {"Accept-Encoding": "identity"} if not session: - from requests import Session - - session = Session() - with session.get(link, headers=headers, stream=stream) as resp: try: - raw = getattr(resp, "raw", None) - result = raw if raw else resp - yield result - finally: - if raw: - conn = getattr(raw, "_connection") - if conn is not None: - conn.close() - result.close() + from requests import Session + except ImportError: + session = None + else: + session = Session() + if session is None: + with closing(six.moves.urllib.request.urlopen(link)) as f: + yield f + else: + with session.get(link, headers=headers, stream=stream) as resp: + try: + raw = getattr(resp, "raw", None) + result = raw if raw else resp + yield result + finally: + if raw: + conn = getattr(raw, "_connection") + if conn is not None: + conn.close() + result.close() @contextmanager diff --git a/pipenv/vendor/vistir/path.py b/pipenv/vendor/vistir/path.py index 2d6e80c6..25d29eb9 100644 --- a/pipenv/vendor/vistir/path.py +++ b/pipenv/vendor/vistir/path.py @@ -30,6 +30,14 @@ from .compat import ( fs_encode, ) +# fmt: off +if six.PY3: + from urllib.parse import quote_from_bytes as quote +else: + from urllib import quote +# fmt: on + + if IS_TYPE_CHECKING: from typing import Optional, Callable, Text, ByteString, AnyStr @@ -158,13 +166,23 @@ def path_to_url(path): >>> path_to_url("/home/user/code/myrepo/myfile.zip") 'file:///home/user/code/myrepo/myfile.zip' """ - from .misc import to_text, to_bytes + from .misc import to_bytes if not path: return path - path = to_bytes(path, encoding="utf-8") - normalized_path = to_text(normalize_drive(os.path.abspath(path)), encoding="utf-8") - return to_text(Path(normalized_path).as_uri(), encoding="utf-8") + normalized_path = Path(normalize_drive(os.path.abspath(path))).as_posix() + if os.name == "nt" and normalized_path[1] == ":": + drive, _, path = normalized_path.partition(":") + # XXX: This enables us to handle half-surrogates that were never + # XXX: actually part of a surrogate pair, but were just incidentally + # XXX: passed in as a piece of a filename + quoted_path = quote(fs_encode(path)) + return fs_decode("file:///{0}:{1}".format(drive, quoted_path)) + # XXX: This is also here to help deal with incidental dangling surrogates + # XXX: on linux, by making sure they are preserved during encoding so that + # XXX: we can urlencode the backslash correctly + bytes_path = to_bytes(normalized_path, errors="backslashreplace") + return fs_decode("file://{0}".format(quote(bytes_path))) def url_to_path(url): @@ -174,7 +192,6 @@ def url_to_path(url): Follows logic taken from pip's equivalent function """ - from .misc import to_bytes assert is_file_url(url), "Only file: urls can be converted to local paths" _, netloc, path, _, _ = urllib_parse.urlsplit(url) @@ -183,7 +200,7 @@ def url_to_path(url): netloc = "\\\\" + netloc path = urllib_request.url2pathname(netloc + path) - return to_bytes(path, encoding="utf-8") + return urllib_parse.unquote(path) def is_valid_url(url): diff --git a/pipenv/vendor/yaspin/spinners.py b/pipenv/vendor/yaspin/spinners.py index 9c3fa7b8..60822a2c 100644 --- a/pipenv/vendor/yaspin/spinners.py +++ b/pipenv/vendor/yaspin/spinners.py @@ -11,10 +11,7 @@ import codecs import os from collections import namedtuple -try: - import simplejson as json -except ImportError: - import json +import json THIS_DIR = os.path.dirname(os.path.realpath(__file__)) diff --git a/tasks/vendoring/__init__.py b/tasks/vendoring/__init__.py index 925d48a9..6c66d008 100644 --- a/tasks/vendoring/__init__.py +++ b/tasks/vendoring/__init__.py @@ -61,7 +61,8 @@ HARDCODED_LICENSE_URLS = { 'distlib': 'https://github.com/vsajip/distlib/raw/master/LICENSE.txt', 'pythonfinder': 'https://raw.githubusercontent.com/techalchemy/pythonfinder/master/LICENSE.txt', 'pyparsing': 'https://raw.githubusercontent.com/pyparsing/pyparsing/master/LICENSE', - 'resolvelib': 'https://raw.githubusercontent.com/sarugaku/resolvelib/master/LICENSE' + 'resolvelib': 'https://raw.githubusercontent.com/sarugaku/resolvelib/master/LICENSE', + 'funcsigs': 'https://raw.githubusercontent.com/aliles/funcsigs/master/LICENSE' } FILE_WHITE_LIST = ( diff --git a/tasks/vendoring/patches/vendor/pip_shims_module_names.patch b/tasks/vendoring/patches/vendor/pip_shims_module_names.patch index dfddacca..f783c96e 100644 --- a/tasks/vendoring/patches/vendor/pip_shims_module_names.patch +++ b/tasks/vendoring/patches/vendor/pip_shims_module_names.patch @@ -2,7 +2,7 @@ diff --git a/pipenv/vendor/pip_shims/__init__.py b/pipenv/vendor/pip_shims/__ini index 2af4166e..598b9ad8 100644 --- a/pipenv/vendor/pip_shims/__init__.py +++ b/pipenv/vendor/pip_shims/__init__.py -@@ -11,10 +11,13 @@ __version__ = "0.4.1.dev0" +@@ -11,10 +11,13 @@ __version__ = "0.5.1" if "pip_shims" in sys.modules: # mainly to keep a reference to the old module on hand so it doesn't get # weakref'd away @@ -18,3 +18,25 @@ index 2af4166e..598b9ad8 100644 module.shims = shims module.__dict__.update( { +diff --git a/pipenv/vendor/pip_shims/compat.py b/../pip-shims/src/pip_shims/compat.py +index ed99d970..63061a6a 100644 +--- a/pipenv/vendor/pip_shims/compat.py ++++ b/../pip-shims/src/pip_shims/compat.py +@@ -25,14 +25,14 @@ from .utils import ( + ) + + if sys.version_info[:2] < (3, 5): +- from backports.tempfile import TemporaryDirectory ++ from pipenv.vendor.vistir.compat import TemporaryDirectory + else: + from tempfile import TemporaryDirectory + + if six.PY3: + from contextlib import ExitStack + else: +- from contextlib2 import ExitStack ++ from pipenv.vendor.contextlib2 import ExitStack + + + if MYPY_RUNNING: + diff --git a/tasks/vendoring/patches/vendor/pythonfinder-pathlib-import.patch b/tasks/vendoring/patches/vendor/pythonfinder-pathlib-import.patch new file mode 100644 index 00000000..89cad037 --- /dev/null +++ b/tasks/vendoring/patches/vendor/pythonfinder-pathlib-import.patch @@ -0,0 +1,13 @@ +diff --git a/pipenv/vendor/pythonfinder/compat.py b/pipenv/vendor/pythonfinder/compat.py +index 6fb4542f..d76c4efc 100644 +--- a/pipenv/vendor/pythonfinder/compat.py ++++ b/pipenv/vendor/pythonfinder/compat.py +@@ -4,7 +4,7 @@ import sys + import six + + if sys.version_info[:2] <= (3, 4): +- from pathlib2 import Path # type: ignore # noqa ++ from pipenv.vendor.pathlib2 import Path # type: ignore # noqa + else: + from pathlib import Path + diff --git a/tasks/vendoring/patches/vendor/yaspin-signal-handling.patch b/tasks/vendoring/patches/vendor/yaspin-signal-handling.patch index 511e782a..c6144f40 100644 --- a/tasks/vendoring/patches/vendor/yaspin-signal-handling.patch +++ b/tasks/vendoring/patches/vendor/yaspin-signal-handling.patch @@ -60,3 +60,19 @@ index d01fb98e..06b8b621 100644 def _clear_line(): - sys.stdout.write("\033[K") + sys.stdout.write(chr(27) + "[K") +diff --git a/pipenv/vendor/yaspin/spinners.py b/pipenv/vendor/yaspin/spinners.py +index 9c3fa7b8..60822a2c 100644 +--- a/pipenv/vendor/yaspin/spinners.py ++++ b/pipenv/vendor/yaspin/spinners.py +@@ -11,10 +11,7 @@ import codecs + import os + from collections import namedtuple + +-try: +- import simplejson as json +-except ImportError: +- import json ++import json + + + THIS_DIR = os.path.dirname(os.path.realpath(__file__))