From b3098d24f8f5b41aedf82ed5af35cbfe9527dbd4 Mon Sep 17 00:00:00 2001 From: Dan Ryan Date: Thu, 22 Nov 2018 00:57:48 -0500 Subject: [PATCH] Add updated version of requirementslib Signed-off-by: Dan Ryan --- pipenv/vendor/requirementslib/__init__.py | 2 +- pipenv/vendor/requirementslib/environment.py | 17 +++ .../vendor/requirementslib/models/pipfile.py | 122 ++++++++++++++---- 3 files changed, 118 insertions(+), 23 deletions(-) create mode 100644 pipenv/vendor/requirementslib/environment.py diff --git a/pipenv/vendor/requirementslib/__init__.py b/pipenv/vendor/requirementslib/__init__.py index 32415c61..aca59917 100644 --- a/pipenv/vendor/requirementslib/__init__.py +++ b/pipenv/vendor/requirementslib/__init__.py @@ -1,5 +1,5 @@ # -*- coding=utf-8 -*- -__version__ = '1.3.1' +__version__ = '1.3.2' import logging import warnings diff --git a/pipenv/vendor/requirementslib/environment.py b/pipenv/vendor/requirementslib/environment.py new file mode 100644 index 00000000..2a7d9b0e --- /dev/null +++ b/pipenv/vendor/requirementslib/environment.py @@ -0,0 +1,17 @@ +# -*- coding=utf-8 -*- +from __future__ import print_function, absolute_import + +import os +from appdirs import user_cache_dir + + +def is_type_checking(): + try: + from typing import TYPE_CHECKING + except ImportError: + return False + return TYPE_CHECKING + + +REQUIREMENTSLIB_CACHE_DIR = os.getenv("REQUIREMENTSLIB_CACHE_DIR", user_cache_dir("pipenv")) +MYPY_RUNNING = os.environ.get("MYPY_RUNNING", is_type_checking()) diff --git a/pipenv/vendor/requirementslib/models/pipfile.py b/pipenv/vendor/requirementslib/models/pipfile.py index e3d353d9..2879b654 100644 --- a/pipenv/vendor/requirementslib/models/pipfile.py +++ b/pipenv/vendor/requirementslib/models/pipfile.py @@ -1,22 +1,79 @@ # -*- coding: utf-8 -*- -from __future__ import absolute_import, unicode_literals, print_function +from __future__ import absolute_import, print_function, unicode_literals -import attr import copy import os +import sys +import attr import tomlkit -from vistir.compat import Path, FileNotFoundError - -from .requirements import Requirement -from .project import ProjectFile -from .utils import optional_instance_of -from ..exceptions import RequirementError -from ..utils import is_vcs, is_editable, merge_items +import plette.models.base import plette.pipfiles +from vistir.compat import FileNotFoundError, Path + +from ..exceptions import RequirementError +from ..utils import is_editable, is_vcs, merge_items +from .project import ProjectFile +from .requirements import Requirement +from .utils import optional_instance_of + +from ..environment import MYPY_RUNNING +if MYPY_RUNNING: + from typing import Union, Any, Dict, Iterable, Sequence, Mapping, List, NoReturn + package_type = Dict[str, Dict[str, Union[List[str], str]]] + source_type = Dict[str, Union[str, bool]] + sources_type = Iterable[source_type] + meta_type = Dict[str, Union[int, Dict[str, str], sources_type]] + lockfile_type = Dict[str, Union[package_type, meta_type]] + + +# Let's start by patching plette to make sure we can validate data without being broken +try: + import cerberus +except ImportError: + cerberus = None + +VALIDATORS = plette.models.base.VALIDATORS + +def patch_plette(): + # type: () -> NoReturn + names = ["plette.models.base", plette.models.base.__name__] + names = [name for name in names if name in sys.modules] + for name in names: + if name in sys.modules: + module = sys.modules[name] + else: + module = plette.models.base + original_fn = getattr(module, "validate") + for key in ["__qualname__", "__name__", "__module__"]: + original_val = getattr(original_fn, key, None) + if original_val is not None: + setattr(validate, key, original_val) + setattr(module, "validate", validate) + sys.modules[name] = module + + +def patch_plette(): + # type: () -> NoReturn + names = ["plette.models.base", plette.models.base.__name__] + names = [name for name in names if name in sys.modules] + for name in names: + if name in sys.modules: + module = sys.modules[name] + else: + module = plette.models.base + original_fn = getattr(module, "validate") + for key in ["__qualname__", "__name__", "__module__"]: + setattr(validate, key, getattr(original_fn, key)) + setattr(module, "validate", validate) + sys.modules[name] = module + + +patch_plette() + is_pipfile = optional_instance_of(plette.pipfiles.Pipfile) is_path = optional_instance_of(Path) @@ -24,8 +81,10 @@ is_projectfile = optional_instance_of(ProjectFile) def reorder_source_keys(data): - for i, entry in enumerate(data["source"]): - table = tomlkit.table() + # type: ignore + sources = data["source"] # type: sources_type + for i, entry in enumerate(sources): + table = tomlkit.table() # type: Mapping table["name"] = entry["name"] table["url"] = entry["url"] table["verify_ssl"] = entry["verify_ssl"] @@ -36,6 +95,7 @@ def reorder_source_keys(data): class PipfileLoader(plette.pipfiles.Pipfile): @classmethod def validate(cls, data): + # type: (Dict[str, Any]) -> None for key, klass in plette.pipfiles.PIPFILE_SECTIONS.items(): if key not in data or key == "source": continue @@ -46,6 +106,7 @@ class PipfileLoader(plette.pipfiles.Pipfile): @classmethod def load(cls, f, encoding=None): + # type: (Any, str) -> PipfileLoader content = f.read() if encoding is not None: content = content.decode(encoding) @@ -69,6 +130,7 @@ class PipfileLoader(plette.pipfiles.Pipfile): return instance def __getattribute__(self, key): + # type: (str) -> Any if key == "source": return self._data[key] return super(PipfileLoader, self).__getattribute__(key) @@ -78,7 +140,7 @@ class PipfileLoader(plette.pipfiles.Pipfile): class Pipfile(object): path = attr.ib(validator=is_path, type=Path) projectfile = attr.ib(validator=is_projectfile, type=ProjectFile) - _pipfile = attr.ib(type=plette.pipfiles.Pipfile) + _pipfile = attr.ib(type=PipfileLoader) _pyproject = attr.ib(default=attr.Factory(tomlkit.document), type=tomlkit.toml_document.TOMLDocument) build_system = attr.ib(default=attr.Factory(dict), type=dict) requirements = attr.ib(default=attr.Factory(list), type=list) @@ -86,22 +148,27 @@ class Pipfile(object): @path.default def _get_path(self): + # type: () -> Path return Path(os.curdir).absolute() @projectfile.default def _get_projectfile(self): + # type: () -> ProjectFile return self.load_projectfile(os.curdir, create=False) @_pipfile.default def _get_pipfile(self): + # type: () -> Union[plette.pipfiles.Pipfile, PipfileLoader] return self.projectfile.model @property def pipfile(self): + # type: () -> Union[PipfileLoader, plette.pipfiles.Pipfile] return self._pipfile def get_deps(self, dev=False, only=True): - deps = {} + # type: (bool, bool) -> Dict[str, Dict[str, Union[List[str], str]]] + deps = {} # type: Dict[str, Dict[str, Union[List[str], str]]] if dev: deps.update(self.pipfile._data["dev-packages"]) if only: @@ -109,15 +176,18 @@ class Pipfile(object): return merge_items([deps, self.pipfile._data["packages"]]) def get(self, k): + # type: (str) -> Any return self.__getitem__(k) def __contains__(self, k): + # type: (str) -> bool check_pipfile = k in self.extended_keys or self.pipfile.__contains__(k) if check_pipfile: return True - return super(Pipfile, self).__contains__(k) + return False def __getitem__(self, k, *args, **kwargs): + # type: ignore retval = None pipfile = self._pipfile section = None @@ -139,6 +209,7 @@ class Pipfile(object): return retval def __getattr__(self, k, *args, **kwargs): + # type: ignore retval = None pipfile = super(Pipfile, self).__getattribute__("_pipfile") try: @@ -151,14 +222,17 @@ class Pipfile(object): @property def requires_python(self): + # type: () -> bool return self._pipfile.requires.requires_python @property def allow_prereleases(self): + # type: () -> bool return self._pipfile.get("pipenv", {}).get("allow_prereleases", False) @classmethod def read_projectfile(cls, path): + # type: (str) -> ProjectFile """Read the specified project file and provide an interface for writing/updating. :param str path: Path to the target file. @@ -174,6 +248,7 @@ class Pipfile(object): @classmethod def load_projectfile(cls, path, create=False): + # type: (str, bool) -> ProjectFile """Given a path, load or create the necessary pipfile. :param str path: Path to the project root or pipfile @@ -198,6 +273,7 @@ class Pipfile(object): @classmethod def load(cls, path, create=False): + # type: (str, bool) -> Pipfile """Given a path, load or create the necessary pipfile. :param str path: Path to the project root or pipfile @@ -226,22 +302,22 @@ class Pipfile(object): return cls(**creation_args) def write(self): + # type: () -> None self.projectfile.model = copy.deepcopy(self._pipfile) self.projectfile.write() @property - def dev_packages(self, as_requirements=True): - if as_requirements: - return self.dev_requirements - return self._pipfile.get('dev-packages', {}) + def dev_packages(self): + # type: () -> List[Requirement] + return self.dev_requirements @property - def packages(self, as_requirements=True): - if as_requirements: - return self.requirements - return self._pipfile.get('packages', {}) + def packages(self): + # type: () -> List[Requirement] + return self.requirements def _read_pyproject(self): + # type: () -> None pyproject = self.path.parent.joinpath("pyproject.toml") if pyproject.exists(): self._pyproject = tomlkit.load(pyproject) @@ -256,8 +332,10 @@ class Pipfile(object): @property def build_requires(self): + # type: () -> List[str] return self.build_system.get("requires", []) @property def build_backend(self): + # type: () -> str return self.build_system.get("build-backend", None)