mamba/micromamba/tests/test_activation.py

960 lines
31 KiB
Python

import os
import pathlib
import platform
import shutil
import subprocess
import tempfile
from pathlib import Path, PurePosixPath, PureWindowsPath
import pytest
from . import helpers
plat, running_os = None, None
if platform.system() == "Linux":
plat = "linux"
running_os = "unix"
elif platform.system() == "Darwin":
plat = "osx"
running_os = "unix"
elif platform.system() == "Windows":
os.system("chcp 65001")
plat = "win"
running_os = "win"
suffixes = {
"cmd.exe": ".bat",
"bash": ".sh",
"zsh": ".sh",
"tcsh": ".csh",
"xonsh": ".sh",
"fish": ".fish",
"powershell": ".ps1",
"nu": ".nu",
}
class WindowsProfiles:
def __getitem__(self, shell: str) -> str:
if shell == "powershell":
# find powershell profile path dyanmically
args = [
"powershell",
"-NoProfile",
"-Command",
"$PROFILE.CurrentUserAllHosts",
]
res = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True)
return res.stdout.decode("utf-8").strip()
elif shell == "cmd.exe":
return None
raise KeyError(f"Invalid shell: {shell}")
paths = {
"win": WindowsProfiles(),
"osx": {
"zsh": "~/.zshrc",
"bash": "~/.bash_profile",
"xonsh": "~/.xonshrc",
"tcsh": "~/.tcshrc",
"fish": "~/.config/fish/config.fish",
"nu": "~/.config/nushell/config.nu",
},
"linux": {
"zsh": "~/.zshrc",
"bash": "~/.bashrc",
"xonsh": "~/.xonshrc",
"tcsh": "~/.tcshrc",
"fish": "~/.config/fish/config.fish",
"nu": "~/.config/nushell/config.nu",
},
}
def xonsh_shell_args(interpreter):
# In macOS, the parent process name is "Python" and not "xonsh" like in Linux.
# Thus, we need to specify the shell explicitly.
return "-s xonsh" if interpreter == "xonsh" and plat == "osx" else ""
def extract_vars(vxs, interpreter):
return [f"echo {v}={shvar(v, interpreter)}" for v in vxs]
def write_script(interpreter, lines, path):
fname = os.path.join(path, "script" + suffixes[interpreter])
if plat == "win":
if interpreter == "powershell":
with open(fname, "w", encoding="utf-8-sig") as fo:
fo.write("\n".join(lines) + "\n")
else:
with open(fname, "w", encoding="utf-8") as fo:
fo.write("\n".join(lines) + "\n")
else:
with open(fname, "w") as fo:
fo.write("\n".join(lines) + "\n")
return fname
possible_interpreters = {
"win": {"powershell", "cmd.exe", "bash", "nu"},
"unix": {"bash", "zsh", "fish", "xonsh", "tcsh", "nu"},
}
regkey = "HKEY_CURRENT_USER\\Software\\Microsoft\\Command Processor\\AutoRun"
@pytest.fixture
def winreg_value():
if plat == "win":
try:
saved_winreg_value = helpers.read_windows_registry(regkey)
except Exception:
print("Could not read registry value")
saved_winreg_value = ("", 1)
new_winreg_value = ("", saved_winreg_value[1])
print("setting registry to ", new_winreg_value)
helpers.write_windows_registry(regkey, *new_winreg_value)
yield new_winreg_value
print("setting registry to ", saved_winreg_value)
helpers.write_windows_registry(regkey, *saved_winreg_value)
else:
yield None
def find_path_in_str(p, s):
if isinstance(p, Path):
p = str(p)
if p in s:
return True
if p.replace("\\", "\\\\") in s:
return True
return False
def format_path(p, interpreter):
if plat == "win" and interpreter == "bash":
return str(PurePosixPath(PureWindowsPath(p)))
else:
return str(p)
def call_interpreter(s, tmp_path, interpreter, interactive=False, env=None):
if interactive and interpreter == "powershell":
# "Get-Content -Path $PROFILE.CurrentUserAllHosts | Invoke-Expression"
s = [". $PROFILE.CurrentUserAllHosts"] + s
if interactive and interpreter == "bash" and plat == "linux":
s = ["source ~/.bashrc"] + s
if interpreter == "cmd.exe":
mods = ["@chcp 65001>nul"]
for x in s:
if x.startswith("micromamba activate") or x.startswith("micromamba deactivate"):
mods.append("call " + x)
else:
mods.append(x)
s = mods
f = write_script(interpreter, s, tmp_path)
if interpreter not in possible_interpreters[running_os]:
return None, None
if interpreter == "cmd.exe":
args = ["cmd.exe", "/Q", "/C", f]
elif interpreter == "powershell":
args = ["powershell", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", f]
elif interpreter == "bash" and plat == "win":
args = [os.path.join(os.environ["PROGRAMFILES"], "Git", "bin", "bash.exe"), f]
else:
args = [interpreter, f]
if interactive:
args.insert(1, "-i")
if interactive and interpreter == "bash":
args.insert(1, "-l")
try:
res = subprocess.run(
args,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
check=True,
env=env,
encoding="utf-8",
)
except subprocess.CalledProcessError as e:
stdout = e.stdout.strip()
stderr = e.stderr.strip()
try:
print(stdout)
print(stderr)
except Exception:
pass
if interpreter == "cmd.exe":
if stdout.startswith("'") and stdout.endswith("'"):
stdout = stdout[1:-1]
e.stdout = stdout
e.stderr = stderr
raise e
except Exception as e:
raise e
stdout = res.stdout.strip()
stderr = res.stderr.strip()
try:
print(stdout)
print(stderr)
except Exception:
pass
if interpreter == "cmd.exe":
if stdout.startswith("'") and stdout.endswith("'"):
stdout = stdout[1:-1]
return stdout, stderr
def get_interpreters(exclude=None):
if exclude is None:
exclude = []
return [x for x in possible_interpreters[running_os] if x not in exclude]
def get_valid_interpreters():
valid_interpreters = []
s = ["echo 'hello world'"]
with tempfile.TemporaryDirectory() as tmpdirname:
for interpreter in possible_interpreters[running_os]:
try:
stdout, _ = call_interpreter(s, tmpdirname, interpreter)
assert stdout == "hello world"
valid_interpreters.append(interpreter)
except Exception:
pass
return valid_interpreters
valid_interpreters = get_valid_interpreters()
def get_self_update_interpreters():
if plat == "win":
return ["cmd.exe", "powershell", "bash"]
if plat == "osx":
return ["zsh", "bash"]
else:
return ["bash"]
def shvar(v, interpreter):
if interpreter in ["bash", "zsh", "xonsh", "fish", "tcsh", "dash"]:
return f"${v}"
elif interpreter == "powershell":
return f"$Env:{v}"
elif interpreter == "cmd.exe":
return f"%{v}%"
elif interpreter == "nu":
return f"$env.{v}"
def env_to_dict(out, interpreter="bash"):
if interpreter == "cmd.exe":
with open(out, "r") as f:
out = f.read()
if interpreter == "fish":
return {
v.split(" ", maxsplit=1)[0]: v.split(" ", maxsplit=1)[1]
for _, _, v in [x.partition("set -gx ") for x in out.splitlines()]
}
elif interpreter in ["csh", "tcsh"]:
res = {}
for line in out.splitlines():
line = line.removesuffix(";")
if line.startswith("set "):
k, v = line.split(" ")[1].split("=")
elif line.startswith("setenv "):
_, k, v = line.strip().split(maxsplit=2)
res[k] = v
return res
else:
return {k: v for k, _, v in [x.partition("=") for x in out.splitlines()]}
@pytest.mark.parametrize("interpreter", get_interpreters())
def test_shell_init(
tmp_home,
winreg_value,
tmp_root_prefix,
tmp_path,
interpreter,
):
# TODO enable these tests also on win + bash!
if interpreter not in valid_interpreters or (plat == "win" and interpreter == "bash"):
pytest.skip(f"{interpreter} not available")
umamba = helpers.get_umamba()
run_dir = tmp_path / "rundir"
run_dir.mkdir()
def call(s):
return call_interpreter(s, run_dir, interpreter)
rpv = shvar("MAMBA_ROOT_PREFIX", interpreter)
s = [f"echo {rpv}"]
stdout, stderr = call(s)
assert stdout == str(tmp_root_prefix)
s = [f"{umamba} shell init -r {rpv} {xonsh_shell_args(interpreter)}"]
stdout, stderr = call(s)
if interpreter == "cmd.exe":
value = helpers.read_windows_registry(regkey)
assert "mamba_hook.bat" in value[0]
assert find_path_in_str(tmp_root_prefix, value[0])
prev_text = value[0]
else:
path = Path(paths[plat][interpreter]).expanduser()
with open(path) as fi:
x = fi.read()
assert "micromamba" in x
assert find_path_in_str(tmp_root_prefix, x)
prev_text = x
s = [f"{umamba} shell init -r {rpv} {xonsh_shell_args(interpreter)}"]
stdout, stderr = call(s)
if interpreter == "cmd.exe":
value = helpers.read_windows_registry(regkey)
assert "mamba_hook.bat" in value[0]
assert find_path_in_str(tmp_root_prefix, value[0])
assert prev_text == value[0]
assert "&" not in value[0]
else:
with open(path) as fi:
x = fi.read()
assert "mamba" in x
assert prev_text == x
if interpreter == "cmd.exe":
helpers.write_windows_registry(regkey, "echo 'test'", winreg_value[1])
s = [f"{umamba} shell init -r {rpv}"]
stdout, stderr = call(s)
value = helpers.read_windows_registry(regkey)
assert "mamba_hook.bat" in value[0]
assert find_path_in_str(tmp_root_prefix, value[0])
assert value[0].startswith("echo 'test' & ")
assert "&" in value[0]
if interpreter != "cmd.exe":
with open(path) as fi:
prevlines = fi.readlines()
with open(path, "w") as fo:
text = "\n".join(
["", "", "echo 'hihi'", ""]
+ [x.rstrip("\n\r") for x in prevlines]
+ ["", "", "echo 'hehe'"]
)
fo.write(text)
s = [f"{umamba} shell init -r {rpv}"]
stdout, stderr = call(s)
with open(path) as fi:
x = fi.read()
assert "mamba" in x
assert text == x
other_root_prefix = tmp_path / "prefix"
other_root_prefix.mkdir()
s = [f"{umamba} shell init -r {other_root_prefix} {xonsh_shell_args(interpreter)}"]
stdout, stderr = call(s)
if interpreter == "cmd.exe":
x = helpers.read_windows_registry(regkey)[0]
assert "mamba" in x
assert find_path_in_str(other_root_prefix, x)
assert not find_path_in_str(tmp_root_prefix, x)
else:
with open(path) as fi:
x = fi.read()
assert "mamba" in x
assert find_path_in_str(other_root_prefix, x)
assert not find_path_in_str(tmp_root_prefix, x)
@pytest.mark.parametrize("interpreter", get_interpreters())
def test_shell_init_deinit_root_prefix_files(
tmp_home,
tmp_root_prefix,
tmp_path,
interpreter,
):
if interpreter not in valid_interpreters or (plat == "win" and interpreter == "bash"):
pytest.skip(f"{interpreter} not available")
umamba = helpers.get_umamba()
if interpreter == "bash" or interpreter == "zsh":
files = [tmp_root_prefix / "etc" / "profile.d" / "micromamba.sh"]
elif interpreter == "cmd.exe":
files = [
tmp_root_prefix / "condabin" / "mamba_hook.bat",
tmp_root_prefix / "condabin" / "micromamba.bat",
tmp_root_prefix / "condabin" / "_mamba_activate.bat",
tmp_root_prefix / "condabin" / "activate.bat",
]
elif interpreter == "powershell":
files = [
tmp_root_prefix / "condabin" / "mamba_hook.ps1",
tmp_root_prefix / "condabin" / "Mamba.psm1",
]
elif interpreter == "fish":
files = [tmp_root_prefix / "etc" / "fish" / "conf.d" / "mamba.fish"]
elif interpreter == "xonsh":
files = [tmp_root_prefix / "etc" / "profile.d" / "mamba.xsh"]
elif interpreter in ["csh", "tcsh"]:
files = [tmp_root_prefix / "etc" / "profile.d" / "micromamba.csh"]
elif interpreter == "nu":
files = [] # moved to ~/.config/nushell.nu controlled by micromamba activation
else:
raise ValueError(f"Unknown shell {interpreter}")
def call(command):
return call_interpreter(command, tmp_path, interpreter)
s = [f"{umamba} shell init -r {tmp_root_prefix} {xonsh_shell_args(interpreter)}"]
call(s)
for file in files:
assert file.exists()
s = [f"{umamba} shell deinit -r {tmp_root_prefix} {xonsh_shell_args(interpreter)}"]
call(s)
for file in files:
assert not file.exists()
def test_shell_init_deinit_contents_cmdexe(
tmp_home,
winreg_value,
tmp_root_prefix,
tmp_path,
):
interpreter = "cmd.exe"
if interpreter not in valid_interpreters:
pytest.skip(f"{interpreter} not available")
umamba = helpers.get_umamba()
def call(command):
return call_interpreter(command, tmp_path, interpreter)
prev_value = helpers.read_windows_registry(regkey)
assert "mamba_hook.bat" not in prev_value[0]
assert not find_path_in_str(tmp_root_prefix, prev_value[0])
s = [f"{umamba} shell init -r {tmp_root_prefix} {xonsh_shell_args(interpreter)}"]
call(s)
value_after_init = helpers.read_windows_registry(regkey)
assert "mamba_hook.bat" in value_after_init[0]
assert find_path_in_str(tmp_root_prefix, value_after_init[0])
s = [f"{umamba} shell deinit -r {tmp_root_prefix} {xonsh_shell_args(interpreter)}"]
call(s)
value_after_deinit = helpers.read_windows_registry(regkey)
assert value_after_deinit == prev_value
@pytest.mark.parametrize("interpreter", get_interpreters(exclude=["cmd.exe"]))
def test_shell_init_deinit_contents(
tmp_home,
tmp_root_prefix,
tmp_path,
interpreter,
):
if interpreter not in valid_interpreters or (plat == "win" and interpreter == "bash"):
pytest.skip(f"{interpreter} not available")
umamba = helpers.get_umamba()
def call(command):
return call_interpreter(command, tmp_path, interpreter)
path = Path(paths[plat][interpreter]).expanduser()
if os.path.exists(path):
with open(path) as fi:
prev_rc_contents = fi.read()
else:
prev_rc_contents = ""
if interpreter == "powershell":
assert "#region mamba initialize" not in prev_rc_contents
else:
assert "# >>> mamba initialize >>>" not in prev_rc_contents
assert not find_path_in_str(tmp_root_prefix, prev_rc_contents)
s = [f"{umamba} shell init -r {tmp_root_prefix} {xonsh_shell_args(interpreter)}"]
call(s)
with open(path) as fi:
rc_contents_after_init = fi.read()
if interpreter == "powershell":
assert "#region mamba initialize" in rc_contents_after_init
else:
assert "# >>> mamba initialize >>>" in rc_contents_after_init
assert find_path_in_str(tmp_root_prefix, rc_contents_after_init)
s = [f"{umamba} shell deinit -r {tmp_root_prefix} {xonsh_shell_args(interpreter)}"]
call(s)
if os.path.exists(path):
with open(path) as fi:
rc_contents_after_deinit = fi.read()
else:
rc_contents_after_deinit = ""
assert rc_contents_after_deinit == prev_rc_contents
@pytest.mark.parametrize("interpreter", get_interpreters())
def test_env_activation(tmp_home, winreg_value, tmp_root_prefix, tmp_path, interpreter):
if interpreter not in valid_interpreters or (plat == "win" and interpreter == "bash"):
pytest.skip(f"{interpreter} not available")
umamba = helpers.get_umamba()
s = [f"{umamba} shell init -r {tmp_root_prefix}"]
stdout, stderr = call_interpreter(s, tmp_path, interpreter)
def call(s):
return call_interpreter(s, tmp_path, interpreter, interactive=True)
evars = extract_vars(["CONDA_PREFIX", "CONDA_SHLVL", "PATH"], interpreter)
if interpreter == "cmd.exe":
x = helpers.read_windows_registry(regkey)
fp = Path(x[0][1:-1])
assert fp.exists()
if interpreter in ["bash", "zsh", "powershell", "cmd.exe"]:
stdout, stderr = call(evars)
s = [f"{umamba} --help"]
stdout, stderr = call(s)
s = ["micromamba activate"] + evars
stdout, stderr = call(s)
res = env_to_dict(stdout)
assert "condabin" in res["PATH"]
assert str(tmp_root_prefix) in res["PATH"]
assert f"CONDA_PREFIX={tmp_root_prefix}" in stdout.splitlines()
assert "CONDA_SHLVL=1" in stdout.splitlines()
# throw with non-existent
if plat != "win":
with pytest.raises(subprocess.CalledProcessError):
stdout, stderr = call(["micromamba activate nonexistent"])
call(["micromamba create -n abc -y"])
call(["micromamba create -n xyz -y"])
s = [
"micromamba activate",
"micromamba activate abc",
"micromamba activate xyz",
] + evars
stdout, stderr = call(s)
res = env_to_dict(stdout)
assert find_path_in_str(tmp_root_prefix / "condabin", res["PATH"])
assert not find_path_in_str(tmp_root_prefix / "bin", res["PATH"])
assert find_path_in_str(tmp_root_prefix / "envs" / "xyz", res["PATH"])
assert not find_path_in_str(tmp_root_prefix / "envs" / "abc", res["PATH"])
s = [
"micromamba activate",
"micromamba activate abc",
"micromamba activate --stack xyz",
] + evars
stdout, stderr = call(s)
res = env_to_dict(stdout)
assert find_path_in_str(tmp_root_prefix / "condabin", res["PATH"])
assert not find_path_in_str(tmp_root_prefix / "bin", res["PATH"])
assert find_path_in_str(tmp_root_prefix / "envs" / "xyz", res["PATH"])
assert find_path_in_str(tmp_root_prefix / "envs" / "abc", res["PATH"])
s = [
"micromamba activate",
"micromamba activate abc",
"micromamba activate xyz --stack",
] + evars
stdout, stderr = call(s)
res = env_to_dict(stdout)
assert find_path_in_str(tmp_root_prefix / "condabin", res["PATH"])
assert not find_path_in_str(tmp_root_prefix / "bin", res["PATH"])
assert find_path_in_str(tmp_root_prefix / "envs" / "xyz", res["PATH"])
assert find_path_in_str(tmp_root_prefix / "envs" / "abc", res["PATH"])
stdout, stderr = call(evars)
res = env_to_dict(stdout)
assert find_path_in_str(tmp_root_prefix / "condabin", res["PATH"])
stdout, stderr = call(["micromamba deactivate"] + evars)
res = env_to_dict(stdout)
assert find_path_in_str(tmp_root_prefix / "condabin", res["PATH"])
assert not find_path_in_str(tmp_root_prefix / "bin", res["PATH"])
assert not find_path_in_str(tmp_root_prefix / "envs" / "xyz", res["PATH"])
assert not find_path_in_str(tmp_root_prefix / "envs" / "abc", res["PATH"])
@pytest.mark.parametrize("interpreter", get_interpreters())
def test_activation_envvars(
tmp_home,
tmp_clean_env,
winreg_value,
tmp_root_prefix,
tmp_path,
interpreter,
):
if interpreter not in valid_interpreters or (plat == "win" and interpreter == "bash"):
pytest.skip(f"{interpreter} not available")
umamba = helpers.get_umamba()
s = [f"{umamba} shell init -r {tmp_root_prefix}"]
stdout, stderr = call_interpreter(s, tmp_path, interpreter)
def call(s):
return call_interpreter(s, tmp_path, interpreter, interactive=True)
evars = extract_vars(["CONDA_PREFIX", "CONDA_SHLVL", "PATH"], interpreter)
if interpreter == "cmd.exe":
x = helpers.read_windows_registry(regkey)
fp = Path(x[0][1:-1])
assert fp.exists()
if interpreter in ["bash", "zsh", "powershell", "cmd.exe"]:
call(["micromamba create -n def -y"])
stdout, stderr = call(["micromamba activate def"] + evars)
res = env_to_dict(stdout)
abc_prefix = pathlib.Path(res["CONDA_PREFIX"])
state_file = abc_prefix / "conda-meta" / "state"
# Python dicts are guaranteed to keep insertion order since 3.7,
# so the following works fine!
state_file.write_text(
helpers.json.dumps(
{
"env_vars": {
"test": "Test",
"HELLO": "world",
"WORKING": "/FINE/PATH/YAY",
"AAA": "last",
}
}
)
)
stdout, stderr = call(
["micromamba activate def"]
+ evars
+ extract_vars(["TEST", "HELLO", "WORKING", "AAA"], interpreter)
)
# assert that env vars are in the same order
activation_script, stderr = call(["micromamba shell activate -s bash -n def"])
idxs = []
for el in ["TEST", "HELLO", "WORKING", "AAA"]:
for idx, line in enumerate(activation_script.splitlines()):
if line.startswith(f"export {el}="):
idxs.append(idx)
continue
assert len(idxs) == 4
# make sure that the order is correct
assert idxs == sorted(idxs)
res = env_to_dict(stdout)
assert res["TEST"] == "Test"
assert res["HELLO"] == "world"
assert res["WORKING"] == "/FINE/PATH/YAY"
assert res["AAA"] == "last"
pkg_env_vars_d = abc_prefix / "etc" / "conda" / "env_vars.d"
pkg_env_vars_d.mkdir(exist_ok=True, parents=True)
j1 = {"PKG_ONE": "FANCY_ENV_VAR", "OVERLAP": "LOSE_AGAINST_PKG_TWO"}
j2 = {
"PKG_TWO": "SUPER_FANCY_ENV_VAR",
"OVERLAP": "WINNER",
"TEST": "LOSE_AGAINST_META_STATE",
}
(pkg_env_vars_d / "001-pkg-one.json").write_text(helpers.json.dumps(j1))
(pkg_env_vars_d / "002-pkg-two.json").write_text(helpers.json.dumps(j2))
activation_script, stderr = call(["micromamba shell activate -s bash -n def"])
stdout, stderr = call(
["micromamba activate def"]
+ evars
+ extract_vars(
[
"TEST",
"HELLO",
"WORKING",
"AAA",
"PKG_ONE",
"PKG_TWO",
"OVERLAP",
],
interpreter,
)
)
res = env_to_dict(stdout)
assert res["HELLO"] == "world"
assert res["WORKING"] == "/FINE/PATH/YAY"
assert res["AAA"] == "last"
assert res["PKG_ONE"] == "FANCY_ENV_VAR"
assert res["PKG_TWO"] == "SUPER_FANCY_ENV_VAR"
assert res["OVERLAP"] == "WINNER"
assert res["TEST"] == "Test"
@pytest.mark.parametrize("interpreter", get_interpreters())
@pytest.mark.parametrize("shared_pkgs_dirs", [True], indirect=True)
def test_unicode_activation(
tmp_home,
winreg_value,
tmp_root_prefix,
tmp_path,
interpreter,
):
if interpreter not in valid_interpreters or (plat == "win" and interpreter == "bash"):
pytest.skip(f"{interpreter} not available")
umamba = helpers.get_umamba()
s = [f"{umamba} shell init -r {tmp_root_prefix}"]
stdout, stderr = call_interpreter(s, tmp_path, interpreter)
def call(s):
return call_interpreter(s, tmp_path, interpreter, interactive=True)
evars = extract_vars(["CONDA_PREFIX", "CONDA_SHLVL", "PATH"], interpreter)
if interpreter == "cmd.exe":
x = helpers.read_windows_registry(regkey)
fp = Path(x[0][1:-1])
assert fp.exists()
if interpreter in ["bash", "zsh", "powershell", "cmd.exe"]:
stdout, stderr = call(evars)
s = [f"{umamba} --help"]
stdout, stderr = call(s)
s = ["micromamba activate"] + evars
stdout, stderr = call(s)
res = env_to_dict(stdout)
assert "condabin" in res["PATH"]
assert str(tmp_root_prefix) in res["PATH"]
assert f"CONDA_PREFIX={tmp_root_prefix}" in stdout.splitlines()
assert "CONDA_SHLVL=1" in stdout.splitlines()
# throw with non-existent
s = ["micromamba activate nonexistent"]
if plat != "win":
with pytest.raises(subprocess.CalledProcessError):
stdout, stderr = call(s)
u1 = "μυρτιὲς"
u2 = "终过鬼门关"
u3 = "some ™∞¢3 spaces §∞©ƒ√≈ç"
s1 = [f"micromamba create -n {u1} xtensor -y -c conda-forge"]
s2 = [f"micromamba create -n {u2} xtensor -y -c conda-forge"]
if interpreter == "cmd.exe":
s3 = [f'micromamba create -n "{u3}" xtensor -y -c conda-forge']
else:
s3 = [f"micromamba create -n '{u3}' xtensor -y -c conda-forge"]
call(s1)
call(s2)
call(s3)
for u in [u1, u2, u3]:
assert (tmp_root_prefix / f"envs/{u}/conda-meta").is_dir()
assert (tmp_root_prefix / f"envs/{u}/conda-meta/history").exists()
if plat == "win":
include_dir = tmp_root_prefix / f"envs/{u}/Library/include"
else:
include_dir = tmp_root_prefix / f"envs/{u}/include"
assert (include_dir / "xtensor/xtensor.hpp").exists()
# unicode activation on win: todo
if plat == "win":
return
s = [
"micromamba activate",
f"micromamba activate {u1}",
f"micromamba activate {u2}",
] + evars
stdout, stderr = call(s)
res = env_to_dict(stdout)
assert find_path_in_str(str(tmp_root_prefix / "condabin"), res["PATH"])
assert not find_path_in_str(str(tmp_root_prefix / "bin"), res["PATH"])
assert find_path_in_str(str(tmp_root_prefix / "envs" / u2), res["PATH"])
assert not find_path_in_str(str(tmp_root_prefix / "envs" / u1), res["PATH"])
s = [
"micromamba activate",
f"micromamba activate {u1}",
f"micromamba activate {u2} --stack",
] + evars
stdout, stderr = call(s)
res = env_to_dict(stdout)
assert find_path_in_str(str(tmp_root_prefix / "condabin"), res["PATH"])
assert not find_path_in_str(str(tmp_root_prefix / "bin"), res["PATH"])
assert find_path_in_str(str(tmp_root_prefix / "envs" / u1), res["PATH"])
assert find_path_in_str(str(tmp_root_prefix / "envs" / u2), res["PATH"])
s = [
"micromamba activate",
f"micromamba activate '{u3}'",
] + evars
stdout, stderr = call(s)
res = env_to_dict(stdout)
assert find_path_in_str(str(tmp_root_prefix / "condabin"), res["PATH"])
assert not find_path_in_str(str(tmp_root_prefix / "bin"), res["PATH"])
assert find_path_in_str(str(tmp_root_prefix / "envs" / u3), res["PATH"])
@pytest.mark.parametrize("interpreter", get_interpreters())
def test_activate_path(tmp_empty_env, tmp_env_name, interpreter, tmp_path):
if interpreter not in valid_interpreters or (plat == "win" and interpreter == "bash"):
pytest.skip(f"{interpreter} not available")
# Activate env name
res = helpers.shell("activate", tmp_env_name, "-s", interpreter)
dict_res = env_to_dict(res, interpreter)
assert any([str(tmp_empty_env) in p for p in dict_res.values()])
# Activate path
res = helpers.shell("activate", str(tmp_empty_env), "-s", interpreter)
dict_res = env_to_dict(res, interpreter)
assert any([str(tmp_empty_env) in p for p in dict_res.values()])
# Activate path with home
prefix_short = str(tmp_empty_env).replace(os.path.expanduser("~"), "~")
res = helpers.shell("activate", prefix_short, "-s", interpreter)
dict_res = env_to_dict(res, interpreter)
assert any([str(tmp_empty_env) in p for p in dict_res.values()])
@pytest.mark.parametrize("interpreter", get_interpreters())
def test_activate_envs_dirs(tmp_root_prefix: Path, interpreter, tmp_path: Path):
"""Activate an environemt as the non leading entry in ``envs_dirs``."""
env_name = "myenv"
helpers.create("-p", tmp_path / env_name, "--offline", "--no-rc", no_dry_run=True)
os.environ["CONDA_ENVS_DIRS"] = f"{Path('/noperm')},{tmp_path}"
res = helpers.shell("activate", env_name, "-s", interpreter)
dict_res = env_to_dict(res, interpreter)
assert any([env_name in p for p in dict_res.values()])
@pytest.fixture
def tmp_umamba():
mamba_exe = helpers.get_umamba()
shutil.copyfile(mamba_exe, mamba_exe + ".orig")
yield mamba_exe
shutil.move(mamba_exe + ".orig", mamba_exe)
os.chmod(mamba_exe, 0o755)
@pytest.mark.parametrize("shared_pkgs_dirs", [True], indirect=True)
@pytest.mark.parametrize("interpreter", get_self_update_interpreters())
def test_self_update(
tmp_umamba,
tmp_home,
tmp_path,
tmp_root_prefix,
winreg_value,
interpreter,
):
mamba_exe = tmp_umamba
shell_init = [
f"{format_path(mamba_exe, interpreter)} shell init -s {interpreter} -r {format_path(tmp_root_prefix, interpreter)}"
]
call_interpreter(shell_init, tmp_path, interpreter)
if interpreter == "bash":
assert (Path(tmp_root_prefix) / "etc" / "profile.d" / "micromamba.sh").exists()
extra_start_code = []
if interpreter == "powershell":
extra_start_code = [
f'$Env:MAMBA_EXE="{mamba_exe}"',
"$MambaModuleArgs = @{ChangePs1 = $True}",
f'Import-Module "{tmp_root_prefix}\\condabin\\Mamba.psm1" -ArgumentList $MambaModuleArgs',
"Remove-Variable MambaModuleArgs",
]
elif interpreter == "bash":
if plat == "linux":
extra_start_code = ["source ~/.bashrc"]
else:
print(mamba_exe)
extra_start_code = [
f"source {PurePosixPath(tmp_home)}/.bash_profile", # HOME from os.environ not acknowledged
"micromamba info",
"echo $MAMBA_ROOT_PREFIX",
"echo $HOME",
"ls ~",
"echo $MAMBA_EXE",
]
elif interpreter == "zsh":
extra_start_code = ["source ~/.zshrc"]
call_interpreter(
extra_start_code + ["micromamba self-update --version 0.25.1 -c conda-forge"],
tmp_path,
interpreter,
interactive=False,
)
assert Path(mamba_exe).exists()
version = subprocess.check_output([mamba_exe, "--version"])
assert version.decode("utf8").strip() == "0.25.1"
assert not Path(mamba_exe + ".bkup").exists()
shutil.copyfile(mamba_exe + ".orig", mamba_exe)
os.chmod(mamba_exe, 0o755)