Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved factor selection to allow multiple uses of -f for "OR" and to allow hyphenated factors #2786

Merged
merged 9 commits into from Dec 29, 2022
1 change: 1 addition & 0 deletions docs/changelog/2766.feature.rst
@@ -0,0 +1 @@
``-f`` can be used multiple times and on hyphenated factors (e.g. ``-f py311-django -f py39``) - by :user:`sirosen`.
33 changes: 27 additions & 6 deletions src/tox/session/env_select.py
Expand Up @@ -91,8 +91,19 @@ def register_env_select_flags(
if multiple:
help_msg = "labels to evaluate"
add_to.add_argument("-m", dest="labels", metavar="label", help=help_msg, default=[], type=str, nargs="+")
help_msg = "factors to evaluate"
add_to.add_argument("-f", dest="factors", metavar="factor", help=help_msg, default=[], type=str, nargs="+")
help_msg = (
"factors to evaluate (passing multiple factors means 'AND', passing this option multiple times means 'OR')"
)
add_to.add_argument(
"-f",
dest="factors",
metavar="factor",
help=help_msg,
default=[],
type=str,
nargs="+",
action="append",
)
help_msg = "exclude all environments selected that match this regular expression"
add_to.add_argument("--skip-env", dest="skip_env", metavar="re", help=help_msg, default="", type=str)
return add_to
Expand Down Expand Up @@ -288,9 +299,17 @@ def _get_package_env(self, packager: str, name: str, is_active: bool) -> Package
self._manager.tox_add_env_config(pkg_conf, self._state)
return pkg_env

def _parse_factors(self) -> tuple[set[str], ...]:
# factors is a list of lists, from the combination of nargs="+" and action="append"
# also parse hyphenated factors into lists of factors
# so that `-f foo-bar` and `-f foo bar` are treated equivalently
raw_factors = getattr(self._state.conf.options, "factors", [])
return tuple({f for factor in factor_list for f in factor.split("-")} for factor_list in raw_factors)

def _mark_active(self) -> None:
labels = set(getattr(self._state.conf.options, "labels", []))
factors = set(getattr(self._state.conf.options, "factors", []))
factors = self._parse_factors()

assert self._defined_envs_ is not None
if labels or factors:
for env_info in self._defined_envs_.values():
Expand All @@ -302,10 +321,12 @@ def _mark_active(self) -> None:
for env_info in self._defined_envs_.values():
if labels.intersection(env_info.env.conf["labels"]):
env_info.is_active = True
if self._state.conf.options.factors: # if matches mark it active
if factors: # if matches mark it active
for name, env_info in self._defined_envs_.items():
if factors.issubset(set(name.split("-"))):
env_info.is_active = True
for factor_set in factors:
if factor_set.issubset(set(name.split("-"))):
env_info.is_active = True
gaborbernat marked this conversation as resolved.
Show resolved Hide resolved
break

def __getitem__(self, item: str) -> RunToxEnv | PackageToxEnv:
"""
Expand Down
29 changes: 26 additions & 3 deletions tests/session/test_env_select.py
@@ -1,5 +1,7 @@
from __future__ import annotations

import pytest

from tox.pytest import MonkeyPatch, ToxProjectCreator


Expand Down Expand Up @@ -61,15 +63,36 @@ def test_label_core_and_trait(tox_project: ToxProjectCreator) -> None:
outcome.assert_out_err("py310\npy39\nflake8\ntype\n", "")


def test_factor_select(tox_project: ToxProjectCreator) -> None:
@pytest.mark.parametrize(
("selection_arguments", "expect_envs"),
[
(
("-f", "cov", "django20"),
("py310-django20-cov", "py39-django20-cov"),
),
(
("-f", "cov-django20"),
("py310-django20-cov", "py39-django20-cov"),
),
(
("-f", "py39", "django20", "-f", "py310", "django21"),
("py310-django21-cov", "py310-django21", "py39-django20-cov", "py39-django20"),
),
],
)
def test_factor_select(
tox_project: ToxProjectCreator,
selection_arguments: tuple[str, ...],
expect_envs: tuple[str, ...],
) -> None:
ini = """
[tox]
env_list = py3{10,9}-{django20,django21}{-cov,}
"""
project = tox_project({"tox.ini": ini})
outcome = project.run("l", "--no-desc", "-f", "cov", "django20")
outcome = project.run("l", "--no-desc", *selection_arguments)
outcome.assert_success()
outcome.assert_out_err("py310-django20-cov\npy39-django20-cov\n", "")
outcome.assert_out_err("{}\n".format("\n".join(expect_envs)), "")


def test_tox_skip_env(tox_project: ToxProjectCreator, monkeypatch: MonkeyPatch) -> None:
Expand Down