Skip to content

Commit

Permalink
Consider complete envs, not factors
Browse files Browse the repository at this point in the history
To determine whether we have been given a valid *env*, we compare the
*factors* of the *env* to our known set of *factors*. If a testenv
contains a series of valid factors, we assume the testenv is valid. This
is an incorrect assumption: a testenv is only valid if it defined in the
configuration file *or* is one of the "special" auto-generated testenvs
like e.g. 'py310'. Correct this mistake.

While we're here, we make use of verbose mode to explain our regex for
matching "magic" factors better.

Signed-off-by: Stephen Finucane <stephen@that.guru>
Closes: #3219
  • Loading branch information
stephenfin committed Feb 15, 2024
1 parent 47bcea6 commit 9b0529c
Showing 1 changed file with 25 additions and 22 deletions.
47 changes: 25 additions & 22 deletions src/tox/session/env_select.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,20 @@ class _ToxEnvInfo:
package_skip: tuple[str, Skip] | None = None #: if set the creation of the packaging environment failed


_DYNAMIC_ENV_FACTORS = re.compile(r"(pypy|py|cython|)((\d(\.\d+(\.\d+)?)?)|\d+)?")
_PY_PRE_RELEASE_FACTOR = re.compile(r"alpha|beta|rc\.\d+")
_DYNAMIC_ENV_FACTORS = re.compile(
r"""
(pypy|py|cython|) # interpreter
(
(
(\d(\.\d+(\.\d+)?)?) # major[.minor[.patch]] version
|
\d+ # major[minor[patch]] version
)
(-(alpha|beta|rc\.\d+))? # pre-release tag
)?
""",
re.VERBOSE,
)


class EnvSelector:
Expand Down Expand Up @@ -183,30 +195,21 @@ def _collect_names(self) -> Iterator[tuple[Iterable[str], bool]]:
yield label_envs.keys(), False

def _ensure_envs_valid(self) -> None:
valid_factors = set(chain.from_iterable(env.split("-") for env in self._state.conf))
valid_factors.add(".pkg") # packaging factor
conf_envs = set(self._state.conf)
conf_envs.add(".pkg") # packaging factor
valid_envs: set[str] = set()
invalid_envs: dict[str, str | None] = {}
for env in self._cli_envs or []:
if env.startswith(".pkg_external"): # external package
continue
factors: dict[str, str | None] = dict.fromkeys(env.split("-"))
found_factors: set[str] = set()
for factor in factors:
if (
_DYNAMIC_ENV_FACTORS.fullmatch(factor)
or _PY_PRE_RELEASE_FACTOR.fullmatch(factor)
or factor in valid_factors
):
found_factors.add(factor)
else:
closest = get_close_matches(factor, valid_factors, n=1)
factors[factor] = closest[0] if closest else None
if set(factors) - found_factors:
invalid_envs[env] = (
None
if any(i is None for i in factors.values())
else "-".join(cast(Iterable[str], factors.values()))
)

if _DYNAMIC_ENV_FACTORS.fullmatch(env) or env in conf_envs:
valid_envs.add(env)
continue

closest = get_close_matches(env, conf_envs, n=1)
invalid_envs[env] = closest[0] if closest else None

if invalid_envs:
msg = "provided environments not found in configuration file:\n"
first = True
Expand Down

0 comments on commit 9b0529c

Please sign in to comment.