More granular control over PIPENV_VENV_IN_PROJECT variable. (#5026)

* Allow PIPENV_VENV_IN_PROJECT to be read in as None, and ensure if it is set to False that it does not use .venv directory.

* refactor based on PR feedback and add news fragment.

* Review unit test coverage and add new tests.  Remove unneccesary bits from other tests.
This commit is contained in:
Matt Davis
2022-04-06 15:10:05 -04:00
committed by GitHub
parent 99cf729dd5
commit 949ee95d67
7 changed files with 54 additions and 21 deletions
+2
View File
@@ -0,0 +1,2 @@
Pipenv will now ignore ``.venv`` in the project when ``PIPENV_VENV_IN_PROJECT`` variable is False.
Unset variable maintains the existing behavior of preferring to use the project's ``.venv`` should it exist.
-1
View File
@@ -1 +0,0 @@
Internal to pipenv, the utils.py was split into a utils module with unused code removed.
+12 -4
View File
@@ -297,10 +297,18 @@ class Setting:
Default is 120 seconds, an arbitrary number that seems to work.
"""
self.PIPENV_VENV_IN_PROJECT = bool(os.environ.get("PIPENV_VENV_IN_PROJECT"))
"""If set, creates ``.venv`` in your project directory.
Default is to create new virtual environments in a global location.
self.PIPENV_VENV_IN_PROJECT = os.environ.get("PIPENV_VENV_IN_PROJECT")
if self.PIPENV_VENV_IN_PROJECT is not None:
if self.PIPENV_VENV_IN_PROJECT.lower() in _true_values:
self.PIPENV_VENV_IN_PROJECT = True
elif self.PIPENV_VENV_IN_PROJECT.lower() in _false_values:
self.PIPENV_VENV_IN_PROJECT = False
else:
self.PIPENV_VENV_IN_PROJECT = None
""" When set True, will create or use the ``.venv`` in your project directory.
When Set False, will ignore the .venv in your project directory even if it exists.
Default is None will use the .venv of project directory should it exist, otherwise
will create new virtual environments in a global location.
"""
self.PIPENV_VERBOSE = bool(os.environ.get("PIPENV_VERBOSE"))
+3 -1
View File
@@ -242,6 +242,8 @@ class Project:
def is_venv_in_project(self):
# type: () -> bool
if self.s.PIPENV_VENV_IN_PROJECT is False:
return False
return self.s.PIPENV_VENV_IN_PROJECT or (
self.project_directory
and os.path.isdir(os.path.join(self.project_directory, ".venv"))
@@ -288,7 +290,7 @@ class Project:
return str(get_workon_home().joinpath(self.virtualenv_name))
# If content looks like a path, use it as a relative path.
# Otherwise use directory named after content in WORKON_HOME.
# Otherwise, use directory named after content in WORKON_HOME.
if looks_like_dir(name):
path = Path(self.project_directory, name)
return path.absolute().as_posix()
+37 -8
View File
@@ -7,13 +7,15 @@ from tempfile import TemporaryDirectory
import pytest
from pipenv.environments import _true_values, _false_values
from pipenv.utils.shell import normalize_drive, temp_environ
@pytest.mark.dotvenv
def test_venv_in_project(PipenvInstance):
@pytest.mark.parametrize("true_value", _true_values)
def test_venv_in_project(true_value, PipenvInstance):
with temp_environ():
os.environ['PIPENV_VENV_IN_PROJECT'] = '1'
os.environ['PIPENV_VENV_IN_PROJECT'] = true_value
with PipenvInstance() as p:
c = p.pipenv('install requests')
assert c.returncode == 0
@@ -21,10 +23,38 @@ def test_venv_in_project(PipenvInstance):
@pytest.mark.dotvenv
def test_venv_at_project_root(PipenvInstance):
@pytest.mark.parametrize("false_value", _false_values)
def test_venv_in_project_disabled_ignores_venv(false_value, PipenvInstance):
venv_name = "my_project"
with temp_environ():
os.environ['PIPENV_VENV_IN_PROJECT'] = false_value
with PipenvInstance() as p:
file_path = os.path.join(p.path, '.venv')
with open(file_path, 'w') as f:
f.write(venv_name)
with temp_environ(), TemporaryDirectory(
prefix='pipenv-', suffix='temp_workon_home'
) as workon_home:
os.environ['WORKON_HOME'] = workon_home
c = p.pipenv('install requests')
assert c.returncode == 0
c = p.pipenv('--venv')
assert c.returncode == 0
venv_loc = Path(c.stdout.strip()).absolute()
assert venv_loc.exists()
assert venv_loc.joinpath('.project').exists()
venv_path = normalize_drive(venv_loc.as_posix())
venv_expected_path = Path(workon_home).joinpath(venv_name).absolute().as_posix()
assert venv_path == normalize_drive(venv_expected_path)
@pytest.mark.dotvenv
@pytest.mark.parametrize("true_value", _true_values)
def test_venv_at_project_root(true_value, PipenvInstance):
with temp_environ():
with PipenvInstance(chdir=True) as p:
os.environ['PIPENV_VENV_IN_PROJECT'] = '1'
os.environ['PIPENV_VENV_IN_PROJECT'] = true_value
c = p.pipenv('install')
assert c.returncode == 0
assert normalize_drive(p.path) in p.pipenv('--venv').stdout
@@ -80,7 +110,7 @@ def test_venv_file(venv_name, PipenvInstance):
@pytest.mark.dotvenv
def test_empty_venv_file(PipenvInstance):
"""Tests virtualenv creation when a empty .venv file exists at the project root
"""Tests virtualenv creation when an empty .venv file exists at the project root
"""
with PipenvInstance(chdir=True) as p:
file_path = os.path.join(p.path, '.venv')
@@ -109,9 +139,8 @@ def test_empty_venv_file(PipenvInstance):
@pytest.mark.dotvenv
def test_venv_file_with_path(PipenvInstance):
"""Tests virtualenv creation when a .venv file exists at the project root
and contains an absolute path.
def test_venv_in_project_default_when_venv_exists(PipenvInstance):
"""Tests virtualenv creation when a .venv file exists at the project root.
"""
with temp_environ(), PipenvInstance(chdir=True) as p:
with TemporaryDirectory(
-2
View File
@@ -405,8 +405,6 @@ def test_install_venv_project_directory(PipenvInstance):
prefix="pipenv-", suffix="temp_workon_home"
) as workon_home:
os.environ["WORKON_HOME"] = workon_home
if "PIPENV_VENV_IN_PROJECT" in os.environ:
del os.environ["PIPENV_VENV_IN_PROJECT"]
c = p.pipenv("install six")
assert c.returncode == 0
-5
View File
@@ -92,14 +92,9 @@ def test_proper_names_unamanged_virtualenv(PipenvInstance):
def test_directory_with_leading_dash(raw_venv, PipenvInstance):
with temp_environ():
with PipenvInstance(chdir=True, venv_in_project=False, name="-project-with-dash") as p:
if "PIPENV_VENV_IN_PROJECT" in os.environ:
del os.environ['PIPENV_VENV_IN_PROJECT']
c = p.pipenv('run pip freeze')
assert c.returncode == 0
c = p.pipenv('--venv')
assert c.returncode == 0
venv_path = c.stdout.strip()
assert os.path.isdir(venv_path)
# Manually clean up environment, since PipenvInstance assumes that
# the virutalenv is in the project directory.
p.pipenv('--rm')