diff --git a/docs/changelog/763.bugfix.rst b/docs/changelog/763.bugfix.rst new file mode 100644 index 000000000..88cc3e0b1 --- /dev/null +++ b/docs/changelog/763.bugfix.rst @@ -0,0 +1 @@ +Support ``#`` character in path for the tox project - by :user:`gaborbernat`. diff --git a/src/tox/config/loader/ini/__init__.py b/src/tox/config/loader/ini/__init__.py index 5822555e0..55d67be3b 100644 --- a/src/tox/config/loader/ini/__init__.py +++ b/src/tox/config/loader/ini/__init__.py @@ -29,8 +29,10 @@ def __init__(self, section: str, parser: ConfigParser, overrides: List[Override] super().__init__(overrides) def load_raw(self, key: str, conf: Optional["Config"], env_name: Optional[str]) -> str: - value = self._section[key] + return self.process_raw(conf, env_name, self._section[key]) + @staticmethod + def process_raw(conf: Optional["Config"], env_name: Optional[str], value: str) -> str: # strip comments elements: List[str] = [] for line in value.split("\n"): @@ -38,7 +40,6 @@ def load_raw(self, key: str, conf: Optional["Config"], env_name: Optional[str]) part = _COMMENTS.sub("", line) elements.append(part.replace("\\#", "#")) strip_comments = "\n".join(elements) - if conf is None: # conf is None when we're loading the global tox configuration file for the CLI factor_filtered = strip_comments # we don't support factor and replace functionality there else: diff --git a/src/tox/config/loader/ini/replace.py b/src/tox/config/loader/ini/replace.py index 3e9d193f9..06facf615 100644 --- a/src/tox/config/loader/ini/replace.py +++ b/src/tox/config/loader/ini/replace.py @@ -120,9 +120,10 @@ def replace_reference( for src in _config_value_sources(settings["env"], settings["section"], current_env, conf, loader): try: if isinstance(src, SectionProxy): - return src[key] + return loader.process_raw(conf, current_env, src[key]) value = src.load(key, chain) as_str, _ = stringify(value) + as_str = as_str.replace("#", r"\#") # escape comment characters as these will be stripped return as_str except KeyError as exc: # if fails, keep trying maybe another source can satisfy exception = exc diff --git a/src/tox/config/loader/str_convert.py b/src/tox/config/loader/str_convert.py index 01a114e68..ba373af8e 100644 --- a/src/tox/config/loader/str_convert.py +++ b/src/tox/config/loader/str_convert.py @@ -47,8 +47,10 @@ def to_dict(value: str, of_type: Tuple[Type[Any], Type[Any]]) -> Iterator[Tuple[ @staticmethod def to_command(value: str) -> Command: is_win = sys.platform == "win32" + value = value.replace(r"\#", "#") splitter = shlex.shlex(value, posix=not is_win) splitter.whitespace_split = True + splitter.commenters = "" # comments handled earlier, and the shlex does not know escaped comment characters args: List[str] = [] pos = 0 try: diff --git a/src/tox/config/set_env.py b/src/tox/config/set_env.py index ce8365163..acfd52fa9 100644 --- a/src/tox/config/set_env.py +++ b/src/tox/config/set_env.py @@ -41,6 +41,7 @@ def load(self, item: str, chain: Optional[List[str]] = None) -> str: return self._materialized[item] raw = self._raw[item] result = self.replacer(raw, chain) # apply any replace options + result = result.replace(r"\#", "#") # unroll escaped comment with replacement self._materialized[item] = result self._raw.pop(item, None) # if the replace requires the env we may be called again, so allow pop to fail return result diff --git a/src/tox/pytest.py b/src/tox/pytest.py index 731233551..1516297c8 100644 --- a/src/tox/pytest.py +++ b/src/tox/pytest.py @@ -370,7 +370,9 @@ def matches(pattern: str, text: str, flags: int = 0) -> None: class ToxProjectCreator(Protocol): - def __call__(self, files: Dict[str, Any], base: Optional[Path] = None) -> ToxProject: # noqa: U100 + def __call__( + self, files: Dict[str, Any], base: Optional[Path] = None, prj_path: Optional[Path] = None # noqa: U100 + ) -> ToxProject: ... @@ -378,9 +380,9 @@ def __call__(self, files: Dict[str, Any], base: Optional[Path] = None) -> ToxPro def init_fixture( tmp_path: Path, capfd: CaptureFixture, monkeypatch: MonkeyPatch, mocker: MockerFixture ) -> ToxProjectCreator: - def _init(files: Dict[str, Any], base: Optional[Path] = None) -> ToxProject: + def _init(files: Dict[str, Any], base: Optional[Path] = None, prj_path: Optional[Path] = None) -> ToxProject: """create tox projects""" - return ToxProject(files, base, tmp_path / "p", capfd, monkeypatch, mocker) + return ToxProject(files, base, prj_path or tmp_path / "p", capfd, monkeypatch, mocker) return _init # noqa diff --git a/tests/session/cmd/test_show_config.py b/tests/session/cmd/test_show_config.py index bfeec5549..366766ffb 100644 --- a/tests/session/cmd/test_show_config.py +++ b/tests/session/cmd/test_show_config.py @@ -1,6 +1,8 @@ import platform import sys from configparser import ConfigParser +from pathlib import Path +from textwrap import dedent from typing import Callable, Tuple import pytest @@ -155,3 +157,27 @@ def test_show_config_description_normalize(tox_project: ToxProjectCreator) -> No outcome = tox_project({"tox.ini": tox_ini}).run("c", "-e", "py", "-k", "description") outcome.assert_success() assert outcome.out == "[testenv:py]\ndescription = A magical pipe of this\n" + + +def test_show_config_ini_comment_path(tox_project: ToxProjectCreator, tmp_path: Path) -> None: + prj_path = tmp_path / "#magic" + prj_path.mkdir() + ini = """ + [testenv] + package = skip + set_env = + A=1 # comment + # more comment + commands = {envpython} -c 'import os; print(os.linesep.join(f"{k}={v}" for k, v in os.environ.items()))' + [testenv:py] + set_env = + {[testenv]set_env} + B = {tox_root} # just some comment + """ + project = tox_project({"tox.ini": dedent(ini)}, prj_path=prj_path) + result = project.run("r", "-e", "py") + result.assert_success() + a_line = next(i for i in result.out.splitlines() if i.startswith("A=")) # pragma: no branch # not found raises + assert a_line == "A=1" + b_line = next(i for i in result.out.splitlines() if i.startswith("B=")) # pragma: no branch # not found raises + assert b_line == f"B={prj_path}" diff --git a/whitelist.txt b/whitelist.txt index c8163050f..c5fd2f259 100644 --- a/whitelist.txt +++ b/whitelist.txt @@ -27,6 +27,7 @@ chdir cmd codec colorama +commenters conf configs conftest