Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add config option to force --always-copy parameter for virtualenv #3157

Merged
merged 1 commit into from
Oct 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ which will give you something similar to this:
cache-dir = "/path/to/cache/directory"
virtualenvs.create = true
virtualenvs.in-project = null
virtualenvs.options.always-copy = true
virtualenvs.path = "{cache-dir}/virtualenvs" # /path/to/cache/directory/virtualenvs
```

Expand Down Expand Up @@ -128,6 +129,12 @@ If not set explicitly (default), `poetry` will use the virtualenv from the `.ven
Directory where virtual environments will be created.
Defaults to `{cache-dir}/virtualenvs` (`{cache-dir}\virtualenvs` on Windows).

### `virtualenvs.options.always-copy`: boolean

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.
Defaults to `false`.


### `repositories.<name>`: string

Set a new alternative repository. See [Repositories](/docs/repositories/) for more information.
19 changes: 16 additions & 3 deletions poetry/config/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class Config(object):
"create": True,
"in-project": None,
"path": os.path.join("{cache-dir}", "virtualenvs"),
"options": {"always-copy": False},
},
"experimental": {"new-installer": True},
}
Expand Down Expand Up @@ -87,7 +88,11 @@ def _all(config, parent_key=""):
for key in config:
value = self.get(parent_key + key)
if isinstance(value, dict):
all_[key] = _all(config[key], parent_key=key + ".")
if parent_key != "":
current_parent = parent_key + key + "."
else:
current_parent = key + "."
all_[key] = _all(config[key], parent_key=current_parent)
continue

all_[key] = value
Expand Down Expand Up @@ -131,14 +136,22 @@ def process(self, value): # type: (Any) -> Any
return re.sub(r"{(.+?)}", lambda m: self.get(m.group(1)), value)

def _get_validator(self, name): # type: (str) -> Callable
if name in {"virtualenvs.create", "virtualenvs.in-project"}:
if name in {
"virtualenvs.create",
"virtualenvs.in-project",
"virtualenvs.options.always-copy",
}:
return boolean_validator

if name == "virtualenvs.path":
return str

def _get_normalizer(self, name): # type: (str) -> Callable
if name in {"virtualenvs.create", "virtualenvs.in-project"}:
if name in {
"virtualenvs.create",
"virtualenvs.in-project",
"virtualenvs.options.always-copy",
}:
return boolean_normalizer

if name == "virtualenvs.path":
Expand Down
5 changes: 5 additions & 0 deletions poetry/console/commands/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ def unique_config_values(self):
boolean_normalizer,
True,
),
"virtualenvs.options.always-copy": (
boolean_validator,
boolean_normalizer,
False,
),
}

return unique_config_values
Expand Down
41 changes: 28 additions & 13 deletions poetry/utils/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -642,7 +642,11 @@ def create_venv(
"Creating virtualenv <c1>{}</> in {}".format(name, str(venv_path))
)

self.build_venv(venv, executable=executable)
self.build_venv(
venv,
executable=executable,
flags=self._poetry.config.get("virtualenvs.options"),
)
else:
if force:
if not env.is_sane():
Expand All @@ -655,7 +659,11 @@ def create_venv(
"Recreating virtualenv <c1>{}</> in {}".format(name, str(venv))
)
self.remove_venv(venv)
self.build_venv(venv, executable=executable)
self.build_venv(
venv,
executable=executable,
flags=self._poetry.config.get("virtualenvs.options"),
)
elif io.is_very_verbose():
io.write_line("Virtualenv <c1>{}</> already exists.".format(name))

Expand All @@ -679,19 +687,26 @@ def create_venv(

@classmethod
def build_venv(
cls, path, executable=None
): # type: (Union[Path,str], Optional[Union[str, Path]]) -> virtualenv.run.session.Session
cls, path, executable=None, flags=None
): # type: (Union[Path,str], Optional[Union[str, Path]], Dict[str, bool]) -> virtualenv.run.session.Session
flags = flags or {}

if isinstance(executable, Path):
executable = executable.resolve().as_posix()
return virtualenv.cli_run(
[
"--no-download",
"--no-periodic-update",
"--python",
executable or sys.executable,
str(path),
]
)

args = [
"--no-download",
"--no-periodic-update",
"--python",
executable or sys.executable,
str(path),
]

for flag, value in flags.items():
if value is True:
args.insert(0, "--{}".format(flag))

return virtualenv.cli_run(args)

@classmethod
def remove_venv(cls, path): # type: (Union[Path,str]) -> None
Expand Down
4 changes: 3 additions & 1 deletion tests/console/commands/env/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
from poetry.utils._compat import Path


def build_venv(path, executable=None): # type: (Union[Path,str], Optional[str]) -> ()
def build_venv(
path, executable=None, flags=None
): # type: (Union[Path,str], Optional[str], bool) -> ()
Path(path).mkdir(parents=True, exist_ok=True)


Expand Down
4 changes: 3 additions & 1 deletion tests/console/commands/env/test_use.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ def test_activate_activates_non_existing_virtualenv_no_envs_file(
tester.execute("3.7")

venv_py37 = venv_cache / "{}-py3.7".format(venv_name)
mock_build_env.assert_called_with(venv_py37, executable="python3.7")
mock_build_env.assert_called_with(
venv_py37, executable="python3.7", flags={"always-copy": False}
)

envs_file = TOMLFile(venv_cache / "envs.toml")
assert envs_file.exists()
Expand Down
3 changes: 3 additions & 0 deletions tests/console/commands/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ def test_list_displays_default_value_if_not_set(tester, config):
experimental.new-installer = true
virtualenvs.create = true
virtualenvs.in-project = null
virtualenvs.options.always-copy = false
virtualenvs.path = {path} # /foo{sep}virtualenvs
""".format(
path=json.dumps(os.path.join("{cache-dir}", "virtualenvs")), sep=os.path.sep
Expand All @@ -36,6 +37,7 @@ def test_list_displays_set_get_setting(tester, config):
experimental.new-installer = true
virtualenvs.create = false
virtualenvs.in-project = null
virtualenvs.options.always-copy = false
virtualenvs.path = {path} # /foo{sep}virtualenvs
""".format(
path=json.dumps(os.path.join("{cache-dir}", "virtualenvs")), sep=os.path.sep
Expand Down Expand Up @@ -75,6 +77,7 @@ def test_list_displays_set_get_local_setting(tester, config):
experimental.new-installer = true
virtualenvs.create = false
virtualenvs.in-project = null
virtualenvs.options.always-copy = false
virtualenvs.path = {path} # /foo{sep}virtualenvs
""".format(
path=json.dumps(os.path.join("{cache-dir}", "virtualenvs")), sep=os.path.sep
Expand Down
32 changes: 25 additions & 7 deletions tests/utils/test_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,9 @@ def test_env_get_venv_with_venv_folder_present(
assert venv.path == in_project_venv_dir


def build_venv(path, executable=None): # type: (Union[Path,str], Optional[str]) -> ()
def build_venv(
path, executable=None, flags=None
): # type: (Union[Path,str], Optional[str], bool) -> ()
os.mkdir(str(path))


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

m.assert_called_with(
Path(tmp_dir) / "{}-py3.7".format(venv_name), executable="python3.7"
Path(tmp_dir) / "{}-py3.7".format(venv_name),
executable="python3.7",
flags={"always-copy": False},
)

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

m.assert_called_with(
Path(tmp_dir) / "{}-py3.6".format(venv_name), executable="python3.6"
Path(tmp_dir) / "{}-py3.6".format(venv_name),
executable="python3.6",
flags={"always-copy": False},
)

assert envs_file.exists()
Expand Down Expand Up @@ -326,7 +332,9 @@ def test_activate_activates_recreates_for_different_patch(
env = manager.activate("python3.7", NullIO())

build_venv_m.assert_called_with(
Path(tmp_dir) / "{}-py3.7".format(venv_name), executable="python3.7"
Path(tmp_dir) / "{}-py3.7".format(venv_name),
executable="python3.7",
flags={"always-copy": False},
)
remove_venv_m.assert_called_with(Path(tmp_dir) / "{}-py3.7".format(venv_name))

Expand Down Expand Up @@ -654,7 +662,9 @@ def test_create_venv_tries_to_find_a_compatible_python_executable_using_generic_
manager.create_venv(NullIO())

m.assert_called_with(
Path("/foo/virtualenvs/{}-py3.7".format(venv_name)), executable="python3"
Path("/foo/virtualenvs/{}-py3.7".format(venv_name)),
executable="python3",
flags={"always-copy": False},
)


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

m.assert_called_with(
Path("/foo/virtualenvs/{}-py3.9".format(venv_name)), executable="python3.9"
Path("/foo/virtualenvs/{}-py3.9".format(venv_name)),
executable="python3.9",
flags={"always-copy": False},
)


Expand Down Expand Up @@ -767,6 +779,7 @@ def test_create_venv_uses_patch_version_to_detect_compatibility(
)
),
executable=None,
flags={"always-copy": False},
)


Expand Down Expand Up @@ -804,6 +817,7 @@ def test_create_venv_uses_patch_version_to_detect_compatibility_with_executable(
)
),
executable="python{}.{}".format(version.major, version.minor - 1),
flags={"always-copy": False},
)


Expand Down Expand Up @@ -834,7 +848,11 @@ def test_activate_with_in_project_setting_does_not_fail_if_no_venvs_dir(

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

m.assert_called_with(poetry.file.parent / ".venv", executable="python3.7")
m.assert_called_with(
poetry.file.parent / ".venv",
executable="python3.7",
flags={"always-copy": False},
)

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