|
9 | 9 | from concurrent.futures import FIRST_COMPLETED, CancelledError, Future, ThreadPoolExecutor |
10 | 10 | from concurrent.futures import wait as wait_futures |
11 | 11 | from fnmatch import fnmatchcase |
| 12 | +from operator import itemgetter |
12 | 13 | from pathlib import Path |
13 | 14 | from signal import SIGINT, Handlers, signal |
14 | 15 | from threading import Event, Thread |
|
24 | 25 | from tox.session.cmd.run.single import ToxEnvRunResult, run_one |
25 | 26 | from tox.tox_env.errors import Fail |
26 | 27 | from tox.util.graph import stable_topological_sort |
| 28 | +from tox.util.python_envs import record_python_envs |
27 | 29 | from tox.util.spinner import MISS_DURATION, Spinner |
28 | 30 |
|
29 | 31 | if TYPE_CHECKING: |
@@ -280,6 +282,8 @@ def _run_thread() -> tuple[Any, bool]: |
280 | 282 | ordered_results = _order_results(state, results, to_run_list) |
281 | 283 | # write the journal |
282 | 284 | write_journal(getattr(state.conf.options, "result_json", None), state._journal) # ruff:ignore[private-member-access] |
| 285 | + # let editors discover the environments |
| 286 | + _record_python_envs(state) |
283 | 287 | # warn about unused config keys |
284 | 288 | _warn_unused_config(state) |
285 | 289 | # report the outcome |
@@ -311,6 +315,22 @@ def _order_results(state: State, results: list[ToxEnvRunResult], to_run_list: li |
311 | 315 | return ordered |
312 | 316 |
|
313 | 317 |
|
| 318 | +def _record_python_envs(state: State) -> None: |
| 319 | + core = state.conf.core |
| 320 | + if not core["python_envs"]: |
| 321 | + return |
| 322 | + ranked: list[tuple[tuple[bool, bool, int], Path]] = [] |
| 323 | + for at, name in enumerate(state.envs.iter(only_active=False)): |
| 324 | + env = state.envs[name] |
| 325 | + if not (env.env_dir / "pyvenv.cfg").exists(): # not a Python environment a reader could use |
| 326 | + continue |
| 327 | + develop = "package" in env.conf and env.conf["package"] in {"editable", "editable-legacy"} |
| 328 | + # the default environment goes last: prefer one named dev, then a develop install, then the env list order |
| 329 | + ranked.append(((name == "dev", develop, -at), env.env_dir)) |
| 330 | + envs = [env_dir for _, env_dir in sorted(ranked, key=itemgetter(0))] |
| 331 | + record_python_envs(cast("Path", core["tox_root"]), cast("Path", core["work_dir"]), envs) |
| 332 | + |
| 333 | + |
314 | 334 | class ToxSpinner(Spinner): |
315 | 335 | def __init__(self, enabled: bool, state: State, total: int) -> None: # ruff:ignore[boolean-type-hint-positional-argument] |
316 | 336 | stream = state._options.log_handler.stdout # ruff:ignore[private-member-access] |
|
0 commit comments