Skip to content

Commit

Permalink
add config option to force --always-copy argument for virtualenv
Browse files Browse the repository at this point in the history
fix issue for showing all configs when options has more then two level
  • Loading branch information
finswimmer committed Oct 10, 2020
1 parent 6a96dd2 commit 5587ffd
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 25 deletions.
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

0 comments on commit 5587ffd

Please sign in to comment.