diff --git a/news/2417.bugfix b/news/2417.bugfix new file mode 100644 index 00000000..bb76c190 --- /dev/null +++ b/news/2417.bugfix @@ -0,0 +1 @@ +Fixed a logic error which caused ``--deploy --system`` to overwrite editable vcs packages in the pipfile before installing, which caused any installation to fail by default. diff --git a/news/2419.bugfix b/news/2419.bugfix new file mode 100644 index 00000000..fec7157a --- /dev/null +++ b/news/2419.bugfix @@ -0,0 +1 @@ +Updated requirementslib to fix an issue with properly quoting markers in VCS requirements. diff --git a/news/2419.vendor b/news/2419.vendor new file mode 100644 index 00000000..fec7157a --- /dev/null +++ b/news/2419.vendor @@ -0,0 +1 @@ +Updated requirementslib to fix an issue with properly quoting markers in VCS requirements. diff --git a/pipenv/__version__.py b/pipenv/__version__.py index 5692134d..afc0a721 100644 --- a/pipenv/__version__.py +++ b/pipenv/__version__.py @@ -2,4 +2,4 @@ # // ) ) / / // ) ) //___) ) // ) ) || / / # //___/ / / / //___/ / // // / / || / / # // / / // ((____ // / / ||/ / -__version__ = '2018.6.25' +__version__ = '2018.6.26.dev0' diff --git a/pipenv/core.py b/pipenv/core.py index 2f85ab9c..4346f487 100644 --- a/pipenv/core.py +++ b/pipenv/core.py @@ -617,7 +617,7 @@ def ensure_project( # Automatically use an activated virtualenv. if PIPENV_USE_SYSTEM: system = True - if not project.pipfile_exists: + if not project.pipfile_exists and not deploy: project.touch_pipfile() # Skip virtualenv creation when --system was used. if not system: @@ -1269,7 +1269,8 @@ def do_init( cleanup_virtualenv(bare=False) sys.exit(1) # Ensure the Pipfile exists. - ensure_pipfile(system=system) + if not deploy: + ensure_pipfile(system=system) if not requirements_dir: cleanup_reqdir = True requirements_dir = TemporaryDirectory( @@ -1916,7 +1917,8 @@ def do_install( package_name = False # Install editable local packages before locking - this gives us access to dist-info if project.pipfile_exists and ( - not project.lockfile_exists or not project.virtualenv_exists + # double negatives are for english readability, leave them alone. + (not project.lockfile_exists and not deploy) or (not project.virtualenv_exists and not system) ): section = project.editable_packages if not dev else project.editable_dev_packages for package in section.keys(): @@ -2570,6 +2572,8 @@ def do_sync( unused=False, sequential=False, pypi_mirror=None, + system=False, + deploy=False, ): # The lock file needs to exist because sync won't write to it. if not project.lockfile_exists: @@ -2582,8 +2586,8 @@ def do_sync( ) sys.exit(1) - # Ensure that virtualenv is available. - ensure_project(three=three, python=python, validate=False) + # Ensure that virtualenv is available if not system. + ensure_project(three=three, python=python, validate=False, deploy=deploy) # Install everything. requirements_dir = TemporaryDirectory( @@ -2596,6 +2600,8 @@ def do_sync( requirements_dir=requirements_dir, ignore_pipfile=True, # Don't check if Pipfile and lock match. pypi_mirror=pypi_mirror, + deploy=deploy, + system=system, ) requirements_dir.cleanup() click.echo(crayons.green('All dependencies are now up-to-date!')) diff --git a/pipenv/patched/piptools/repositories/pypi.py b/pipenv/patched/piptools/repositories/pypi.py index 3fee3d89..4a960d8f 100644 --- a/pipenv/patched/piptools/repositories/pypi.py +++ b/pipenv/patched/piptools/repositories/pypi.py @@ -19,7 +19,6 @@ from .._compat import ( PyPI, InstallRequirement, SafeFileCache, - InstallationError, ) from pipenv.patched.notpip._vendor.packaging.requirements import InvalidRequirement, Requirement @@ -27,6 +26,7 @@ from pipenv.patched.notpip._vendor.packaging.version import Version, InvalidVers 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._internal.exceptions import InstallationError from ..cache import CACHE_DIR from pipenv.environments import PIPENV_CACHE_DIR @@ -278,13 +278,16 @@ class PyPIRepository(BaseRepository): if ireq.editable: try: dist = ireq.get_dist() + except InstallationError: + ireq.run_egg_info() + dist = ireq.get_dist() + except (TypeError, ValueError, AttributeError): + pass + else: if dist.has_metadata('requires.txt'): setup_requires = self.finder.get_extras_links( dist.get_metadata_lines('requires.txt') ) - except (TypeError, ValueError, AttributeError): - pass - try: # Pip < 9 and below reqset = RequirementSet( diff --git a/pipenv/vendor/requirementslib/__init__.py b/pipenv/vendor/requirementslib/__init__.py index f3393c11..7e4acf40 100644 --- a/pipenv/vendor/requirementslib/__init__.py +++ b/pipenv/vendor/requirementslib/__init__.py @@ -1,5 +1,5 @@ # -*- coding=utf-8 -*- -__version__ = "1.0.5.dev0" +__version__ = "1.0.6" from .exceptions import RequirementError diff --git a/pipenv/vendor/requirementslib/models/requirements.py b/pipenv/vendor/requirementslib/models/requirements.py index 16d99863..6dc76e0d 100644 --- a/pipenv/vendor/requirementslib/models/requirements.py +++ b/pipenv/vendor/requirementslib/models/requirements.py @@ -649,7 +649,7 @@ class Requirement(object): @property def markers_as_pip(self): if self.markers: - return "; {0}".format(self.markers) + return "; {0}".format(self.markers.replace('"', "'")) return "" diff --git a/pipenv/vendor/vendor.txt b/pipenv/vendor/vendor.txt index 6b44b53d..a19294b7 100644 --- a/pipenv/vendor/vendor.txt +++ b/pipenv/vendor/vendor.txt @@ -27,7 +27,7 @@ requests==2.19.1 idna==2.7 urllib3==1.23 certifi==2018.4.16 -requirementslib==1.0.5 +requirementslib==1.0.6 attrs==18.1.0 distlib==0.2.7 packaging==17.1 diff --git a/setup.py b/setup.py index 3931cde7..9a31430d 100644 --- a/setup.py +++ b/setup.py @@ -116,6 +116,7 @@ setup( '': ['LICENSE', 'NOTICES'], "pipenv.vendor.requests": ["*.pem"], "pipenv.vendor.certifi": ["*.pem"], + "pipenv.vendor.click_completion": ["*.j2"], "pipenv.patched.notpip._vendor.certifi": ["*.pem"], "pipenv.patched.notpip._vendor.requests": ["*.pem"], "pipenv.patched.notpip._vendor.distlib._backport": ["sysconfig.cfg"], diff --git a/tasks/vendoring/patches/patched/piptools.patch b/tasks/vendoring/patches/patched/piptools.patch index 088aa06c..522c13d8 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..07cd667 100644 +index 1c4b943..c4e5b0e 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, @@ -38,7 +38,6 @@ index 1c4b943..07cd667 100644 + PyPI, + InstallRequirement, + SafeFileCache, -+ InstallationError, ) +from pip._vendor.packaging.requirements import InvalidRequirement, Requirement @@ -46,6 +45,7 @@ index 1c4b943..07cd667 100644 +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 pip._internal.exceptions import InstallationError + from ..cache import CACHE_DIR +from pipenv.environments import PIPENV_CACHE_DIR @@ -223,10 +223,11 @@ index 1c4b943..07cd667 100644 """ Given a pinned or an editable InstallRequirement, returns a set of dependencies (also InstallRequirements, but not necessarily pinned). -@@ -155,6 +270,20 @@ class PyPIRepository(BaseRepository): +@@ -155,7 +270,24 @@ class PyPIRepository(BaseRepository): os.makedirs(download_dir) if not os.path.isdir(self._wheel_download_dir): os.makedirs(self._wheel_download_dir) +- + # Collect setup_requires info from local eggs. + # Do this after we call the preparer on these reqs to make sure their + # egg info has been created @@ -235,16 +236,20 @@ index 1c4b943..07cd667 100644 + if ireq.editable: + try: + dist = ireq.get_dist() ++ except InstallationError: ++ ireq.run_egg_info() ++ dist = ireq.get_dist() ++ except (TypeError, ValueError, AttributeError): ++ pass ++ else: + if dist.has_metadata('requires.txt'): + setup_requires = self.finder.get_extras_links( + dist.get_metadata_lines('requires.txt') + ) -+ except (TypeError, ValueError, AttributeError): -+ pass - try: # Pip < 9 and below -@@ -164,11 +293,14 @@ class PyPIRepository(BaseRepository): + reqset = RequirementSet( +@@ -164,11 +296,14 @@ class PyPIRepository(BaseRepository): download_dir=download_dir, wheel_download_dir=self._wheel_download_dir, session=self.session, @@ -261,7 +266,7 @@ index 1c4b943..07cd667 100644 ) except TypeError: # Pip >= 10 (new resolver!) -@@ -188,17 +320,97 @@ class PyPIRepository(BaseRepository): +@@ -188,17 +323,97 @@ class PyPIRepository(BaseRepository): finder=self.finder, session=self.session, upgrade_strategy="to-satisfy-only", @@ -362,7 +367,7 @@ index 1c4b943..07cd667 100644 return set(self._dependencies_cache[ireq]) def get_hashes(self, ireq): -@@ -217,24 +429,22 @@ class PyPIRepository(BaseRepository): +@@ -217,24 +432,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.