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
|
"""
Show materialized configuration of tox environments.
"""
from __future__ import annotations
from textwrap import indent
from typing import Iterable
from colorama import Fore
from tox.config.cli.parser import ToxParser
from tox.config.loader.stringify import stringify
from tox.config.sets import ConfigSet
from tox.plugin import impl
from tox.session.cmd.run.common import env_run_create_flags
from tox.session.env_select import CliEnv, register_env_select_flags
from tox.session.state import State
from tox.tox_env.api import ToxEnv
@impl
def tox_add_option(parser: ToxParser) -> None:
our = parser.add_command("config", ["c"], "show tox configuration", show_config)
our.add_argument(
"-k",
nargs="+",
help="list just configuration keys specified",
dest="list_keys_only",
default=[],
metavar="key",
)
our.add_argument(
"--core",
action="store_true",
help="show core options (by default is hidden unless -e ALL is passed)",
dest="show_core",
)
register_env_select_flags(our, default=CliEnv())
env_run_create_flags(our, mode="config")
def show_config(state: State) -> int:
is_colored = state.conf.options.is_colored
keys: list[str] = state.conf.options.list_keys_only
is_first = True
def _print_env(tox_env: ToxEnv) -> None:
nonlocal is_first
if is_first:
is_first = False
else:
print("")
print_section_header(is_colored, f"[testenv:{tox_env.conf.name}]")
if not keys:
print_key_value(is_colored, "type", type(tox_env).__name__)
print_conf(is_colored, tox_env.conf, keys)
show_everything = state.conf.options.env.is_all
done: set[str] = set()
for name in state.envs.iter(package=True): # now go through selected ones
done.add(name)
_print_env(state.envs[name])
# environments may define core configuration flags, so we must exhaust first the environments to tell the core part
if show_everything or state.conf.options.show_core:
print("")
print_section_header(is_colored, "[tox]")
print_conf(is_colored, state.conf.core, keys)
return 0
def _colored(is_colored: bool, color: int, msg: str) -> str:
return f"{color}{msg}{Fore.RESET}" if is_colored else msg
def print_section_header(is_colored: bool, name: str) -> None:
print(_colored(is_colored, Fore.YELLOW, name))
def print_comment(is_colored: bool, comment: str) -> None:
print(_colored(is_colored, Fore.CYAN, comment))
def print_key_value(is_colored: bool, key: str, value: str, multi_line: bool = False) -> None:
print(_colored(is_colored, Fore.GREEN, key), end="")
print(" =", end="")
if multi_line:
print("")
value_str = indent(value, prefix=" ")
else:
print(" ", end="")
value_str = value
print(value_str)
def print_conf(is_colored: bool, conf: ConfigSet, keys: Iterable[str]) -> None:
for key in keys if keys else conf:
if key not in conf:
continue
key = conf.primary_key(key)
try:
value = conf[key]
as_str, multi_line = stringify(value)
except Exception as exception: # because e.g. the interpreter cannot be found
as_str, multi_line = _colored(is_colored, Fore.LIGHTRED_EX, f"# Exception: {exception!r}"), False
if multi_line and "\n" not in as_str:
multi_line = False
print_key_value(is_colored, key, as_str, multi_line=multi_line)
unused = conf.unused()
if unused and not keys:
print_comment(is_colored, f"# !!! unused: {', '.join(unused)}")
|