From d396040c10779918872f0466be32638c42c0eb45 Mon Sep 17 00:00:00 2001 From: Tsvika Date: Mon, 3 Feb 2020 17:53:21 +0200 Subject: [PATCH 1/2] feat: update pip to defined versions after creating a new venv Until now, a new venv created with poetry would have an undefined pip version. This could be problematic, as older pip versions are not compatible with some packages (see issues list below), and might have security risks. And on the other hand, future pip versions might introduce API changes that will prevent poetry from working. This commit forces new venvs to update pip to a defined range of versions. Updating pip just after venv creation (and not each time before package installation) will still allow users to manualy change it, if the need arise. code is loosely based on https://github.com/python-poetry/poetry/pull/740 closes: https://github.com/python-poetry/poetry/issues/732 https://github.com/python-poetry/poetry/issues/1661 https://github.com/python-poetry/poetry/issues/1962 https://github.com/python-poetry/poetry/issues/1651 --- poetry/utils/env.py | 64 ++++++++++++++++++++++++++++------------- tests/utils/test_env.py | 6 ++++ 2 files changed, 50 insertions(+), 20 deletions(-) diff --git a/poetry/utils/env.py b/poetry/utils/env.py index dcdec0363bf..01a45bcf168 100644 --- a/poetry/utils/env.py +++ b/poetry/utils/env.py @@ -34,6 +34,20 @@ from poetry.version.markers import BaseMarker +# pip version requirements when creating venvs are specified here. +# The maximal version is chosen to be the last version in the 19.3 branch, as +# it seems to be relatively bug free, and to work well with poetry (poetry +# uses pip internally, and pip API might change in ways that can break stuff). +# Note that pip 19.3 is required to find and install manylinux2014 packages. +# This version should be updated from time to time. +PIP_VERSION_MAX = "19.3.1" +# We use a different minimal version to allow fallback in case of older python +# versions. This version was chosen to be 19.1.1, as it is the most recent +# version that supports python 3.4. +# When poetry will drop support for EOL python versions, it might be possible +# to update this version, or to use a pinned version instead. +PIP_VERSION_MIN = "19.1.1" + GET_ENVIRONMENT_INFO = """\ import json import os @@ -656,26 +670,36 @@ def build_venv(cls, path, executable=None): except CalledProcessError as e: raise EnvCommandError(e) - return - - try: - from venv import EnvBuilder - - # use the same defaults as python -m venv - if os.name == "nt": - use_symlinks = False - else: - use_symlinks = True - - builder = EnvBuilder(with_pip=True, symlinks=use_symlinks) - build = builder.create - except ImportError: - # We fallback on virtualenv for Python 2.7 - from virtualenv import create_environment - - build = create_environment - - build(path) + else: + try: + from venv import EnvBuilder + + # use the same defaults as python -m venv + if os.name == "nt": + use_symlinks = False + else: + use_symlinks = True + + builder = EnvBuilder(with_pip=True, symlinks=use_symlinks) + build = builder.create + except ImportError: + # We fallback on virtualenv for Python 2.7 + from virtualenv import create_environment + + build = create_environment + + build(path) + + # update pip version + the_venv = VirtualEnv(Path(path)) + the_venv.run( + "python", + "-m", + "pip", + "install", + "--upgrade", + "pip>={},<={}".format(PIP_VERSION_MIN, PIP_VERSION_MAX), + ) def remove_venv(self, path): # type: (str) -> None shutil.rmtree(path) diff --git a/tests/utils/test_env.py b/tests/utils/test_env.py index e5926e68862..82a8ba71434 100644 --- a/tests/utils/test_env.py +++ b/tests/utils/test_env.py @@ -11,6 +11,7 @@ from poetry.semver import Version from poetry.utils._compat import WINDOWS from poetry.utils._compat import Path +from poetry.utils.env import PIP_VERSION_MAX from poetry.utils.env import EnvCommandError from poetry.utils.env import EnvManager from poetry.utils.env import NoCompatiblePythonVersionFound @@ -575,6 +576,11 @@ def test_run_with_input_non_zero_return(tmp_dir, tmp_venv): assert processError.value.e.returncode == 1 +def test_env_pip_version(tmp_dir, tmp_venv): + venv_pip_version = tmp_venv.run("pip", "-V", shell=True) + assert venv_pip_version.split()[:2] == ["pip", PIP_VERSION_MAX] + + def test_create_venv_tries_to_find_a_compatible_python_executable_using_generic_ones_first( manager, poetry, config, mocker ): From 2ef5a88ca4f5a8996d90d4602bd6d1b42b54a2a7 Mon Sep 17 00:00:00 2001 From: Tsvika Date: Wed, 5 Feb 2020 14:24:46 +0200 Subject: [PATCH 2/2] fix: failing venv creation on windows in windows, run() forces shell=True, which understand the < and > in the requirements as cmd operators. To prevent that, we encase the requirement in quotes, but this requires us to use shell=True in linux also. --- poetry/utils/env.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/poetry/utils/env.py b/poetry/utils/env.py index 01a45bcf168..7a74f713391 100644 --- a/poetry/utils/env.py +++ b/poetry/utils/env.py @@ -698,7 +698,8 @@ def build_venv(cls, path, executable=None): "pip", "install", "--upgrade", - "pip>={},<={}".format(PIP_VERSION_MIN, PIP_VERSION_MAX), + '"pip>={},<={}"'.format(PIP_VERSION_MIN, PIP_VERSION_MAX), + shell=True, ) def remove_venv(self, path): # type: (str) -> None