Skip to content

Commit f9918e1

Browse files
committed
Standardise on using virtualenv package
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.
1 parent 1598dff commit f9918e1

File tree

4 files changed

+25
-71
lines changed

4 files changed

+25
-71
lines changed

poetry.lock

Lines changed: 6 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

poetry/utils/env.py

Lines changed: 16 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@
1515
from typing import List
1616
from typing import Optional
1717
from typing import Tuple
18+
from typing import Union
1819

1920
import tomlkit
2021

2122
from clikit.api.io import IO
2223

2324
import packaging.tags
25+
import virtualenv
2426

2527
from packaging.tags import Tag
2628
from packaging.tags import interpreter_name
@@ -141,27 +143,6 @@ def _version_nodot(version):
141143
print(json.dumps(sysconfig.get_paths()))
142144
"""
143145

144-
CREATE_VENV_COMMAND = """\
145-
path = {!r}
146-
147-
try:
148-
from venv import EnvBuilder
149-
150-
builder = EnvBuilder(with_pip=True)
151-
builder.create(path)
152-
except ImportError:
153-
try:
154-
# We fallback on virtualenv for Python 2.7
155-
from virtualenv import create_environment
156-
157-
create_environment(path)
158-
except ImportError:
159-
# since virtualenv>20 we have to use cli_run
160-
from virtualenv import cli_run
161-
162-
cli_run([path])
163-
"""
164-
165146

166147
class EnvError(Exception):
167148

@@ -697,43 +678,20 @@ def create_venv(
697678
return VirtualEnv(venv)
698679

699680
@classmethod
700-
def build_venv(cls, path, executable=None):
701-
if executable is not None:
702-
# Create virtualenv by using an external executable
703-
try:
704-
p = subprocess.Popen(
705-
list_to_shell_command([executable, "-"]),
706-
stdin=subprocess.PIPE,
707-
shell=True,
708-
)
709-
p.communicate(encode(CREATE_VENV_COMMAND.format(path)))
710-
except CalledProcessError as e:
711-
raise EnvCommandError(e)
712-
713-
return
714-
715-
try:
716-
from venv import EnvBuilder
717-
718-
# use the same defaults as python -m venv
719-
if os.name == "nt":
720-
use_symlinks = False
721-
else:
722-
use_symlinks = True
723-
724-
builder = EnvBuilder(with_pip=True, symlinks=use_symlinks)
725-
builder.create(path)
726-
except ImportError:
727-
try:
728-
# We fallback on virtualenv for Python 2.7
729-
from virtualenv import create_environment
730-
731-
create_environment(path)
732-
except ImportError:
733-
# since virtualenv>20 we have to use cli_run
734-
from virtualenv import cli_run
735-
736-
cli_run([path])
681+
def build_venv(
682+
cls, path, executable=None
683+
): # type: (str, Optional[Union[str, Path]]) -> virtualenv.run.session.Session
684+
if isinstance(executable, Path):
685+
executable = executable.resolve()
686+
return virtualenv.cli_run(
687+
[
688+
"--no-download",
689+
"--no-periodic-update",
690+
"--python",
691+
executable or sys.executable,
692+
path,
693+
]
694+
)
737695

738696
def remove_venv(self, path): # type: (str) -> None
739697
shutil.rmtree(path)

pyproject.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ shellingham = "^1.1"
3838
tomlkit = "^0.5.11"
3939
pexpect = "^4.7.0"
4040
packaging = "^20.4"
41+
virtualenv = { version = "^20.0.26" }
4142

4243
# The typing module is not in the stdlib in Python 2.7
4344
typing = { version = "^3.6", python = "~2.7" }
@@ -48,8 +49,6 @@ pathlib2 = { version = "^2.3", python = "~2.7" }
4849
futures = { version = "^3.3.0", python = "~2.7" }
4950
# Use glob2 for Python 2.7 and 3.4
5051
glob2 = { version = "^0.6", python = "~2.7" }
51-
# Use virtualenv for Python 2.7 since venv does not exist
52-
virtualenv = { version = "^20.0.18", python = "~2.7" }
5352
# functools32 is needed for Python 2.7
5453
functools32 = { version = "^3.2.3", python = "~2.7" }
5554
keyring = [

tests/utils/test_env.py

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -535,17 +535,9 @@ def test_remove_also_deactivates(tmp_dir, manager, poetry, config, mocker):
535535
assert venv_name not in envs
536536

537537

538+
@pytest.mark.skipif(os.name == "nt", reason="Symlinks are not support for Windows")
538539
def test_env_has_symlinks_on_nix(tmp_dir, tmp_venv):
539-
venv_available = False
540-
try:
541-
from venv import EnvBuilder # noqa
542-
543-
venv_available = True
544-
except ImportError:
545-
pass
546-
547-
if os.name != "nt" and venv_available:
548-
assert os.path.islink(tmp_venv.python)
540+
assert os.path.islink(tmp_venv.python)
549541

550542

551543
def test_run_with_input(tmp_dir, tmp_venv):

0 commit comments

Comments
 (0)