1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
from typing import TYPE_CHECKING, Dict, Iterator, Optional, Sequence, Set, Tuple, cast
from tox.config.main import Config
from tox.config.sets import EnvConfigSet
from tox.journal import Journal
from tox.plugin import impl
from tox.report import HandledError, ToxHandler
from tox.session.common import CliEnv
from tox.tox_env.package import PackageToxEnv
from tox.tox_env.runner import RunToxEnv
if TYPE_CHECKING:
from tox.config.cli.parse import Handlers
from tox.config.cli.parser import Parsed, ToxParser
class State:
def __init__(
self,
conf: Config,
opt_parse: Tuple["Parsed", "Handlers"],
args: Sequence[str],
log_handler: ToxHandler,
) -> None:
self.conf = conf
self.conf.register_config_set = self.register_config_set
options, cmd_handlers = opt_parse
self.options = options
self.cmd_handlers = cmd_handlers
self.log_handler = log_handler
self.args = args
self._run_env: Dict[str, RunToxEnv] = {}
self._pkg_env: Dict[str, Tuple[str, PackageToxEnv]] = {}
self._pkg_env_discovered: Set[str] = set()
self.journal: Journal = Journal(getattr(options, "result_json", None) is not None)
def env_list(self, everything: bool = False) -> Iterator[str]:
fallback_env = "py"
use_env_list: Optional[CliEnv] = getattr(self.options, "env", None)
if everything or (use_env_list is not None and use_env_list.all):
_at = 0
for _at, env in enumerate(self.conf, start=1):
yield env
if _at == 0: # if we discovered no other env, inject the default
yield fallback_env
return
if use_env_list is not None and use_env_list.use_default_list:
use_env_list = self.conf.core["env_list"]
if use_env_list is None or bool(use_env_list) is False:
use_env_list = CliEnv([fallback_env])
yield from use_env_list
def tox_env(self, name: str) -> RunToxEnv:
if name in self._pkg_env_discovered:
raise HandledError(f"cannot run packaging environment {name}")
with self.log_handler.with_context(name):
tox_env = self._run_env.get(name)
if tox_env is not None:
return tox_env
self.conf.get_env(name) # the lookup here will trigger register_config_set, which will build it
return self._run_env[name]
def register_config_set(self, name: str, config_set: EnvConfigSet) -> None:
"""Ensure the config set with the given name has been registered with configuration values"""
# during the creation of the tox environment we automatically register configurations, so to ensure
# config sets have a set of defined values in it we have to ensure the tox environment is created
if name in self._pkg_env_discovered:
return # packaging environments are created explicitly, nothing to do here
if name in self._run_env: # pragma: no branch
raise ValueError(f"{name} run tox env already defined") # pragma: no cover
# runtime environments are created upon lookup via the tox_env method, call it
self._build_run_env(config_set)
def _build_run_env(self, env_conf: EnvConfigSet) -> None:
env_conf.add_config(
keys="runner",
desc="the tox execute used to evaluate this environment",
of_type=str,
default=self.options.default_runner, # noqa
)
runner = cast(str, env_conf["runner"])
from tox.tox_env.register import REGISTER
builder = REGISTER.runner(runner)
name = env_conf.name
journal = self.journal.get_env_journal(name)
env: RunToxEnv = builder(env_conf, self.conf.core, self.options, journal, self.log_handler)
self._run_env[name] = env
self._build_package_env(env)
def _build_package_env(self, env: RunToxEnv) -> None:
for tag, name, core_type in env.iter_package_env_types():
with self.log_handler.with_context(name):
package_tox_env = self._get_package_env(core_type, name)
env.notify_of_package_env(tag, package_tox_env)
def _get_package_env(self, packager: str, name: str) -> PackageToxEnv:
if name in self._pkg_env: # if already created reuse
old, pkg_tox_env = self._pkg_env[name]
if old != packager: # pragma: no branch # same env name is used by different packaging: dpkg vs virtualenv
msg = f"{name} is already defined as a {old}, cannot be {packager} too" # pragma: no cover
raise HandledError(msg) # pragma: no cover
else:
from tox.tox_env.register import REGISTER
package_type = REGISTER.package(packager)
self._pkg_env_discovered.add(name)
if name in self._run_env:
raise HandledError(f"{name} is already defined as a run environment, cannot be packaging too")
pkg_conf = self.conf.get_env(name, package=True)
journal = self.journal.get_env_journal(name)
pkg_tox_env = package_type(pkg_conf, self.conf.core, self.options, journal, self.log_handler)
self._pkg_env[name] = packager, pkg_tox_env
return pkg_tox_env
def run_envs(self) -> Iterator[Tuple[str, RunToxEnv]]:
yield from self._run_env.items()
@impl
def tox_add_option(parser: "ToxParser") -> None:
from tox.tox_env.register import REGISTER
parser.add_argument(
"--runner",
dest="default_runner",
help="the tox run engine to use when not explicitly stated in tox env configuration",
default=REGISTER.default_run_env,
choices=list(REGISTER.run_envs),
)
|