Skip to content

Commit

Permalink
Add system-site-packages setting
Browse files Browse the repository at this point in the history
  • Loading branch information
kam1sh authored and wyl8899 committed Jul 19, 2020
1 parent d5a99f0 commit c0158e5
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 20 deletions.
6 changes: 6 additions & 0 deletions docs/docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,12 @@ Defaults to `true`.
Create the virtualenv inside the project's root directory.
Defaults to `false`.

### `virtualenvs.include-system-packages`: boolean

Give the virtual environment access to the system site-packages dir.
Defaults to `false`.


### `virtualenvs.path`: string

Directory where virtual environments will be created.
Expand Down
11 changes: 9 additions & 2 deletions poetry/config/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,18 @@ class Config(object):
"virtualenvs": {
"create": True,
"in-project": False,
"include-system-packages": False,
"path": os.path.join("{cache-dir}", "virtualenvs"),
},
"experimental": {"new-installer": True},
}

_boolean_settings = (
"virtualenvs.create",
"virtualenvs.in-project",
"virtualenvs.include-system-packages",
)

def __init__(
self, use_environment=True, base_dir=None
): # type: (bool, Optional[Path]) -> None
Expand Down Expand Up @@ -131,14 +138,14 @@ 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 self._boolean_settings:
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 self._boolean_settings:
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 @@ -52,6 +52,11 @@ def unique_config_values(self):
),
"virtualenvs.create": (boolean_validator, boolean_normalizer, True),
"virtualenvs.in-project": (boolean_validator, boolean_normalizer, False),
"virtualenvs.include-system-packages": (
boolean_validator,
boolean_normalizer,
False,
),
"virtualenvs.path": (
str,
lambda val: str(Path(val)),
Expand Down
38 changes: 24 additions & 14 deletions poetry/utils/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,9 @@ def create_venv(

create_venv = self._poetry.config.get("virtualenvs.create")
root_venv = self._poetry.config.get("virtualenvs.in-project")
include_system_packages = self._poetry.config.get(
"virtualenvs.include-system-packages"
)

venv_path = self._poetry.config.get("virtualenvs.path")
if root_venv:
Expand Down Expand Up @@ -627,6 +630,12 @@ def create_venv(
name = "{}-py{}".format(name, python_minor.strip())
venv = venv_path / name

def _build_venv():
extra_kwargs = {}
if include_system_packages is True:
extra_kwargs.update(include_system_packages=True)
self.build_venv(str(venv), executable=executable, **extra_kwargs)

if not venv.exists():
if create_venv is False:
io.write_line(
Expand All @@ -642,7 +651,7 @@ def create_venv(
"Creating virtualenv <c1>{}</> in {}".format(name, str(venv_path))
)

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

Expand All @@ -679,19 +688,20 @@ def create_venv(

@classmethod
def build_venv(
cls, path, executable=None
): # type: (str, Optional[Union[str, Path]]) -> virtualenv.run.session.Session
cls, path, executable=None, include_system_packages=False
): # type: (str, Optional[Union[str, Path]], bool) -> 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,
]
)

options = [
"--no-download",
"--no-periodic-update",
"--python",
executable or sys.executable,
]
if include_system_packages:
options.extend(["--system-site-packages"])
return virtualenv.cli_run([*options, path])

def remove_venv(self, path): # type: (str) -> None
shutil.rmtree(path)
Expand Down Expand Up @@ -883,7 +893,7 @@ def _run(self, cmd, **kwargs):
stderr=subprocess.STDOUT,
input=encode(input_),
check=True,
**kwargs
**kwargs,
).stdout
elif call:
return subprocess.call(cmd, stderr=subprocess.STDOUT, **kwargs)
Expand Down
2 changes: 1 addition & 1 deletion tests/console/commands/env/test_use.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
CWD = Path(__file__).parent.parent / "fixtures" / "simple_project"


def build_venv(path, executable=None):
def build_venv(path, executable=None, include_system_packages=False):
os.mkdir(path)


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 @@ -16,6 +16,7 @@ def test_list_displays_default_value_if_not_set(app, config):
experimental.new-installer = true
virtualenvs.create = true
virtualenvs.in-project = false
virtualenvs.include-system-packages = 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(app, config):
experimental.new-installer = true
virtualenvs.create = false
virtualenvs.in-project = false
virtualenvs.include-system-packages = 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 @@ -84,6 +86,7 @@ def test_list_displays_set_get_local_setting(app, config):
experimental.new-installer = true
virtualenvs.create = false
virtualenvs.in-project = false
virtualenvs.include-system-packages = false
virtualenvs.path = {path} # /foo{sep}virtualenvs
""".format(
path=json.dumps(os.path.join("{cache-dir}", "virtualenvs")), sep=os.path.sep
Expand Down
5 changes: 3 additions & 2 deletions tests/test_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,5 +204,6 @@ def test_create_poetry_fails_on_invalid_configuration():
def test_create_poetry_with_local_config(fixture_dir):
poetry = Factory().create_poetry(fixture_dir("with_local_config"))

assert not poetry.config.get("virtualenvs.in-project")
assert not poetry.config.get("virtualenvs.create")
assert poetry.config.get("virtualenvs.in-project") is False
assert poetry.config.get("virtualenvs.create") is False
assert poetry.config.get("virtualenvs.include-system-packages") is False
14 changes: 13 additions & 1 deletion tests/utils/test_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def test_env_get_in_project_venv(manager, poetry):
shutil.rmtree(str(venv.path))


def build_venv(path, executable=None):
def build_venv(path, executable=None, include_system_packages=False):
os.mkdir(path)


Expand Down Expand Up @@ -536,6 +536,18 @@ def test_remove_also_deactivates(tmp_dir, manager, poetry, config, mocker):
assert venv_name not in envs


def test_env_system_packages(tmp_dir, config):
venv_path = Path(tmp_dir) / "venv"
EnvManager(config).build_venv(str(venv_path), include_system_packages=True)
pyvenv_cfg = venv_path / "pyvenv.cfg"
if sys.version_info >= (3, 3):
assert "include-system-site-packages = true" in pyvenv_cfg.read_text()
elif (2, 6) < sys.version_info < (3, 0):
assert not venv_path.joinpath(
"lib", "python2.7", "no-global-site-packages.txt"
).exists()


@pytest.mark.skipif(
os.name == "nt" or PY2, reason="Symlinks are not support for Windows"
)
Expand Down

0 comments on commit c0158e5

Please sign in to comment.