Skip to content

Commit

Permalink
Standardise on using virtualenv package (#2666)
Browse files Browse the repository at this point in the history
Until now poetry used the built-in venv module available in Python 3.
This has presented a few concerns. Chief of which has been
inconsistent environment setup. This includes, but is not limited to,
pip version used by the `ensurepip` module which is in turn used by the
built-in `venv.EnvBuilder`. Additionally, the `virtualenv` package
allows for faster environment creation. This can also allow us to, going
forward, drop ad-hoc code required to inspect and manage environments.
  • Loading branch information
abn authored Jul 14, 2020
1 parent 46dd1d7 commit d5a99f0
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 71 deletions.
7 changes: 6 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

74 changes: 16 additions & 58 deletions poetry/utils/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@
from typing import List
from typing import Optional
from typing import Tuple
from typing import Union

import tomlkit

from clikit.api.io import IO

import packaging.tags
import virtualenv

from packaging.tags import Tag
from packaging.tags import interpreter_name
Expand Down Expand Up @@ -141,27 +143,6 @@ def _version_nodot(version):
print(json.dumps(sysconfig.get_paths()))
"""

CREATE_VENV_COMMAND = """\
path = {!r}
try:
from venv import EnvBuilder
builder = EnvBuilder(with_pip=True)
builder.create(path)
except ImportError:
try:
# We fallback on virtualenv for Python 2.7
from virtualenv import create_environment
create_environment(path)
except ImportError:
# since virtualenv>20 we have to use cli_run
from virtualenv import cli_run
cli_run([path])
"""


class EnvError(Exception):

Expand Down Expand Up @@ -697,43 +678,20 @@ def create_venv(
return VirtualEnv(venv)

@classmethod
def build_venv(cls, path, executable=None):
if executable is not None:
# Create virtualenv by using an external executable
try:
p = subprocess.Popen(
list_to_shell_command([executable, "-"]),
stdin=subprocess.PIPE,
shell=True,
)
p.communicate(encode(CREATE_VENV_COMMAND.format(path)))
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)
builder.create(path)
except ImportError:
try:
# We fallback on virtualenv for Python 2.7
from virtualenv import create_environment

create_environment(path)
except ImportError:
# since virtualenv>20 we have to use cli_run
from virtualenv import cli_run

cli_run([path])
def build_venv(
cls, path, executable=None
): # type: (str, Optional[Union[str, Path]]) -> virtualenv.run.session.Session
if isinstance(executable, Path):
executable = executable.resolve()
return virtualenv.cli_run(
[
"--no-download",
"--no-periodic-update",
"--python",
executable or sys.executable,
path,
]
)

def remove_venv(self, path): # type: (str) -> None
shutil.rmtree(path)
Expand Down
3 changes: 1 addition & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ shellingham = "^1.1"
tomlkit = "^0.5.11"
pexpect = "^4.7.0"
packaging = "^20.4"
virtualenv = { version = "^20.0.26" }

# The typing module is not in the stdlib in Python 2.7
typing = { version = "^3.6", python = "~2.7" }
Expand All @@ -48,8 +49,6 @@ pathlib2 = { version = "^2.3", python = "~2.7" }
futures = { version = "^3.3.0", python = "~2.7" }
# Use glob2 for Python 2.7 and 3.4
glob2 = { version = "^0.6", python = "~2.7" }
# Use virtualenv for Python 2.7 since venv does not exist
virtualenv = { version = "^20.0.18", python = "~2.7" }
# functools32 is needed for Python 2.7
functools32 = { version = "^3.2.3", python = "~2.7" }
keyring = [
Expand Down
15 changes: 5 additions & 10 deletions tests/utils/test_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

from poetry.core.semver import Version
from poetry.factory import Factory
from poetry.utils._compat import PY2
from poetry.utils._compat import Path
from poetry.utils.env import EnvCommandError
from poetry.utils.env import EnvManager
Expand Down Expand Up @@ -535,17 +536,11 @@ def test_remove_also_deactivates(tmp_dir, manager, poetry, config, mocker):
assert venv_name not in envs


@pytest.mark.skipif(
os.name == "nt" or PY2, reason="Symlinks are not support for Windows"
)
def test_env_has_symlinks_on_nix(tmp_dir, tmp_venv):
venv_available = False
try:
from venv import EnvBuilder # noqa

venv_available = True
except ImportError:
pass

if os.name != "nt" and venv_available:
assert os.path.islink(tmp_venv.python)
assert os.path.islink(tmp_venv.python)


def test_run_with_input(tmp_dir, tmp_venv):
Expand Down

0 comments on commit d5a99f0

Please sign in to comment.