From c9e1fdb93eb28069f658afe072e6757d0c462c17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bern=C3=A1t=20G=C3=A1bor?= Date: Sat, 17 Dec 2022 11:53:58 -0800 Subject: [PATCH 1/2] Fix space not accepted in factor filter expression (#2743) Resolves https://github.com/tox-dev/tox/issues/2718 --- docs/changelog/2718.bugfix.rst | 1 + src/tox/config/loader/ini/factor.py | 2 +- tests/config/loader/ini/test_factor.py | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 docs/changelog/2718.bugfix.rst diff --git a/docs/changelog/2718.bugfix.rst b/docs/changelog/2718.bugfix.rst new file mode 100644 index 000000000..02e3cab8b --- /dev/null +++ b/docs/changelog/2718.bugfix.rst @@ -0,0 +1 @@ +Fix space not accepted in factor filter expression - by :user:`gaborbernat`. diff --git a/src/tox/config/loader/ini/factor.py b/src/tox/config/loader/ini/factor.py index 1c6f59fd7..3f547775b 100644 --- a/src/tox/config/loader/ini/factor.py +++ b/src/tox/config/loader/ini/factor.py @@ -48,7 +48,7 @@ def explode_factor(group: list[tuple[str, bool]]) -> str: def expand_factors(value: str) -> Iterator[tuple[Iterator[list[tuple[str, bool]]] | None, str]]: for line in value.split("\n"): - match = re.match(r"^((?P[\w{}.!,-]+):\s+)?(?P.*?)$", line) + match = re.match(r"^((?P[\w {}.!,-]+):\s+)?(?P.*?)$", line) if match is None: # pragma: no cover raise RuntimeError("for a valid factor regex this cannot happen") groups = match.groupdict() diff --git a/tests/config/loader/ini/test_factor.py b/tests/config/loader/ini/test_factor.py index 29c70a482..0a4e025a2 100644 --- a/tests/config/loader/ini/test_factor.py +++ b/tests/config/loader/ini/test_factor.py @@ -27,6 +27,7 @@ def complex_example() -> str: py: py only !py: not py {py,!pi}-{a,b}{,-dev},c: complex + py, d: space extra: extra more-default """, @@ -46,6 +47,7 @@ def test_factor_env_discover(complex_example: str) -> None: "pi-b", "pi-b-dev", "c", + "d", "extra", ] From 31ac5f250658d618860ec03f8e8104e371125571 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bern=C3=A1t=20G=C3=A1bor?= Date: Sat, 17 Dec 2022 12:24:49 -0800 Subject: [PATCH 2/2] Ask forgiveness MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bernát Gábor --- src/tox/config/loader/ini/factor.py | 24 ++++++++++--------- .../ini/replace/test_replace_posargs.py | 4 ++-- tests/session/cmd/test_list_envs.py | 2 ++ 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/tox/config/loader/ini/factor.py b/src/tox/config/loader/ini/factor.py index 3f547775b..731fe610c 100644 --- a/src/tox/config/loader/ini/factor.py +++ b/src/tox/config/loader/ini/factor.py @@ -46,18 +46,18 @@ def explode_factor(group: list[tuple[str, bool]]) -> str: return "-".join([name for name, _ in group]) -def expand_factors(value: str) -> Iterator[tuple[Iterator[list[tuple[str, bool]]] | None, str]]: +def expand_factors(value: str) -> Iterator[tuple[list[list[tuple[str, bool]]] | None, str]]: for line in value.split("\n"): - match = re.match(r"^((?P[\w {}.!,-]+):\s+)?(?P.*?)$", line) - if match is None: # pragma: no cover - raise RuntimeError("for a valid factor regex this cannot happen") - groups = match.groupdict() - factor_expr, content = groups["factor_expr"], groups["content"] - if factor_expr is not None: - factors = find_factor_groups(factor_expr) - yield factors, content - else: - yield None, content + factors: list[list[tuple[str, bool]]] | None = None + marker_at, content = line.find(":"), line + if marker_at != -1: + try: + factors = list(find_factor_groups(line[:marker_at].strip())) + except ValueError: + pass # when cannot extract factors keep the entire line + else: + content = line[marker_at + 1 :].strip() + yield factors, content def find_factor_groups(value: str) -> Iterator[list[tuple[str, bool]]]: @@ -76,6 +76,8 @@ def expand_env_with_negation(value: str) -> Iterator[str]: parts = [re.sub(r"\s+", "", elem).split(",") for elem in elements] for variant in product(*parts): variant_str = "".join(variant) + if not re.fullmatch(r"!?[\w._][\w._-]*", variant_str): + raise ValueError(variant_str) yield variant_str diff --git a/tests/config/loader/ini/replace/test_replace_posargs.py b/tests/config/loader/ini/replace/test_replace_posargs.py index 840869ac6..0ca258218 100644 --- a/tests/config/loader/ini/replace/test_replace_posargs.py +++ b/tests/config/loader/ini/replace/test_replace_posargs.py @@ -37,8 +37,8 @@ def test_replace_pos_args(syntax: str, replace_one: ReplaceOne) -> None: [ ("magic", "magic"), ("magic:colon", "magic:colon"), - ("magic\n b:c", "magic\nb:c"), # an unescaped newline keeps the newline - ("magi\\\n c:d", "magic:d"), # an escaped newline merges the lines + ("magic\n b c", "magic\nb c"), # an unescaped newline keeps the newline + ("magi\\\n c d", "magic d"), # an escaped newline merges the lines ("\\{a\\}", "{a}"), # escaped curly braces ], ) diff --git a/tests/session/cmd/test_list_envs.py b/tests/session/cmd/test_list_envs.py index 3d9b693a2..0ac0d5991 100644 --- a/tests/session/cmd/test_list_envs.py +++ b/tests/session/cmd/test_list_envs.py @@ -36,6 +36,7 @@ def test_list_env(project: ToxProject) -> None: additional environments: fix -> fix it + pypy -> with pypy """ outcome.assert_out_err(expected, "") @@ -62,6 +63,7 @@ def test_list_env_quiet(project: ToxProject) -> None: py31 py fix + pypy """ outcome.assert_out_err(expected, "")