| from __future__ import annotations |
| |
| import shlex |
| import shutil |
| import subprocess |
| import sys |
| from argparse import Namespace |
| |
| import pytest |
| |
| from virtualenv.activation import BashActivator |
| from virtualenv.info import IS_WIN |
| from virtualenv.run import cli_run |
| |
| |
| @pytest.mark.skipif(IS_WIN, reason="Github Actions ships with WSL bash") |
| @pytest.mark.parametrize( |
| ("tcl_lib", "tk_lib", "present"), |
| [ |
| ("/path/to/tcl", "/path/to/tk", True), |
| (None, None, False), |
| ], |
| ) |
| def test_bash_tkinter_generation(tmp_path, tcl_lib, tk_lib, present) -> None: |
| # GIVEN |
| class MockInterpreter: |
| pass |
| |
| interpreter = MockInterpreter() |
| interpreter.tcl_lib = tcl_lib |
| interpreter.tk_lib = tk_lib |
| |
| class MockCreator: |
| def __init__(self, dest) -> None: |
| self.dest = dest |
| self.bin_dir = dest / "bin" |
| self.bin_dir.mkdir() |
| self.interpreter = interpreter |
| self.pyenv_cfg = {} |
| self.env_name = "my-env" |
| |
| creator = MockCreator(tmp_path) |
| options = Namespace(prompt=None) |
| activator = BashActivator(options) |
| |
| # WHEN |
| activator.generate(creator) |
| content = (creator.bin_dir / "activate").read_text(encoding="utf-8") |
| |
| # THEN |
| # The teardown logic is always present in deactivate() |
| assert "unset _OLD_VIRTUAL_TCL_LIBRARY" in content |
| assert "unset _OLD_VIRTUAL_TK_LIBRARY" in content |
| assert "unset _OLD_PKG_CONFIG_PATH" in content |
| |
| # PKG_CONFIG_PATH is always set |
| assert '_OLD_PKG_CONFIG_PATH="${PKG_CONFIG_PATH:-}"' in content |
| assert 'PKG_CONFIG_PATH="${VIRTUAL_ENV}/lib/pkgconfig${PKG_CONFIG_PATH:+:${PKG_CONFIG_PATH}}"' in content |
| assert "export PKG_CONFIG_PATH" in content |
| assert 'PKG_CONFIG_PATH="$_OLD_PKG_CONFIG_PATH"' in content |
| |
| if present: |
| assert 'if [ /path/to/tcl != "" ]; then' in content |
| assert "TCL_LIBRARY=/path/to/tcl" in content |
| assert "export TCL_LIBRARY" in content |
| |
| assert 'if [ /path/to/tk != "" ]; then' in content |
| assert "TK_LIBRARY=/path/to/tk" in content |
| assert "export TK_LIBRARY" in content |
| else: |
| # When not present, the if condition is false, so the block is not executed |
| assert "if [ '' != \"\" ]; then" in content, content |
| assert "TCL_LIBRARY=''" in content |
| # The export is inside the if, so this is fine |
| assert "export TCL_LIBRARY" in content |
| |
| |
| @pytest.mark.skipif(IS_WIN, reason="Github Actions ships with WSL bash") |
| def test_bash_activate_relocation_resolves_virtual_env(tmp_path, current_fastest) -> None: |
| original = tmp_path / "original" |
| cli_run([ |
| "--without-pip", |
| str(original), |
| "--creator", |
| current_fastest, |
| "--no-periodic-update", |
| "--activators", |
| "bash", |
| ]) |
| relocated = tmp_path / "relocated" |
| shutil.move(original, relocated) |
| |
| work_dir = tmp_path / "workdir" |
| work_dir.mkdir() |
| activate_script = relocated / "bin" / "activate" |
| result = subprocess.run( |
| ["bash", "-c", f'source "{activate_script}" 2>/dev/null && echo "$VIRTUAL_ENV"'], |
| capture_output=True, |
| text=True, |
| cwd=str(work_dir), |
| encoding="utf-8", |
| ) |
| assert result.returncode == 0 |
| assert result.stdout.strip() == str(relocated) |
| |
| |
| @pytest.mark.skipif(IS_WIN, reason="Github Actions ships with WSL bash") |
| def test_bash_activate_does_not_export_ps1(tmp_path, current_fastest) -> None: |
| dest = tmp_path / "env" |
| cli_run([ |
| "--without-pip", |
| str(dest), |
| "--creator", |
| current_fastest, |
| "--no-periodic-update", |
| "--activators", |
| "bash", |
| ]) |
| activate_script = dest / "bin" / "activate" |
| print_ps1 = f"{shlex.quote(sys.executable)} -c 'import os; print(os.environ.get(\"PS1\"))'" |
| result = subprocess.run( |
| [ |
| "bash", |
| "-c", |
| (f"unset PS1; PS1='base$ '; source \"{activate_script}\" && {print_ps1} && deactivate && {print_ps1}"), |
| ], |
| capture_output=True, |
| encoding="utf-8", |
| text=True, |
| ) |
| assert result.returncode == 0, result.stderr |
| assert result.stdout.splitlines() == ["None", "None"] |
| |
| |
| @pytest.mark.skipif(IS_WIN, reason="Github Actions ships with WSL bash") |
| @pytest.mark.parametrize("hashing_enabled", [True, False]) |
| def test_bash(raise_on_non_source_class, hashing_enabled, activation_tester) -> None: |
| class Bash(raise_on_non_source_class): |
| def __init__(self, session) -> None: |
| super().__init__( |
| BashActivator, |
| session, |
| "bash", |
| "activate", |
| "sh", |
| "You must source this script: $ source ", |
| ) |
| self.deactivate += " || exit 1" |
| self._invoke_script.append("-h" if hashing_enabled else "+h") |
| |
| def activate_call(self, script): |
| return super().activate_call(script) + " || exit 1" |
| |
| def print_prompt(self): |
| return 'printf "%s\\n" "$PS1"' |
| |
| activation_tester(Bash) |