1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
|
from __future__ import annotations
from argparse import Namespace
import pytest
from virtualenv.activation import BatchActivator
def test_batch_pydoc_bat_quoting(tmp_path):
"""Test that pydoc.bat properly quotes python.exe path to handle spaces."""
# GIVEN: A mock interpreter
class MockInterpreter:
os = "nt"
tcl_lib = None
tk_lib = None
class MockCreator:
def __init__(self, dest):
self.dest = dest
self.bin_dir = dest / "Scripts"
self.bin_dir.mkdir(parents=True)
self.interpreter = MockInterpreter()
self.pyenv_cfg = {}
self.env_name = "test-env"
creator = MockCreator(tmp_path)
options = Namespace(prompt=None)
activator = BatchActivator(options)
# WHEN: Generate activation scripts
activator.generate(creator)
# THEN: pydoc.bat should quote python.exe to handle paths with spaces
pydoc_content = (creator.bin_dir / "pydoc.bat").read_text(encoding="utf-8")
# The python.exe should be quoted to handle paths with spaces like "C:\Program Files\Python39\python.exe"
assert '"python.exe"' in pydoc_content, f"python.exe should be quoted in pydoc.bat. Content:\n{pydoc_content}"
@pytest.mark.parametrize(
("tcl_lib", "tk_lib", "present"),
[
("C:\\tcl", "C:\\tk", True),
(None, None, False),
],
)
def test_batch_tkinter_generation(tmp_path, tcl_lib, tk_lib, present):
# GIVEN
class MockInterpreter:
os = "nt"
interpreter = MockInterpreter()
interpreter.tcl_lib = tcl_lib
interpreter.tk_lib = tk_lib
class MockCreator:
def __init__(self, dest):
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 = BatchActivator(options)
# WHEN
activator.generate(creator)
activate_content = (creator.bin_dir / "activate.bat").read_text(encoding="utf-8")
deactivate_content = (creator.bin_dir / "deactivate.bat").read_text(encoding="utf-8")
# THEN
# PKG_CONFIG_PATH is always set
assert '@if defined PKG_CONFIG_PATH @set "_OLD_PKG_CONFIG_PATH=%PKG_CONFIG_PATH%"' in activate_content
assert '@set "PKG_CONFIG_PATH=%VIRTUAL_ENV%\\lib\\pkgconfig;%PKG_CONFIG_PATH%"' in activate_content
assert '@if defined _OLD_PKG_CONFIG_PATH @set "PKG_CONFIG_PATH=%_OLD_PKG_CONFIG_PATH%"' in deactivate_content
assert "@if not defined _OLD_PKG_CONFIG_PATH @set PKG_CONFIG_PATH=" in deactivate_content
assert "@set _OLD_PKG_CONFIG_PATH=" in deactivate_content
if present:
assert '@if NOT "C:\\tcl"=="" @set "TCL_LIBRARY=C:\\tcl"' in activate_content
assert '@if NOT "C:\\tk"=="" @set "TK_LIBRARY=C:\\tk"' in activate_content
assert "if defined _OLD_VIRTUAL_TCL_LIBRARY" in deactivate_content
assert "if defined _OLD_VIRTUAL_TK_LIBRARY" in deactivate_content
else:
assert '@if NOT ""=="" @set "TCL_LIBRARY="' in activate_content
assert '@if NOT ""=="" @set "TK_LIBRARY="' in activate_content
@pytest.mark.usefixtures("activation_python")
def test_batch(activation_tester_class, activation_tester, tmp_path):
version_script = tmp_path / "version.bat"
version_script.write_text("ver", encoding="utf-8")
class Batch(activation_tester_class):
def __init__(self, session) -> None:
super().__init__(BatchActivator, session, None, "activate.bat", "bat")
self._version_cmd = [str(version_script)]
self._invoke_script = []
self.deactivate = "call deactivate"
self.activate_cmd = "call"
self.pydoc_call = f"call {self.pydoc_call}"
self.unix_line_ending = False
def _get_test_lines(self, activate_script):
return ["@echo off", *super()._get_test_lines(activate_script)]
def quote(self, s):
if '"' in s or " " in s:
text = s.replace('"', r"\"")
return f'"{text}"'
return s
def print_prompt(self):
return 'echo "%PROMPT%"'
activation_tester(Batch)
@pytest.mark.usefixtures("activation_python")
def test_batch_output(activation_tester_class, activation_tester, tmp_path):
version_script = tmp_path / "version.bat"
version_script.write_text("ver", encoding="utf-8")
class Batch(activation_tester_class):
def __init__(self, session) -> None:
super().__init__(BatchActivator, session, None, "activate.bat", "bat")
self._version_cmd = [str(version_script)]
self._invoke_script = []
self.deactivate = "call deactivate"
self.activate_cmd = "call"
self.pydoc_call = f"call {self.pydoc_call}"
self.unix_line_ending = False
def _get_test_lines(self, activate_script):
"""Build intermediary script which will be then called. In the script just activate environment, call echo to get current echo setting, and then deactivate. This ensures that echo setting is preserved and no unwanted output appears."""
intermediary_script_path = str(tmp_path / "intermediary.bat")
activate_script_quoted = self.quote(str(activate_script))
return [
"@echo on",
f"@echo @call {activate_script_quoted} > {intermediary_script_path}",
f"@echo @echo >> {intermediary_script_path}",
f"@echo @deactivate >> {intermediary_script_path}",
f"@call {intermediary_script_path}",
]
def assert_output(self, out, raw, tmp_path): # noqa: ARG002
assert out[0] == "ECHO is on.", raw
def quote(self, s):
if '"' in s or " " in s:
text = s.replace('"', r"\"")
return f'"{text}"'
return s
def print_prompt(self):
return 'echo "%PROMPT%"'
activation_tester(Batch)
|