replace pyvenv with builtin venv

This commit is contained in:
Tyler Levy Conde 2024-06-27 16:25:53 -06:00 committed by Daniel Wozniak
parent 28d144aa46
commit bb26d8c97c
2 changed files with 117 additions and 53 deletions

View file

@ -27,7 +27,10 @@ KNOWN_BINARY_NAMES = frozenset(
log = logging.getLogger(__name__)
__opts__ = {"venv_bin": salt.utils.path.which_bin(KNOWN_BINARY_NAMES) or "virtualenv"}
__opts__ = {
"venv_bin": salt.utils.path.which_bin(KNOWN_BINARY_NAMES)
or f"{sys.executable} -m venv"
}
__pillar__ = {}
@ -82,6 +85,8 @@ def create(
never_download=None,
prompt=None,
pip=False,
symlinks=None,
upgrade=None,
user=None,
use_vt=False,
saltenv="base",
@ -99,7 +104,7 @@ def create(
Defaults to ``virtualenv``.
system_site_packages : False
Passthrough argument given to virtualenv
Passthrough argument given to virtualenv or venv
distribute : False
Passthrough argument given to virtualenv
@ -109,7 +114,7 @@ def create(
``distribute=True``
clear : False
Passthrough argument given to virtualenv
Passthrough argument given to virtualenv or venv
python : None (default)
Passthrough argument given to virtualenv
@ -123,6 +128,12 @@ def create(
prompt : None (default)
Passthrough argument given to virtualenv if not None
symlinks : None
Passthrough argument given to venv if True
upgrade : None
Passthrough argument given to venv if True
user : None
Set ownership for the virtualenv
@ -165,47 +176,98 @@ def create(
- env:
- VIRTUALENV_ALWAYS_COPY: 1
"""
# TODO venv_bin can be "sys.executable -m venv"
if venv_bin is None:
venv_bin = __opts__.get("venv_bin") or __pillar__.get("venv_bin")
venv_bin = __pillar__.get("venv_bin") or __opts__.get("venv_bin")
cmd = [venv_bin]
virtualenv_version_info = virtualenv_ver(venv_bin, user=user, **kwargs)
if distribute:
if virtualenv_version_info >= (1, 10):
log.info(
"The virtualenv '--distribute' option has been "
"deprecated in virtualenv(>=1.10), as such, the "
"'distribute' option to `virtualenv.create()` has "
"also been deprecated and it's not necessary anymore."
if "venv" not in venv_bin:
# ----- Stop the user if venv only options are used ----------------->
# If any of the following values are not None, it means that the user
# is actually passing a True or False value. Stop Him!
if upgrade is not None:
raise CommandExecutionError(
"The `upgrade`(`--upgrade`) option is not supported by '{}'".format(
venv_bin
)
)
else:
cmd.append("--distribute")
if python is not None and python.strip() != "":
if not salt.utils.path.which(python):
raise CommandExecutionError(f"Cannot find requested python ({python}).")
cmd.append(f"--python={python}")
if extra_search_dir is not None:
if isinstance(extra_search_dir, str) and extra_search_dir.strip() != "":
extra_search_dir = [e.strip() for e in extra_search_dir.split(",")]
for entry in extra_search_dir:
cmd.append(f"--extra-search-dir={entry}")
if never_download is True:
if (1, 10) <= virtualenv_version_info < (14, 0, 0):
log.info(
"--never-download was deprecated in 1.10.0, but reimplemented in"
" 14.0.0. If this feature is needed, please install a supported"
" virtualenv version."
elif symlinks is not None:
raise CommandExecutionError(
"The `symlinks`(`--symlinks`) option is not supported by '{}'".format(
venv_bin
)
)
else:
cmd.append("--never-download")
if prompt is not None and prompt.strip() != "":
cmd.append(f"--prompt='{prompt}'")
# <---- Stop the user if venv only options are used ------------------
# Common options to virtualenv
virtualenv_version_info = virtualenv_ver(venv_bin, user=user, **kwargs)
if distribute:
if virtualenv_version_info >= (1, 10):
log.info(
"The virtualenv '--distribute' option has been "
"deprecated in virtualenv(>=1.10), as such, the "
"'distribute' option to `virtualenv.create()` has "
"also been deprecated and it's not necessary anymore."
)
else:
cmd.append("--distribute")
if python is not None and python.strip() != "":
if not salt.utils.path.which(python):
raise CommandExecutionError(f"Cannot find requested python ({python}).")
cmd.append(f"--python={python}")
if extra_search_dir is not None:
if isinstance(extra_search_dir, str) and extra_search_dir.strip() != "":
extra_search_dir = [e.strip() for e in extra_search_dir.split(",")]
for entry in extra_search_dir:
cmd.append(f"--extra-search-dir={entry}")
if never_download is True:
if (1, 10) <= virtualenv_version_info < (14, 0, 0):
log.info(
"--never-download was deprecated in 1.10.0, but reimplemented in"
" 14.0.0. If this feature is needed, please install a supported"
" virtualenv version."
)
else:
cmd.append("--never-download")
if prompt is not None and prompt.strip() != "":
cmd.append(f"--prompt='{prompt}'")
else:
# venv module from the Python >= 3.3 standard library
# ----- Stop the user if virtualenv only options are being used ----->
# If any of the following values are not None, it means that the user
# is actually passing a True or False value. Stop Him!
if python is not None and python.strip() != "":
raise CommandExecutionError(
"The `python`(`--python`) option is not supported by '{}'".format(
venv_bin
)
)
elif extra_search_dir is not None and extra_search_dir.strip() != "":
raise CommandExecutionError(
"The `extra_search_dir`(`--extra-search-dir`) option is not "
"supported by '{}'".format(venv_bin)
)
elif never_download is not None:
raise CommandExecutionError(
"The `never_download`(`--never-download`) option is not "
"supported by '{}'".format(venv_bin)
)
elif prompt is not None and prompt.strip() != "":
raise CommandExecutionError(
"The `prompt`(`--prompt`) option is not supported by '{}'".format(
venv_bin
)
)
# <---- Stop the user if virtualenv only options are being used ------
if upgrade is True:
cmd.append("--upgrade")
if symlinks is True:
cmd.append("--symlinks")
# Common options to virtualenv and venv
if clear is True:
cmd.append("--clear")
if system_site_packages is True:

View file

@ -17,6 +17,8 @@ from tests.support.mixins import LoaderModuleMockMixin
from tests.support.mock import MagicMock, patch
from tests.support.unit import TestCase
VENV_BIN = f"{sys.executable} -m venv"
class VirtualenvTestCase(TestCase, LoaderModuleMockMixin):
def setup_loader_modules(self):
@ -146,7 +148,7 @@ class VirtualenvTestCase(TestCase, LoaderModuleMockMixin):
)
def test_unapplicable_options(self):
# ----- Virtualenv using pyvenv options ----------------------------->
# ----- Virtualenv using venv options ------------------------------->
mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
with patch.dict(virtualenv_mod.__salt__, {"cmd.run_all": mock}):
self.assertRaises(
@ -166,19 +168,19 @@ class VirtualenvTestCase(TestCase, LoaderModuleMockMixin):
venv_bin="virtualenv",
symlinks=True,
)
# <---- Virtualenv using pyvenv options ------------------------------
# <---- Virtualenv using venv options --------------------------------
# ----- pyvenv using virtualenv options ----------------------------->
# ----- venv using virtualenv options ------------------------------->
mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
with patch.dict(
virtualenv_mod.__salt__,
{"cmd.run_all": mock, "cmd.which_bin": lambda _: "pyvenv"},
{"cmd.run_all": mock, "cmd.which_bin": lambda _: VENV_BIN},
):
self.assertRaises(
CommandExecutionError,
virtualenv_mod.create,
"/tmp/foo",
venv_bin="pyvenv",
venv_bin=VENV_BIN,
python="python2.7",
)
@ -187,7 +189,7 @@ class VirtualenvTestCase(TestCase, LoaderModuleMockMixin):
CommandExecutionError,
virtualenv_mod.create,
"/tmp/foo",
venv_bin="pyvenv",
venv_bin=VENV_BIN,
prompt="PY Prompt",
)
@ -196,7 +198,7 @@ class VirtualenvTestCase(TestCase, LoaderModuleMockMixin):
CommandExecutionError,
virtualenv_mod.create,
"/tmp/foo",
venv_bin="pyvenv",
venv_bin=VENV_BIN,
never_download=True,
)
@ -205,10 +207,10 @@ class VirtualenvTestCase(TestCase, LoaderModuleMockMixin):
CommandExecutionError,
virtualenv_mod.create,
"/tmp/foo",
venv_bin="pyvenv",
venv_bin=VENV_BIN,
extra_search_dir="/tmp/bar",
)
# <---- pyvenv using virtualenv options ------------------------------
# <---- venv using virtualenv options --------------------------------
def test_get_virtualenv_version_from_shell(self):
with ForceImportErrorOn("virtualenv"):
@ -321,30 +323,30 @@ class VirtualenvTestCase(TestCase, LoaderModuleMockMixin):
)
def test_upgrade_argument(self):
# We test for pyvenv only because with virtualenv this is un
# We test for venv only because with virtualenv this is un
# unsupported option.
mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
with patch.dict(virtualenv_mod.__salt__, {"cmd.run_all": mock}):
virtualenv_mod.create("/tmp/foo", venv_bin="pyvenv", upgrade=True)
virtualenv_mod.create("/tmp/foo", venv_bin=VENV_BIN, upgrade=True)
mock.assert_called_once_with(
["pyvenv", "--upgrade", "/tmp/foo"], runas=None, python_shell=False
[VENV_BIN, "--upgrade", "/tmp/foo"], runas=None, python_shell=False
)
def test_symlinks_argument(self):
# We test for pyvenv only because with virtualenv this is un
# We test for venv only because with virtualenv this is un
# unsupported option.
mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
with patch.dict(virtualenv_mod.__salt__, {"cmd.run_all": mock}):
virtualenv_mod.create("/tmp/foo", venv_bin="pyvenv", symlinks=True)
virtualenv_mod.create("/tmp/foo", venv_bin=VENV_BIN, symlinks=True)
mock.assert_called_once_with(
["pyvenv", "--symlinks", "/tmp/foo"], runas=None, python_shell=False
[VENV_BIN, "--symlinks", "/tmp/foo"], runas=None, python_shell=False
)
def test_virtualenv_ver(self):
"""
test virtualenv_ver when there is no ImportError
"""
ret = virtualenv_mod.virtualenv_ver(venv_bin="pyvenv")
ret = virtualenv_mod.virtualenv_ver(venv_bin=VENV_BIN)
assert ret == (1, 9, 1)
def test_virtualenv_ver_importerror(self):