From 45e9f6e417615ba37f4b0621b9b1194693895c2c Mon Sep 17 00:00:00 2001 From: Dan Ryan Date: Sun, 18 Nov 2018 23:49:57 -0500 Subject: [PATCH] Fix parsing of markers in VCS requirements - Parsing of markers in non-editable vcs requirements was broken - This PR adds some VCS repos, some utility pipfile generation functions and some fixture helpers - Fixes #3249 Signed-off-by: Dan Ryan --- .gitmodules | 15 +++++++++ news/3249.bugfix.rst | 1 + pipenv/cli/command.py | 1 - pipenv/core.py | 6 +++- pytest.ini | 2 +- tests/conftest.py | 0 tests/integration/conftest.py | 44 +++++++++++++++++++++++++-- tests/integration/test_install_uri.py | 14 +++++++++ tests/test_artifacts/git/dateutil | 1 + tests/test_artifacts/git/pinax | 1 + tests/test_artifacts/git/requests | 1 + tests/test_artifacts/git/six | 1 + tests/test_artifacts/git/six-1.9.0 | 1 + 13 files changed, 83 insertions(+), 5 deletions(-) create mode 100644 .gitmodules create mode 100644 news/3249.bugfix.rst create mode 100644 tests/conftest.py create mode 160000 tests/test_artifacts/git/dateutil create mode 160000 tests/test_artifacts/git/pinax create mode 160000 tests/test_artifacts/git/requests create mode 160000 tests/test_artifacts/git/six create mode 160000 tests/test_artifacts/git/six-1.9.0 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..f40ee10cde --- /dev/null +++ b/.gitmodules @@ -0,0 +1,15 @@ +[submodule "tests/test_artifacts/git/six-1.9.0"] + path = tests/test_artifacts/git/six-1.9.0 + url = https://github.com/benjaminp/six.git +[submodule "tests/test_artifacts/git/pinax"] + path = tests/test_artifacts/git/pinax + url = https://github.com/pinax/pinax.git +[submodule "tests/test_artifacts/git/requests"] + path = tests/test_artifacts/git/requests + url = https://github.com/requests/requests.git +[submodule "tests/test_artifacts/git/six"] + path = tests/test_artifacts/git/six + url = https://github.com/benjaminp/six.git +[submodule "tests/test_artifacts/git/dateutil"] + path = tests/test_artifacts/git/dateutil + url = https://github.com/dateutil/dateutil diff --git a/news/3249.bugfix.rst b/news/3249.bugfix.rst new file mode 100644 index 0000000000..26d708cb84 --- /dev/null +++ b/news/3249.bugfix.rst @@ -0,0 +1 @@ +Adding normal pep 508 compatible markers is now fully functional when using VCS dependencies. diff --git a/pipenv/cli/command.py b/pipenv/cli/command.py index 16778ede88..a49e90ddd9 100644 --- a/pipenv/cli/command.py +++ b/pipenv/cli/command.py @@ -296,7 +296,6 @@ def uninstall( if retcode: sys.exit(retcode) - @cli.command(short_help="Generates Pipfile.lock.") @lock_options @pass_state diff --git a/pipenv/core.py b/pipenv/core.py index 3b30462542..7dbd755506 100644 --- a/pipenv/core.py +++ b/pipenv/core.py @@ -1361,7 +1361,11 @@ def pip_install( ignore_hashes = True else: ignore_hashes = True if not requirement.hashes else False - install_reqs = [escape_cmd(r) for r in requirement.as_line(as_list=True)] + install_reqs = requirement.as_line(as_list=True) + if not requirement.markers: + install_reqs = [escape_cmd(r) for r in install_reqs] + elif len(install_reqs) > 1: + install_reqs = install_reqs[0] + [escape_cmd(r) for r in install_reqs[1:]] pip_command = [which_pip(allow_global=allow_global), "install"] if pre: pip_command.append("--pre") diff --git a/pytest.ini b/pytest.ini index 2bfca079ab..ff9847d3b1 100644 --- a/pytest.ini +++ b/pytest.ini @@ -2,7 +2,7 @@ addopts = -ra -n auto testpaths = tests ; Add vendor and patched in addition to the default list of ignored dirs -norecursedirs = .* build dist CVS _darcs {arch} *.egg vendor patched news tasks docs +norecursedirs = .* build dist CVS _darcs {arch} *.egg vendor patched news tasks docs tests/test_artifacts filterwarnings = ignore::DeprecationWarning ignore::PendingDeprecationWarning diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 6ed95b3e7c..33fc4fca44 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -9,6 +9,7 @@ from pipenv.vendor import delegator from pipenv.vendor import requests from pipenv.vendor import toml +from pipenv.vendor import tomlkit from pytest_pypi.app import prepare_packages as prepare_pypi_packages from vistir.compat import ResourceWarning, fs_str from vistir.path import mkdir_p @@ -119,6 +120,44 @@ def isolate(pathlib_tmpdir): WE_HAVE_GITHUB_SSH_KEYS = check_github_ssh() +class _Pipfile(object): + def __init__(self, path): + self.path = path + self.document = tomlkit.document() + self.document["sources"] = tomlkit.aot() + self.document["requires"] = tomlkit.table() + self.document["packages"] = tomlkit.table() + self.document["dev_packages"] = tomlkit.table() + + def install(self, package, value, dev=False): + section = "packages" if not dev else "dev_packages" + if isinstance(value, dict): + table = tomlkit.inline_table() + table.update(value) + self.document[section][package] = table + else: + self.document[section][package] = value + self.write() + + def loads(self): + self.document = tomlkit.loads(self.path.read_text()) + + def dumps(self): + source_table = tomlkit.table() + source_table["url"] = os.environ.get("PIPENV_TEST_INDEX") + source_table["verify_ssl"] = False + source_table["name"] = "pipenv_test_index" + self.document["sources"].append(source_table) + return tomlkit.dumps(self.document) + + def write(self): + self.path.write_text(self.dumps()) + + @classmethod + def get_fixture_path(cls, path): + return Path(__file__).absolute().parent.parent / "test_artifacts" / path + + class _PipenvInstance(object): """An instance of a Pipenv Project...""" def __init__(self, pypi=None, pipfile=True, chdir=False, path=None, home_dir=None): @@ -129,7 +168,7 @@ def __init__(self, pypi=None, pipfile=True, chdir=False, path=None, home_dir=Non os.environ["CI"] = fs_str("1") warnings.simplefilter("ignore", category=ResourceWarning) warnings.filterwarnings("ignore", category=ResourceWarning, message="unclosed.*") - path = os.environ.get("PIPENV_PROJECT_DIR", None) + path = path if path else os.environ.get("PIPENV_PROJECT_DIR", None) if not path: self._path = TemporaryDirectory(suffix='-project', prefix='pipenv-') path = Path(self._path.name) @@ -138,7 +177,7 @@ def __init__(self, pypi=None, pipfile=True, chdir=False, path=None, home_dir=Non except OSError: self.path = str(path.absolute()) else: - self._path = None + self._path = path self.path = path # set file creation perms self.pipfile_path = None @@ -154,6 +193,7 @@ def __init__(self, pypi=None, pipfile=True, chdir=False, path=None, home_dir=Non self.chdir = False or chdir self.pipfile_path = p_path + self._pipfile = _Pipfile(Path(p_path)) def __enter__(self): os.environ['PIPENV_DONT_USE_PYENV'] = fs_str('1') diff --git a/tests/integration/test_install_uri.py b/tests/integration/test_install_uri.py index c5915607c3..337181faf2 100644 --- a/tests/integration/test_install_uri.py +++ b/tests/integration/test_install_uri.py @@ -270,3 +270,17 @@ def test_vcs_entry_supersedes_non_vcs(PipenvInstance, pip_src_dir): p.lockfile["default"]["pyinstaller"]["git"] == "https://github.com/pyinstaller/pyinstaller.git" ) + + +@pytest.mark.vcs +@pytest.mark.install +@pytest.mark.needs_internet +def test_vcs_can_use_markers(PipenvInstance, pip_src_dir, pypi): + with PipenvInstance(chdir=True, pypi=pypi) as p: + path = p._pipfile.get_fixture_path("git/six/.git") + p._pipfile.install("six", {"git": "{0}".format(path.as_uri()), "markers": "sys_platform == 'linux'"}) + assert "six" in p.pipfile["packages"] + c = p.pipenv("install") + assert c.return_code == 0 + assert "six" in p.lockfile["default"] + assert "git" in p.lockfile["default"]["six"] diff --git a/tests/test_artifacts/git/dateutil b/tests/test_artifacts/git/dateutil new file mode 160000 index 0000000000..6618dee970 --- /dev/null +++ b/tests/test_artifacts/git/dateutil @@ -0,0 +1 @@ +Subproject commit 6618dee970ec1e5f92e0f48ec74584caf13075aa diff --git a/tests/test_artifacts/git/pinax b/tests/test_artifacts/git/pinax new file mode 160000 index 0000000000..147d854322 --- /dev/null +++ b/tests/test_artifacts/git/pinax @@ -0,0 +1 @@ +Subproject commit 147d854322cc2ab8246b9f52fa3189dfca3cddec diff --git a/tests/test_artifacts/git/requests b/tests/test_artifacts/git/requests new file mode 160000 index 0000000000..57d7284c1a --- /dev/null +++ b/tests/test_artifacts/git/requests @@ -0,0 +1 @@ +Subproject commit 57d7284c1a245cf9fbcecb594f50471d86e879f7 diff --git a/tests/test_artifacts/git/six b/tests/test_artifacts/git/six new file mode 160000 index 0000000000..e114efceea --- /dev/null +++ b/tests/test_artifacts/git/six @@ -0,0 +1 @@ +Subproject commit e114efceea962fb143c909c904157ca994246fd2 diff --git a/tests/test_artifacts/git/six-1.9.0 b/tests/test_artifacts/git/six-1.9.0 new file mode 160000 index 0000000000..5efb522b06 --- /dev/null +++ b/tests/test_artifacts/git/six-1.9.0 @@ -0,0 +1 @@ +Subproject commit 5efb522b0647f7467248273ec1b893d06b984a59