Skip to content

Commit a5ae42f

Browse files
committed
add config option to force --always-copy argument for virtualenv
1 parent 6a96dd2 commit a5ae42f

File tree

8 files changed

+66
-22
lines changed

8 files changed

+66
-22
lines changed

docs/docs/configuration.md

+7
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ cache-dir = "/path/to/cache/directory"
3535
virtualenvs.create = true
3636
virtualenvs.in-project = null
3737
virtualenvs.path = "{cache-dir}/virtualenvs" # /path/to/cache/directory/virtualenvs
38+
virtualenvs.always-copy = true
3839
```
3940

4041
## Displaying a single configuration setting
@@ -128,6 +129,12 @@ If not set explicitly (default), `poetry` will use the virtualenv from the `.ven
128129
Directory where virtual environments will be created.
129130
Defaults to `{cache-dir}/virtualenvs` (`{cache-dir}\virtualenvs` on Windows).
130131

132+
### `virtualenvs.always-copy`: boolean
133+
134+
If set to `true` the `--always-copy` parameter is passed to `virtualenv` on creation of the venv. Thus all needed files are copied into the venv instead of symlinked.
135+
Defaults to `false`.
136+
137+
131138
### `repositories.<name>`: string
132139

133140
Set a new alternative repository. See [Repositories](/docs/repositories/) for more information.

poetry/config/config.py

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class Config(object):
3636
"create": True,
3737
"in-project": None,
3838
"path": os.path.join("{cache-dir}", "virtualenvs"),
39+
"always-copy": False,
3940
},
4041
"experimental": {"new-installer": True},
4142
}

poetry/console/commands/config.py

+1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ def unique_config_values(self):
5858
lambda val: str(Path(val)),
5959
str(Path(CACHE_DIR) / "virtualenvs"),
6060
),
61+
"virtualenvs.always-copy": (boolean_validator, boolean_normalizer, False),
6162
"experimental.new-installer": (
6263
boolean_validator,
6364
boolean_normalizer,

poetry/utils/env.py

+25-13
Original file line numberDiff line numberDiff line change
@@ -642,7 +642,11 @@ def create_venv(
642642
"Creating virtualenv <c1>{}</> in {}".format(name, str(venv_path))
643643
)
644644

645-
self.build_venv(venv, executable=executable)
645+
self.build_venv(
646+
venv,
647+
executable=executable,
648+
always_copy=self._poetry.config.get("virtualenvs.always-copy"),
649+
)
646650
else:
647651
if force:
648652
if not env.is_sane():
@@ -655,7 +659,11 @@ def create_venv(
655659
"Recreating virtualenv <c1>{}</> in {}".format(name, str(venv))
656660
)
657661
self.remove_venv(venv)
658-
self.build_venv(venv, executable=executable)
662+
self.build_venv(
663+
venv,
664+
executable=executable,
665+
always_copy=self._poetry.config.get("virtualenvs.always-copy"),
666+
)
659667
elif io.is_very_verbose():
660668
io.write_line("Virtualenv <c1>{}</> already exists.".format(name))
661669

@@ -679,19 +687,23 @@ def create_venv(
679687

680688
@classmethod
681689
def build_venv(
682-
cls, path, executable=None
683-
): # type: (Union[Path,str], Optional[Union[str, Path]]) -> virtualenv.run.session.Session
690+
cls, path, executable=None, always_copy=False
691+
): # type: (Union[Path,str], Optional[Union[str, Path]], bool) -> virtualenv.run.session.Session
684692
if isinstance(executable, Path):
685693
executable = executable.resolve().as_posix()
686-
return virtualenv.cli_run(
687-
[
688-
"--no-download",
689-
"--no-periodic-update",
690-
"--python",
691-
executable or sys.executable,
692-
str(path),
693-
]
694-
)
694+
695+
args = [
696+
"--no-download",
697+
"--no-periodic-update",
698+
"--python",
699+
executable or sys.executable,
700+
str(path),
701+
]
702+
703+
if always_copy:
704+
args.insert(0, "--always-copy")
705+
706+
return virtualenv.cli_run(args)
695707

696708
@classmethod
697709
def remove_venv(cls, path): # type: (Union[Path,str]) -> None

tests/console/commands/env/helpers.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
from poetry.utils._compat import Path
66

77

8-
def build_venv(path, executable=None): # type: (Union[Path,str], Optional[str]) -> ()
8+
def build_venv(
9+
path, executable=None, always_copy=False
10+
): # type: (Union[Path,str], Optional[str], bool) -> ()
911
Path(path).mkdir(parents=True, exist_ok=True)
1012

1113

tests/console/commands/env/test_use.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@ def test_activate_activates_non_existing_virtualenv_no_envs_file(
5050
tester.execute("3.7")
5151

5252
venv_py37 = venv_cache / "{}-py3.7".format(venv_name)
53-
mock_build_env.assert_called_with(venv_py37, executable="python3.7")
53+
mock_build_env.assert_called_with(
54+
venv_py37, executable="python3.7", always_copy=False
55+
)
5456

5557
envs_file = TOMLFile(venv_cache / "envs.toml")
5658
assert envs_file.exists()

tests/console/commands/test_config.py

+3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ def test_list_displays_default_value_if_not_set(tester, config):
1717

1818
expected = """cache-dir = "/foo"
1919
experimental.new-installer = true
20+
virtualenvs.always-copy = false
2021
virtualenvs.create = true
2122
virtualenvs.in-project = null
2223
virtualenvs.path = {path} # /foo{sep}virtualenvs
@@ -34,6 +35,7 @@ def test_list_displays_set_get_setting(tester, config):
3435

3536
expected = """cache-dir = "/foo"
3637
experimental.new-installer = true
38+
virtualenvs.always-copy = false
3739
virtualenvs.create = false
3840
virtualenvs.in-project = null
3941
virtualenvs.path = {path} # /foo{sep}virtualenvs
@@ -73,6 +75,7 @@ def test_list_displays_set_get_local_setting(tester, config):
7375

7476
expected = """cache-dir = "/foo"
7577
experimental.new-installer = true
78+
virtualenvs.always-copy = false
7679
virtualenvs.create = false
7780
virtualenvs.in-project = null
7881
virtualenvs.path = {path} # /foo{sep}virtualenvs

tests/utils/test_env.py

+23-7
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,9 @@ def test_env_get_venv_with_venv_folder_present(
118118
assert venv.path == in_project_venv_dir
119119

120120

121-
def build_venv(path, executable=None): # type: (Union[Path,str], Optional[str]) -> ()
121+
def build_venv(
122+
path, executable=None, always_copy=False
123+
): # type: (Union[Path,str], Optional[str], bool) -> ()
122124
os.mkdir(str(path))
123125

124126

@@ -156,7 +158,9 @@ def test_activate_activates_non_existing_virtualenv_no_envs_file(
156158
venv_name = EnvManager.generate_env_name("simple-project", str(poetry.file.parent))
157159

158160
m.assert_called_with(
159-
Path(tmp_dir) / "{}-py3.7".format(venv_name), executable="python3.7"
161+
Path(tmp_dir) / "{}-py3.7".format(venv_name),
162+
executable="python3.7",
163+
always_copy=False,
160164
)
161165

162166
envs_file = TOMLFile(Path(tmp_dir) / "envs.toml")
@@ -274,7 +278,9 @@ def test_activate_activates_different_virtualenv_with_envs_file(
274278
env = manager.activate("python3.6", NullIO())
275279

276280
m.assert_called_with(
277-
Path(tmp_dir) / "{}-py3.6".format(venv_name), executable="python3.6"
281+
Path(tmp_dir) / "{}-py3.6".format(venv_name),
282+
executable="python3.6",
283+
always_copy=False,
278284
)
279285

280286
assert envs_file.exists()
@@ -326,7 +332,9 @@ def test_activate_activates_recreates_for_different_patch(
326332
env = manager.activate("python3.7", NullIO())
327333

328334
build_venv_m.assert_called_with(
329-
Path(tmp_dir) / "{}-py3.7".format(venv_name), executable="python3.7"
335+
Path(tmp_dir) / "{}-py3.7".format(venv_name),
336+
executable="python3.7",
337+
always_copy=False,
330338
)
331339
remove_venv_m.assert_called_with(Path(tmp_dir) / "{}-py3.7".format(venv_name))
332340

@@ -654,7 +662,9 @@ def test_create_venv_tries_to_find_a_compatible_python_executable_using_generic_
654662
manager.create_venv(NullIO())
655663

656664
m.assert_called_with(
657-
Path("/foo/virtualenvs/{}-py3.7".format(venv_name)), executable="python3"
665+
Path("/foo/virtualenvs/{}-py3.7".format(venv_name)),
666+
executable="python3",
667+
always_copy=False,
658668
)
659669

660670

@@ -678,7 +688,9 @@ def test_create_venv_tries_to_find_a_compatible_python_executable_using_specific
678688
manager.create_venv(NullIO())
679689

680690
m.assert_called_with(
681-
Path("/foo/virtualenvs/{}-py3.9".format(venv_name)), executable="python3.9"
691+
Path("/foo/virtualenvs/{}-py3.9".format(venv_name)),
692+
executable="python3.9",
693+
always_copy=False,
682694
)
683695

684696

@@ -767,6 +779,7 @@ def test_create_venv_uses_patch_version_to_detect_compatibility(
767779
)
768780
),
769781
executable=None,
782+
always_copy=False,
770783
)
771784

772785

@@ -804,6 +817,7 @@ def test_create_venv_uses_patch_version_to_detect_compatibility_with_executable(
804817
)
805818
),
806819
executable="python{}.{}".format(version.major, version.minor - 1),
820+
always_copy=False,
807821
)
808822

809823

@@ -834,7 +848,9 @@ def test_activate_with_in_project_setting_does_not_fail_if_no_venvs_dir(
834848

835849
manager.activate("python3.7", NullIO())
836850

837-
m.assert_called_with(poetry.file.parent / ".venv", executable="python3.7")
851+
m.assert_called_with(
852+
poetry.file.parent / ".venv", executable="python3.7", always_copy=False
853+
)
838854

839855
envs_file = TOMLFile(Path(tmp_dir) / "virtualenvs" / "envs.toml")
840856
assert not envs_file.exists()

0 commit comments

Comments
 (0)