xonsh/tests/test_vox.py

395 lines
10 KiB
Python
Raw Normal View History

"""Vox tests"""
2022-01-31 21:26:34 +05:30
import os
import pathlib
import stat
import subprocess as sp
2022-01-31 21:26:34 +05:30
import sys
import types
2022-01-31 21:26:34 +05:30
from typing import TYPE_CHECKING
import pytest
from tools import skip_if_on_conda, skip_if_on_msys
from xonsh.platform import ON_WINDOWS
2022-01-31 21:26:34 +05:30
from xontrib.voxapi import Vox
if TYPE_CHECKING:
from xontrib.vox import VoxHandler
2016-07-23 11:21:41 -04:00
@pytest.fixture
def vox(xession, tmpdir, load_xontrib) -> "VoxHandler":
"""vox Alias function"""
# Set up an isolated venv home
xession.env["VIRTUALENV_HOME"] = str(tmpdir)
# Set up enough environment for xonsh to function
xession.env["PWD"] = os.getcwd()
xession.env["DIRSTACK_SIZE"] = 10
xession.env["PATH"] = []
xession.env["XONSH_SHOW_TRACEBACK"] = True
load_xontrib("vox")
2016-08-28 13:37:23 -04:00
yield xession.aliases["vox"]
2016-08-28 13:37:23 -04:00
@pytest.fixture
def record_events(xession):
class Listener:
def __init__(self):
self.last = None
def listener(self, name):
def _wrapper(**kwargs):
self.last = (name,) + tuple(kwargs.values())
return _wrapper
def __call__(self, *events: str):
for name in events:
event = getattr(xession.builtins.events, name)
event(self.listener(name))
yield Listener()
@skip_if_on_msys
@skip_if_on_conda
def test_vox_flow(xession, vox, record_events, tmpdir):
"""
Creates a virtual environment, gets it, enumerates it, and then deletes it.
"""
xession.env["VIRTUALENV_HOME"] = str(tmpdir)
2016-08-28 13:37:23 -04:00
record_events(
"vox_on_create", "vox_on_delete", "vox_on_activate", "vox_on_deactivate"
)
2016-08-28 13:37:23 -04:00
vox(["create", "spam"])
assert stat.S_ISDIR(tmpdir.join("spam").stat().mode)
assert record_events.last == ("vox_on_create", "spam")
2016-08-28 13:37:23 -04:00
ve = vox.vox["spam"]
assert ve.env == str(tmpdir.join("spam"))
assert os.path.isdir(ve.bin)
2016-08-28 13:37:23 -04:00
assert "spam" in vox.vox
assert "spam" in list(vox.vox)
# activate/deactivate
vox(["activate", "spam"])
assert xession.env["VIRTUAL_ENV"] == vox.vox["spam"].env
assert record_events.last == ("vox_on_activate", "spam", str(ve.env))
vox.deactivate()
assert "VIRTUAL_ENV" not in xession.env
assert record_events.last == ("vox_on_deactivate", "spam", str(ve.env))
# removal
vox(["rm", "spam", "--force"])
assert not tmpdir.join("spam").check()
assert record_events.last == ("vox_on_delete", "spam")
@skip_if_on_msys
@skip_if_on_conda
def test_activate_non_vox_venv(xession, vox, record_events, tmpdir):
"""
Create a virtual environment using Python's built-in venv module
(not in VIRTUALENV_HOME) and verify that vox can activate it correctly.
"""
update test xsh usage (#4581) * todo * test: remove usage of DummyEnv and setting .env attribute on xession fixture one step closer to making too much of tweaking to xession during tests * test: fix tests vox and gitstatus-prompt * docs: update test-fixture usage * fix: import flake8 error * test: remove direct access to XSH in tests * test: remove usage of XSH in test files * todo * test: use tmp-dir to create stubs * refactor: use fixture factory to mock out XonshSession * refactor: remove direct access of XSH from functions * refactor: remove direct access of XSH from functions * fix: qa checks * refactor: rename variables to match their values * test: update failing tests because it had no PATH set previously * fix: remove builtins usage from pyghooks.py * style: * refactor: update tests to use fixtures * fix: env varialbe is setup per function some tests accidentally update the env variables and that is leaking into next tests * fix: failing vox tests * test: set commands_cache per test * test: fix failing tests * fix: failing tests on linux ptk-highlight * fix: failing tests on Windows cwd-prompt * test: copy env as to not affect original object * fix: lazily evaluate cmds-cache in pyghooks * test: fix failing tests * fix: qa errors import * test: set commands-cache per test while caching path results * test: speedup test_thread_local_swap * fix: failing tests on windows * refactor: Execer doesn't control session * refactor: XSH.unload will take care of reversing builtins attrs set * test: use env.update over monkeypatch * Revert "test: use env.update over monkeypatch" This reverts commit 010a5022247a098f1741966b8af1bf758663480e.
2022-01-08 04:03:22 +05:30
xession.env["PATH"] = []
record_events("vox_on_activate", "vox_on_deactivate")
with tmpdir.as_cwd():
2020-08-26 10:10:59 -05:00
venv_dirname = "venv"
sp.run([sys.executable, "-m", "venv", venv_dirname])
vox(["activate", venv_dirname])
vxv = vox.vox[venv_dirname]
env = xession.env
assert os.path.isabs(vxv.bin)
assert env["PATH"][0] == vxv.bin
assert os.path.isabs(vxv.env)
assert env["VIRTUAL_ENV"] == vxv.env
assert record_events.last == (
"vox_on_activate",
venv_dirname,
str(pathlib.Path(str(tmpdir)) / venv_dirname),
)
vox(["deactivate"])
assert not env["PATH"]
assert "VIRTUAL_ENV" not in env
assert record_events.last == (
"vox_on_deactivate",
venv_dirname,
str(pathlib.Path(str(tmpdir)) / venv_dirname),
)
@skip_if_on_msys
@skip_if_on_conda
def test_path(xession, vox, tmpdir, a_venv):
"""
Test to make sure Vox properly activates and deactivates by examining $PATH
"""
oldpath = list(xession.env["PATH"])
vox(["activate", a_venv.basename])
2018-08-30 09:18:49 -05:00
assert oldpath != xession.env["PATH"]
vox.deactivate()
2018-08-30 09:18:49 -05:00
assert oldpath == xession.env["PATH"]
@skip_if_on_msys
@skip_if_on_conda
def test_crud_subdir(xession, tmpdir):
"""
Creates a virtual environment, gets it, enumerates it, and then deletes it.
"""
xession.env["VIRTUALENV_HOME"] = str(tmpdir)
vox = Vox(force_removals=True)
2018-08-30 09:18:49 -05:00
vox.create("spam/eggs")
assert stat.S_ISDIR(tmpdir.join("spam", "eggs").stat().mode)
2018-08-30 09:18:49 -05:00
ve = vox["spam/eggs"]
assert ve.env == str(tmpdir.join("spam", "eggs"))
assert os.path.isdir(ve.bin)
2018-08-30 09:18:49 -05:00
assert "spam/eggs" in vox
assert "spam" not in vox
2018-08-30 09:18:49 -05:00
# assert 'spam/eggs' in list(vox) # This is NOT true on Windows
assert "spam" not in list(vox)
2018-08-30 09:18:49 -05:00
del vox["spam/eggs"]
assert not tmpdir.join("spam", "eggs").check()
@skip_if_on_msys
@skip_if_on_conda
def test_crud_path(xession, tmpdir):
"""
Creates a virtual environment, gets it, enumerates it, and then deletes it.
"""
tmp = pathlib.Path(str(tmpdir))
2016-12-09 23:14:41 -05:00
vox = Vox(force_removals=True)
vox.create(tmp)
assert stat.S_ISDIR(tmpdir.join("lib").stat().mode)
2016-12-09 23:14:41 -05:00
ve = vox[tmp]
assert ve.env == str(tmp)
assert os.path.isdir(ve.bin)
2016-12-09 23:14:41 -05:00
del vox[tmp]
2016-12-09 23:14:41 -05:00
assert not tmpdir.check()
2016-12-09 23:14:41 -05:00
@skip_if_on_msys
@skip_if_on_conda
def test_reserved_names(xession, tmpdir):
"""
2019-08-28 14:07:27 -04:00
Tests that reserved words are disallowed.
"""
xession.env["VIRTUALENV_HOME"] = str(tmpdir)
vox = Vox()
with pytest.raises(ValueError):
if ON_WINDOWS:
2018-08-30 09:18:49 -05:00
vox.create("Scripts")
else:
2018-08-30 09:18:49 -05:00
vox.create("bin")
with pytest.raises(ValueError):
if ON_WINDOWS:
2018-08-30 09:18:49 -05:00
vox.create("spameggs/Scripts")
else:
2018-08-30 09:18:49 -05:00
vox.create("spameggs/bin")
2019-08-28 14:50:27 -04:00
@pytest.mark.parametrize("registered", [False, True])
2019-08-28 14:50:27 -04:00
@skip_if_on_msys
@skip_if_on_conda
def test_autovox(xession, tmpdir, vox, a_venv, load_xontrib, registered):
2019-08-28 14:50:27 -04:00
"""
Tests that autovox works
"""
2022-01-31 21:26:34 +05:30
from xonsh.dirstack import popd, pushd
2019-08-28 14:50:27 -04:00
# Makes sure that event handlers are registered
load_xontrib("autovox")
2020-08-26 10:10:59 -05:00
env_name = a_venv.basename
env_path = str(a_venv)
2019-08-28 14:50:27 -04:00
# init properly
assert vox.parser
2019-08-28 14:50:27 -04:00
def policy(path, **_):
if str(path) == env_path:
return env_name
2019-08-28 14:50:27 -04:00
if registered:
xession.builtins.events.autovox_policy(policy)
2019-08-28 14:50:27 -04:00
pushd([env_path])
value = env_name if registered else None
assert vox.vox.active() == value
popd([])
@pytest.fixture
def venv_home(tmpdir):
"""Path where VENVs are created"""
return tmpdir
@pytest.fixture
def venvs(venv_home):
"""Create virtualenv with names venv0, venv1"""
2022-01-31 21:26:34 +05:30
from xonsh.dirstack import popd, pushd
pushd([str(venv_home)])
paths = []
for idx in range(2):
env_path = venv_home / f"venv{idx}"
bin_path = env_path / "bin"
paths.append(env_path)
(bin_path / "python").write("", ensure=True)
(bin_path / "python.exe").write("", ensure=True)
for file in bin_path.listdir():
st = os.stat(str(file))
os.chmod(str(file), st.st_mode | stat.S_IEXEC)
yield paths
popd([])
@pytest.fixture
def a_venv(venvs):
return venvs[0]
@pytest.fixture
def patched_cmd_cache(xession, vox, venvs, monkeypatch):
cc = xession.commands_cache
def no_change(self, *_):
return False, False, False
update test xsh usage (#4581) * todo * test: remove usage of DummyEnv and setting .env attribute on xession fixture one step closer to making too much of tweaking to xession during tests * test: fix tests vox and gitstatus-prompt * docs: update test-fixture usage * fix: import flake8 error * test: remove direct access to XSH in tests * test: remove usage of XSH in test files * todo * test: use tmp-dir to create stubs * refactor: use fixture factory to mock out XonshSession * refactor: remove direct access of XSH from functions * refactor: remove direct access of XSH from functions * fix: qa checks * refactor: rename variables to match their values * test: update failing tests because it had no PATH set previously * fix: remove builtins usage from pyghooks.py * style: * refactor: update tests to use fixtures * fix: env varialbe is setup per function some tests accidentally update the env variables and that is leaking into next tests * fix: failing vox tests * test: set commands_cache per test * test: fix failing tests * fix: failing tests on linux ptk-highlight * fix: failing tests on Windows cwd-prompt * test: copy env as to not affect original object * fix: lazily evaluate cmds-cache in pyghooks * test: fix failing tests * fix: qa errors import * test: set commands-cache per test while caching path results * test: speedup test_thread_local_swap * fix: failing tests on windows * refactor: Execer doesn't control session * refactor: XSH.unload will take care of reversing builtins attrs set * test: use env.update over monkeypatch * Revert "test: use env.update over monkeypatch" This reverts commit 010a5022247a098f1741966b8af1bf758663480e.
2022-01-08 04:03:22 +05:30
monkeypatch.setattr(cc, "_check_changes", types.MethodType(no_change, cc))
monkeypatch.setattr(cc, "_update_cmds_cache", types.MethodType(no_change, cc))
bins = {path: (path, False) for path in _PY_BINS}
cc._cmds_cache.update(bins)
yield cc
_VENV_NAMES = {"venv1", "venv1/", "venv0/", "venv0"}
if ON_WINDOWS:
_VENV_NAMES = {"venv1\\", "venv0\\"}
_HELP_OPTS = {
"-h",
"--help",
}
_PY_BINS = {"/bin/python2", "/bin/python3"}
_VOX_NEW_OPTS = {
"--ssp",
"--system-site-packages",
"--without-pip",
}.union(_HELP_OPTS)
_VOX_NEW_EXP = _PY_BINS.union(_VOX_NEW_OPTS)
if ON_WINDOWS:
_VOX_NEW_OPTS.add("--symlinks")
else:
_VOX_NEW_OPTS.add("--copies")
_VOX_RM_OPTS = {"-f", "--force"}.union(_HELP_OPTS)
@pytest.mark.parametrize(
"args, positionals, opts",
[
(
"vox",
{
"delete",
"new",
"remove",
"del",
"workon",
"list",
"exit",
"info",
"ls",
"rm",
"deactivate",
"activate",
"enter",
"create",
"project-get",
"project-set",
"runin",
"runin-all",
"toggle-ssp",
"wipe",
"upgrade",
},
_HELP_OPTS,
),
(
"vox create",
set(),
_VOX_NEW_OPTS.union(
{
"-a",
"--activate",
"--wp",
"--without-pip",
"-p",
"--interpreter",
"-i",
"--install",
"-l",
"--link",
"--link-project",
"-r",
"--requirements",
"-t",
"--temp",
"--prompt",
}
),
),
("vox activate", _VENV_NAMES, _HELP_OPTS.union({"-n", "--no-cd"})),
("vox rm", _VENV_NAMES, _VOX_RM_OPTS),
("vox rm venv1", _VENV_NAMES, _VOX_RM_OPTS), # pos nargs: one or more
("vox rm venv1 venv2", _VENV_NAMES, _VOX_RM_OPTS), # pos nargs: two or more
("vox new --activate --interpreter", _PY_BINS, set()), # option after option
("vox new --interpreter", _PY_BINS, set()), # "option: first
("vox new --activate env1 --interpreter", _PY_BINS, set()), # option after pos
("vox new env1 --interpreter", _PY_BINS, set()), # "option: at end"
("vox new env1 --interpreter=", _PY_BINS, set()), # "option: at end with
],
)
def test_vox_completer(
args, check_completer, positionals, opts, xession, patched_cmd_cache, venv_home
):
xession.env["XONSH_DATA_DIR"] = venv_home
if positionals:
assert check_completer(args) == positionals
xession.env["ALIAS_COMPLETIONS_OPTIONS_BY_DEFAULT"] = True
if opts:
assert check_completer(args) == positionals.union(opts)