From 00dd84537244262e98db1fa45319d33254f383e7 Mon Sep 17 00:00:00 2001 From: Dan Ryan Date: Mon, 23 Jul 2018 12:38:50 -0400 Subject: [PATCH 1/8] Enable parsing of dependency links in setup.py - Fixed errors with url parsing during hashing Signed-off-by: Dan Ryan --- news/2434.bugfix | 1 + pipenv/patched/piptools/repositories/pypi.py | 14 ++++--- .../vendoring/patches/patched/piptools.patch | 38 +++++++++++-------- 3 files changed, 33 insertions(+), 20 deletions(-) create mode 100644 news/2434.bugfix diff --git a/news/2434.bugfix b/news/2434.bugfix new file mode 100644 index 0000000000..0a9603e102 --- /dev/null +++ b/news/2434.bugfix @@ -0,0 +1 @@ +Fixed the ability of pipenv to parse ``dependency_links`` from ``setup.py`` when ``PIP_PROCESS_DEPENDENCY_LINKS`` is enabled. diff --git a/pipenv/patched/piptools/repositories/pypi.py b/pipenv/patched/piptools/repositories/pypi.py index f09ff372e1..2f746094be 100644 --- a/pipenv/patched/piptools/repositories/pypi.py +++ b/pipenv/patched/piptools/repositories/pypi.py @@ -1,7 +1,7 @@ # coding: utf-8 from __future__ import (absolute_import, division, print_function, unicode_literals) - +import copy import hashlib import os import sys @@ -64,15 +64,19 @@ def __init__(self, *args, **kwargs): def get_hash(self, location): # if there is no location hash (i.e., md5 / sha256 / etc) we on't want to store it hash_value = None - can_hash = location.hash + vcs_uris = ('git+', 'bzr+', 'hg+', 'svn+') + new_location = copy.deepcopy(location) + if any(new_location.url.startswith(vcs) for vcs in vcs_uris): + new_location.url = new_location.url.split("+", 1)[-1] + can_hash = new_location.hash if can_hash: # hash url WITH fragment - hash_value = self.get(location.url) + hash_value = self.get(new_location.url) if not hash_value: - hash_value = self._get_file_hash(location) + hash_value = self._get_file_hash(new_location) hash_value = hash_value.encode('utf8') if can_hash: - self.set(location.url, hash_value) + self.set(new_location.url, hash_value) return hash_value.decode('utf8') def _get_file_hash(self, location): diff --git a/tasks/vendoring/patches/patched/piptools.patch b/tasks/vendoring/patches/patched/piptools.patch index f5fb822f4a..56696e0889 100644 --- a/tasks/vendoring/patches/patched/piptools.patch +++ b/tasks/vendoring/patches/patched/piptools.patch @@ -19,11 +19,15 @@ index 4e6174c..75f9b49 100644 # NOTE # We used to store the cache dir under ~/.pip-tools, which is not the diff --git a/pipenv/patched/piptools/repositories/pypi.py b/pipenv/patched/piptools/repositories/pypi.py -index 1c4b943..c922be1 100644 +index 1c4b943..245e9ce 100644 --- a/pipenv/patched/piptools/repositories/pypi.py +++ b/pipenv/patched/piptools/repositories/pypi.py -@@ -4,6 +4,7 @@ from __future__ import (absolute_import, division, print_function, - +@@ -1,9 +1,10 @@ + # coding: utf-8 + from __future__ import (absolute_import, division, print_function, + unicode_literals) +- ++import copy import hashlib import os +import sys @@ -58,7 +62,7 @@ index 1c4b943..c922be1 100644 from .base import BaseRepository -@@ -37,6 +49,40 @@ except ImportError: +@@ -37,6 +49,44 @@ except ImportError: from pip.wheel import WheelCache @@ -77,15 +81,19 @@ index 1c4b943..c922be1 100644 + def get_hash(self, location): + # if there is no location hash (i.e., md5 / sha256 / etc) we on't want to store it + hash_value = None -+ can_hash = location.hash ++ vcs_uris = ('git+', 'bzr+', 'hg+', 'svn+') ++ new_location = copy.deepcopy(location) ++ if any(new_location.url.startswith(vcs) for vcs in vcs_uris): ++ new_location.url = new_location.url.split("+", 1)[-1] ++ can_hash = new_location.hash + if can_hash: + # hash url WITH fragment -+ hash_value = self.get(location.url) ++ hash_value = self.get(new_location.url) + if not hash_value: -+ hash_value = self._get_file_hash(location) ++ hash_value = self._get_file_hash(new_location) + hash_value = hash_value.encode('utf8') + if can_hash: -+ self.set(location.url, hash_value) ++ self.set(new_location.url, hash_value) + return hash_value.decode('utf8') + + def _get_file_hash(self, location): @@ -99,7 +107,7 @@ index 1c4b943..c922be1 100644 class PyPIRepository(BaseRepository): DEFAULT_INDEX_URL = PyPI.simple_url -@@ -46,10 +92,11 @@ class PyPIRepository(BaseRepository): +@@ -46,10 +96,11 @@ class PyPIRepository(BaseRepository): config), but any other PyPI mirror can be used if index_urls is changed/configured on the Finder. """ @@ -113,7 +121,7 @@ index 1c4b943..c922be1 100644 index_urls = [pip_options.index_url] + pip_options.extra_index_urls if pip_options.no_index: -@@ -74,11 +121,15 @@ class PyPIRepository(BaseRepository): +@@ -74,11 +125,15 @@ class PyPIRepository(BaseRepository): # of all secondary dependencies for the given requirement, so we # only have to go to disk once for each requirement self._dependencies_cache = {} @@ -131,7 +139,7 @@ index 1c4b943..c922be1 100644 def freshen_build_caches(self): """ -@@ -114,10 +165,14 @@ class PyPIRepository(BaseRepository): +@@ -114,10 +169,14 @@ class PyPIRepository(BaseRepository): if ireq.editable: return ireq # return itself as the best match @@ -148,7 +156,7 @@ index 1c4b943..c922be1 100644 # Reuses pip's internal candidate sort key to sort matching_candidates = [candidates_by_version[ver] for ver in matching_versions] -@@ -126,11 +181,71 @@ class PyPIRepository(BaseRepository): +@@ -126,11 +185,71 @@ class PyPIRepository(BaseRepository): best_candidate = max(matching_candidates, key=self.finder._candidate_sort_key) # Turn the candidate into a pinned InstallRequirement @@ -223,7 +231,7 @@ index 1c4b943..c922be1 100644 """ Given a pinned or an editable InstallRequirement, returns a set of dependencies (also InstallRequirements, but not necessarily pinned). -@@ -155,20 +270,40 @@ class PyPIRepository(BaseRepository): +@@ -155,20 +274,40 @@ class PyPIRepository(BaseRepository): os.makedirs(download_dir) if not os.path.isdir(self._wheel_download_dir): os.makedirs(self._wheel_download_dir) @@ -268,7 +276,7 @@ index 1c4b943..c922be1 100644 ) except TypeError: # Pip >= 10 (new resolver!) -@@ -188,17 +323,97 @@ class PyPIRepository(BaseRepository): +@@ -188,17 +327,97 @@ class PyPIRepository(BaseRepository): finder=self.finder, session=self.session, upgrade_strategy="to-satisfy-only", @@ -369,7 +377,7 @@ index 1c4b943..c922be1 100644 return set(self._dependencies_cache[ireq]) def get_hashes(self, ireq): -@@ -217,24 +432,22 @@ class PyPIRepository(BaseRepository): +@@ -217,24 +436,22 @@ class PyPIRepository(BaseRepository): # We need to get all of the candidates that match our current version # pin, these will represent all of the files that could possibly # satisfy this constraint. From f3e4e73cff7ac91fc13da87f367b2bdbfb2b9d31 Mon Sep 17 00:00:00 2001 From: Dan Ryan Date: Tue, 24 Jul 2018 18:31:55 -0400 Subject: [PATCH 2/8] Fix resolution using `dependency_links` with ssh - Exclude VCS SSH uris from hashing - Add additional resilience to the piptools resolver - Fixes #2613 Signed-off-by: Dan Ryan --- news/2643.bugfix | 1 + pipenv/patched/piptools/repositories/pypi.py | 28 +++++---- .../vendoring/patches/patched/piptools.patch | 57 ++++++++++++------- 3 files changed, 55 insertions(+), 31 deletions(-) create mode 100644 news/2643.bugfix diff --git a/news/2643.bugfix b/news/2643.bugfix new file mode 100644 index 0000000000..566879afbc --- /dev/null +++ b/news/2643.bugfix @@ -0,0 +1 @@ +Dependency links to private repositories defined via ``ssh://`` schemes will now install correctly and skip hashing as long as ``PIP_PROCESS_DEPENDENCY_LINKS=1``. diff --git a/pipenv/patched/piptools/repositories/pypi.py b/pipenv/patched/piptools/repositories/pypi.py index 2f746094be..feab21b53c 100644 --- a/pipenv/patched/piptools/repositories/pypi.py +++ b/pipenv/patched/piptools/repositories/pypi.py @@ -21,18 +21,16 @@ SafeFileCache, ) -from pipenv.patched.notpip._vendor.packaging.requirements import InvalidRequirement, Requirement -from pipenv.patched.notpip._vendor.packaging.version import Version, InvalidVersion, parse as parse_version -from pipenv.patched.notpip._vendor.packaging.specifiers import SpecifierSet, InvalidSpecifier, Specifier -from pipenv.patched.notpip._vendor.packaging.markers import Marker, Op, Value, Variable -from pipenv.patched.notpip._vendor.pyparsing import ParseException +from pipenv.patched.notpip._vendor.packaging.requirements import Requirement +from pipenv.patched.notpip._vendor.packaging.specifiers import SpecifierSet, Specifier +from pipenv.patched.notpip._vendor.packaging.markers import Op, Value, Variable from pipenv.patched.notpip._internal.exceptions import InstallationError +from pipenv.patched.notpip._internal.vcs import VcsSupport -from ..cache import CACHE_DIR from pipenv.environments import PIPENV_CACHE_DIR from ..exceptions import NoCandidateFound -from ..utils import (fs_str, is_pinned_requirement, lookup_table, as_tuple, key_from_req, - make_install_requirement, format_requirement, dedup, clean_requires_python) +from ..utils import (fs_str, is_pinned_requirement, lookup_table, + make_install_requirement, clean_requires_python) from .base import BaseRepository @@ -64,9 +62,10 @@ def __init__(self, *args, **kwargs): def get_hash(self, location): # if there is no location hash (i.e., md5 / sha256 / etc) we on't want to store it hash_value = None - vcs_uris = ('git+', 'bzr+', 'hg+', 'svn+') + vcs = VcsSupport() + orig_scheme = location.scheme new_location = copy.deepcopy(location) - if any(new_location.url.startswith(vcs) for vcs in vcs_uris): + if orig_scheme in vcs.all_schemes: new_location.url = new_location.url.split("+", 1)[-1] can_hash = new_location.hash if can_hash: @@ -280,6 +279,11 @@ def get_legacy_dependencies(self, ireq): setup_requires = {} dist = None if ireq.editable: + try: + from setuptools.build_meta import _run_setup + _run_setup(ireq.setup_py) + except (ImportError, InstallationError): + pass try: dist = ireq.get_dist() except InstallationError: @@ -429,6 +433,10 @@ def get_hashes(self, ireq): if ireq.editable: return set() + vcs = VcsSupport() + if ireq.link.scheme in vcs.all_schemes and 'ssh' in ireq.link.scheme: + return set() + if not is_pinned_requirement(ireq): raise TypeError( "Expected pinned requirement, got {}".format(ireq)) diff --git a/tasks/vendoring/patches/patched/piptools.patch b/tasks/vendoring/patches/patched/piptools.patch index 56696e0889..b527470bdf 100644 --- a/tasks/vendoring/patches/patched/piptools.patch +++ b/tasks/vendoring/patches/patched/piptools.patch @@ -19,7 +19,7 @@ index 4e6174c..75f9b49 100644 # NOTE # We used to store the cache dir under ~/.pip-tools, which is not the diff --git a/pipenv/patched/piptools/repositories/pypi.py b/pipenv/patched/piptools/repositories/pypi.py -index 1c4b943..245e9ce 100644 +index 1c4b943..9461709 100644 --- a/pipenv/patched/piptools/repositories/pypi.py +++ b/pipenv/patched/piptools/repositories/pypi.py @@ -1,9 +1,10 @@ @@ -34,7 +34,7 @@ index 1c4b943..245e9ce 100644 from contextlib import contextmanager from shutil import rmtree -@@ -15,13 +16,24 @@ from .._compat import ( +@@ -15,13 +16,22 @@ from .._compat import ( Wheel, FAVORITE_HASH, TemporaryDirectory, @@ -44,25 +44,23 @@ index 1c4b943..245e9ce 100644 + SafeFileCache, ) -+from pip._vendor.packaging.requirements import InvalidRequirement, Requirement -+from pip._vendor.packaging.version import Version, InvalidVersion, parse as parse_version -+from pip._vendor.packaging.specifiers import SpecifierSet, InvalidSpecifier, Specifier -+from pip._vendor.packaging.markers import Marker, Op, Value, Variable -+from pip._vendor.pyparsing import ParseException +-from ..cache import CACHE_DIR ++from pip._vendor.packaging.requirements import Requirement ++from pip._vendor.packaging.specifiers import SpecifierSet, Specifier ++from pip._vendor.packaging.markers import Op, Value, Variable +from pip._internal.exceptions import InstallationError ++from pip._internal.vcs import VcsSupport + - from ..cache import CACHE_DIR +from pipenv.environments import PIPENV_CACHE_DIR from ..exceptions import NoCandidateFound --from ..utils import (fs_str, is_pinned_requirement, lookup_table, + from ..utils import (fs_str, is_pinned_requirement, lookup_table, - make_install_requirement) -+from ..utils import (fs_str, is_pinned_requirement, lookup_table, as_tuple, key_from_req, -+ make_install_requirement, format_requirement, dedup, clean_requires_python) ++ make_install_requirement, clean_requires_python) + from .base import BaseRepository -@@ -37,6 +49,44 @@ except ImportError: +@@ -37,6 +47,45 @@ except ImportError: from pip.wheel import WheelCache @@ -81,9 +79,10 @@ index 1c4b943..245e9ce 100644 + def get_hash(self, location): + # if there is no location hash (i.e., md5 / sha256 / etc) we on't want to store it + hash_value = None -+ vcs_uris = ('git+', 'bzr+', 'hg+', 'svn+') ++ vcs = VcsSupport() ++ orig_scheme = location.scheme + new_location = copy.deepcopy(location) -+ if any(new_location.url.startswith(vcs) for vcs in vcs_uris): ++ if orig_scheme in vcs.all_schemes: + new_location.url = new_location.url.split("+", 1)[-1] + can_hash = new_location.hash + if can_hash: @@ -107,7 +106,7 @@ index 1c4b943..245e9ce 100644 class PyPIRepository(BaseRepository): DEFAULT_INDEX_URL = PyPI.simple_url -@@ -46,10 +96,11 @@ class PyPIRepository(BaseRepository): +@@ -46,10 +95,11 @@ class PyPIRepository(BaseRepository): config), but any other PyPI mirror can be used if index_urls is changed/configured on the Finder. """ @@ -121,7 +120,7 @@ index 1c4b943..245e9ce 100644 index_urls = [pip_options.index_url] + pip_options.extra_index_urls if pip_options.no_index: -@@ -74,11 +125,15 @@ class PyPIRepository(BaseRepository): +@@ -74,11 +124,15 @@ class PyPIRepository(BaseRepository): # of all secondary dependencies for the given requirement, so we # only have to go to disk once for each requirement self._dependencies_cache = {} @@ -139,7 +138,7 @@ index 1c4b943..245e9ce 100644 def freshen_build_caches(self): """ -@@ -114,10 +169,14 @@ class PyPIRepository(BaseRepository): +@@ -114,10 +168,14 @@ class PyPIRepository(BaseRepository): if ireq.editable: return ireq # return itself as the best match @@ -156,7 +155,7 @@ index 1c4b943..245e9ce 100644 # Reuses pip's internal candidate sort key to sort matching_candidates = [candidates_by_version[ver] for ver in matching_versions] -@@ -126,11 +185,71 @@ class PyPIRepository(BaseRepository): +@@ -126,11 +184,71 @@ class PyPIRepository(BaseRepository): best_candidate = max(matching_candidates, key=self.finder._candidate_sort_key) # Turn the candidate into a pinned InstallRequirement @@ -231,7 +230,7 @@ index 1c4b943..245e9ce 100644 """ Given a pinned or an editable InstallRequirement, returns a set of dependencies (also InstallRequirements, but not necessarily pinned). -@@ -155,20 +274,40 @@ class PyPIRepository(BaseRepository): +@@ -155,20 +273,45 @@ class PyPIRepository(BaseRepository): os.makedirs(download_dir) if not os.path.isdir(self._wheel_download_dir): os.makedirs(self._wheel_download_dir) @@ -243,6 +242,11 @@ index 1c4b943..245e9ce 100644 + dist = None + if ireq.editable: + try: ++ from setuptools.build_meta import _run_setup ++ _run_setup(ireq.setup_py) ++ except (ImportError, InstallationError): ++ pass ++ try: + dist = ireq.get_dist() + except InstallationError: + ireq.run_egg_info() @@ -276,7 +280,7 @@ index 1c4b943..245e9ce 100644 ) except TypeError: # Pip >= 10 (new resolver!) -@@ -188,17 +327,97 @@ class PyPIRepository(BaseRepository): +@@ -188,17 +331,97 @@ class PyPIRepository(BaseRepository): finder=self.finder, session=self.session, upgrade_strategy="to-satisfy-only", @@ -377,7 +381,18 @@ index 1c4b943..245e9ce 100644 return set(self._dependencies_cache[ireq]) def get_hashes(self, ireq): -@@ -217,24 +436,22 @@ class PyPIRepository(BaseRepository): +@@ -210,6 +433,10 @@ class PyPIRepository(BaseRepository): + if ireq.editable: + return set() + ++ vcs = VcsSupport() ++ if ireq.link.scheme in vcs.all_schemes and 'ssh' in ireq.link.scheme: ++ return set() ++ + if not is_pinned_requirement(ireq): + raise TypeError( + "Expected pinned requirement, got {}".format(ireq)) +@@ -217,24 +444,22 @@ class PyPIRepository(BaseRepository): # We need to get all of the candidates that match our current version # pin, these will represent all of the files that could possibly # satisfy this constraint. From 5334183c436c6a1572645fbd7de7720eb51f419f Mon Sep 17 00:00:00 2001 From: Dan Ryan Date: Tue, 24 Jul 2018 19:11:36 -0400 Subject: [PATCH 3/8] Make sure there is a link to check against Signed-off-by: Dan Ryan --- pipenv/patched/piptools/repositories/pypi.py | 2 +- tasks/vendoring/patches/patched/piptools.patch | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pipenv/patched/piptools/repositories/pypi.py b/pipenv/patched/piptools/repositories/pypi.py index feab21b53c..daaa590287 100644 --- a/pipenv/patched/piptools/repositories/pypi.py +++ b/pipenv/patched/piptools/repositories/pypi.py @@ -434,7 +434,7 @@ def get_hashes(self, ireq): return set() vcs = VcsSupport() - if ireq.link.scheme in vcs.all_schemes and 'ssh' in ireq.link.scheme: + if ireq.link and ireq.link.scheme in vcs.all_schemes and 'ssh' in ireq.link.scheme: return set() if not is_pinned_requirement(ireq): diff --git a/tasks/vendoring/patches/patched/piptools.patch b/tasks/vendoring/patches/patched/piptools.patch index b527470bdf..8dd58066d2 100644 --- a/tasks/vendoring/patches/patched/piptools.patch +++ b/tasks/vendoring/patches/patched/piptools.patch @@ -386,7 +386,7 @@ index 1c4b943..9461709 100644 return set() + vcs = VcsSupport() -+ if ireq.link.scheme in vcs.all_schemes and 'ssh' in ireq.link.scheme: ++ if ireq.link and ireq.link.scheme in vcs.all_schemes and 'ssh' in ireq.link.scheme: + return set() + if not is_pinned_requirement(ireq): From 6e38560a7f8026caeeaa4a3b486115ff430a24c9 Mon Sep 17 00:00:00 2001 From: Dan Ryan Date: Tue, 24 Jul 2018 19:35:44 -0400 Subject: [PATCH 4/8] Add chdir context manager and properly run setup.py files during resolution Signed-off-by: Dan Ryan --- news/2643.feature | 1 + pipenv/patched/piptools/repositories/pypi.py | 6 ++++-- pipenv/utils.py | 12 ++++++++++++ tasks/vendoring/patches/patched/piptools.patch | 16 +++++++++------- 4 files changed, 26 insertions(+), 9 deletions(-) create mode 100644 news/2643.feature diff --git a/news/2643.feature b/news/2643.feature new file mode 100644 index 0000000000..052398c7d9 --- /dev/null +++ b/news/2643.feature @@ -0,0 +1 @@ +Enhanced resolution of editable and VCS dependencies. diff --git a/pipenv/patched/piptools/repositories/pypi.py b/pipenv/patched/piptools/repositories/pypi.py index daaa590287..94879f2ff5 100644 --- a/pipenv/patched/piptools/repositories/pypi.py +++ b/pipenv/patched/piptools/repositories/pypi.py @@ -280,8 +280,10 @@ def get_legacy_dependencies(self, ireq): dist = None if ireq.editable: try: - from setuptools.build_meta import _run_setup - _run_setup(ireq.setup_py) + from pipenv.utils import chdir + with chdir(ireq.setup_py_dir): + from setuptools.dist import distutils + distutils.core.run_setup(ireq.setup_py) except (ImportError, InstallationError): pass try: diff --git a/pipenv/utils.py b/pipenv/utils.py index 08c08381cf..b45081fe11 100644 --- a/pipenv/utils.py +++ b/pipenv/utils.py @@ -1361,3 +1361,15 @@ def is_virtual_environment(path): if python_like.is_file() and os.access(str(python_like), os.X_OK): return True return False + + +@contextmanager +def chdir(path): + """Context manager to change working directories.""" + from ._compat import Path + prev_cwd = Path.cwd() + os.chdir(str(path)) + try: + yield + finally: + os.chdir(prev_cwd) diff --git a/tasks/vendoring/patches/patched/piptools.patch b/tasks/vendoring/patches/patched/piptools.patch index 8dd58066d2..17f2e2b56f 100644 --- a/tasks/vendoring/patches/patched/piptools.patch +++ b/tasks/vendoring/patches/patched/piptools.patch @@ -19,7 +19,7 @@ index 4e6174c..75f9b49 100644 # NOTE # We used to store the cache dir under ~/.pip-tools, which is not the diff --git a/pipenv/patched/piptools/repositories/pypi.py b/pipenv/patched/piptools/repositories/pypi.py -index 1c4b943..9461709 100644 +index 1c4b943..91902dc 100644 --- a/pipenv/patched/piptools/repositories/pypi.py +++ b/pipenv/patched/piptools/repositories/pypi.py @@ -1,9 +1,10 @@ @@ -230,7 +230,7 @@ index 1c4b943..9461709 100644 """ Given a pinned or an editable InstallRequirement, returns a set of dependencies (also InstallRequirements, but not necessarily pinned). -@@ -155,20 +273,45 @@ class PyPIRepository(BaseRepository): +@@ -155,20 +273,47 @@ class PyPIRepository(BaseRepository): os.makedirs(download_dir) if not os.path.isdir(self._wheel_download_dir): os.makedirs(self._wheel_download_dir) @@ -242,8 +242,10 @@ index 1c4b943..9461709 100644 + dist = None + if ireq.editable: + try: -+ from setuptools.build_meta import _run_setup -+ _run_setup(ireq.setup_py) ++ from pipenv.utils import chdir ++ with chdir(ireq.setup_py_dir): ++ from setuptools.dist import distutils ++ distutils.core.run_setup(ireq.setup_py) + except (ImportError, InstallationError): + pass + try: @@ -280,7 +282,7 @@ index 1c4b943..9461709 100644 ) except TypeError: # Pip >= 10 (new resolver!) -@@ -188,17 +331,97 @@ class PyPIRepository(BaseRepository): +@@ -188,17 +333,97 @@ class PyPIRepository(BaseRepository): finder=self.finder, session=self.session, upgrade_strategy="to-satisfy-only", @@ -381,7 +383,7 @@ index 1c4b943..9461709 100644 return set(self._dependencies_cache[ireq]) def get_hashes(self, ireq): -@@ -210,6 +433,10 @@ class PyPIRepository(BaseRepository): +@@ -210,6 +435,10 @@ class PyPIRepository(BaseRepository): if ireq.editable: return set() @@ -392,7 +394,7 @@ index 1c4b943..9461709 100644 if not is_pinned_requirement(ireq): raise TypeError( "Expected pinned requirement, got {}".format(ireq)) -@@ -217,24 +444,22 @@ class PyPIRepository(BaseRepository): +@@ -217,24 +446,22 @@ class PyPIRepository(BaseRepository): # We need to get all of the candidates that match our current version # pin, these will represent all of the files that could possibly # satisfy this constraint. From 1c6acfecb5db81575ea3af8266dbf08bb812324c Mon Sep 17 00:00:00 2001 From: Dan Ryan Date: Tue, 24 Jul 2018 20:24:06 -0400 Subject: [PATCH 5/8] Ensure that we use posix style strings instead of Path objects for chdir context manager Signed-off-by: Dan Ryan --- pipenv/utils.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pipenv/utils.py b/pipenv/utils.py index b45081fe11..be1240ac05 100644 --- a/pipenv/utils.py +++ b/pipenv/utils.py @@ -1367,7 +1367,9 @@ def is_virtual_environment(path): def chdir(path): """Context manager to change working directories.""" from ._compat import Path - prev_cwd = Path.cwd() + prev_cwd = Path.cwd().as_posix() + if isinstance(path, Path): + path = path.as_posix() os.chdir(str(path)) try: yield From c584739b417c52d06c4b14a0e58fba620e01dc00 Mon Sep 17 00:00:00 2001 From: Dan Ryan Date: Tue, 24 Jul 2018 20:31:27 -0400 Subject: [PATCH 6/8] Handle NoneType paths Signed-off-by: Dan Ryan --- pipenv/utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pipenv/utils.py b/pipenv/utils.py index be1240ac05..286b18665e 100644 --- a/pipenv/utils.py +++ b/pipenv/utils.py @@ -1367,6 +1367,8 @@ def is_virtual_environment(path): def chdir(path): """Context manager to change working directories.""" from ._compat import Path + if not path: + return prev_cwd = Path.cwd().as_posix() if isinstance(path, Path): path = path.as_posix() From dc97d73e62bf89a8a57d9efb25c24676c0e39df3 Mon Sep 17 00:00:00 2001 From: Dan Ryan Date: Tue, 24 Jul 2018 23:37:28 -0400 Subject: [PATCH 7/8] Add exception handling for non-existent setup_py_dir Signed-off-by: Dan Ryan --- pipenv/patched/piptools/repositories/pypi.py | 2 +- tasks/vendoring/patches/patched/piptools.patch | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pipenv/patched/piptools/repositories/pypi.py b/pipenv/patched/piptools/repositories/pypi.py index 94879f2ff5..f92bd97e0b 100644 --- a/pipenv/patched/piptools/repositories/pypi.py +++ b/pipenv/patched/piptools/repositories/pypi.py @@ -284,7 +284,7 @@ def get_legacy_dependencies(self, ireq): with chdir(ireq.setup_py_dir): from setuptools.dist import distutils distutils.core.run_setup(ireq.setup_py) - except (ImportError, InstallationError): + except (ImportError, InstallationError, TypeError): pass try: dist = ireq.get_dist() diff --git a/tasks/vendoring/patches/patched/piptools.patch b/tasks/vendoring/patches/patched/piptools.patch index 17f2e2b56f..273955a1f2 100644 --- a/tasks/vendoring/patches/patched/piptools.patch +++ b/tasks/vendoring/patches/patched/piptools.patch @@ -246,7 +246,7 @@ index 1c4b943..91902dc 100644 + with chdir(ireq.setup_py_dir): + from setuptools.dist import distutils + distutils.core.run_setup(ireq.setup_py) -+ except (ImportError, InstallationError): ++ except (ImportError, InstallationError, TypeError): + pass + try: + dist = ireq.get_dist() From d33c4e86e18489e0ac51b1d225fe26e1d68d1d69 Mon Sep 17 00:00:00 2001 From: Dan Ryan Date: Wed, 25 Jul 2018 00:14:44 -0400 Subject: [PATCH 8/8] Fix exception handling Signed-off-by: Dan Ryan --- pipenv/patched/piptools/repositories/pypi.py | 2 +- tasks/vendoring/patches/patched/piptools.patch | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pipenv/patched/piptools/repositories/pypi.py b/pipenv/patched/piptools/repositories/pypi.py index f92bd97e0b..bf7ebd2da6 100644 --- a/pipenv/patched/piptools/repositories/pypi.py +++ b/pipenv/patched/piptools/repositories/pypi.py @@ -284,7 +284,7 @@ def get_legacy_dependencies(self, ireq): with chdir(ireq.setup_py_dir): from setuptools.dist import distutils distutils.core.run_setup(ireq.setup_py) - except (ImportError, InstallationError, TypeError): + except (ImportError, InstallationError, TypeError, AttributeError): pass try: dist = ireq.get_dist() diff --git a/tasks/vendoring/patches/patched/piptools.patch b/tasks/vendoring/patches/patched/piptools.patch index 273955a1f2..7d9b64d8ee 100644 --- a/tasks/vendoring/patches/patched/piptools.patch +++ b/tasks/vendoring/patches/patched/piptools.patch @@ -246,7 +246,7 @@ index 1c4b943..91902dc 100644 + with chdir(ireq.setup_py_dir): + from setuptools.dist import distutils + distutils.core.run_setup(ireq.setup_py) -+ except (ImportError, InstallationError, TypeError): ++ except (ImportError, InstallationError, TypeError, AttributeError): + pass + try: + dist = ireq.get_dist()