summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBernát Gábor <bgabor8@bloomberg.net>2021-01-13 18:34:16 +0000
committerGitHub <noreply@github.com>2021-01-13 18:34:16 +0000
commitbad3dc570438385ccd84648a6050a89cb5ced0fa (patch)
treee14e0a0b8d3f0cb2e59f797fa1a693c4c9cfe6b1 /src
parent41c7eb4af57f5917926e0e0b348e1bc4b8c3bb70 (diff)
downloadtox-git-bad3dc570438385ccd84648a6050a89cb5ced0fa.tar.gz
Colorize config and fix a circular config bug (#1821)
Signed-off-by: Bernát Gábor <bgabor8@bloomberg.net>
Diffstat (limited to 'src')
-rw-r--r--src/tox/config/loader/ini/replace.py29
-rw-r--r--src/tox/config/loader/stringify.py3
-rw-r--r--src/tox/config/sets.py8
-rw-r--r--src/tox/session/cmd/show_config.py48
-rw-r--r--src/tox/tox_env/python/api.py2
-rw-r--r--src/tox/tox_env/runner.py22
6 files changed, 71 insertions, 41 deletions
diff --git a/src/tox/config/loader/ini/replace.py b/src/tox/config/loader/ini/replace.py
index f590b3dd..b0d4c445 100644
--- a/src/tox/config/loader/ini/replace.py
+++ b/src/tox/config/loader/ini/replace.py
@@ -110,8 +110,8 @@ def replace_reference(
settings = match.groupdict()
key = settings["key"]
- if settings["section"] is None and settings["full_env"] == BASE_TEST_ENV:
- settings["section"] = BASE_TEST_ENV
+ if settings["section"] is None and settings["full_env"]:
+ settings["section"] = settings["full_env"]
exception: Optional[Exception] = None
try:
@@ -152,20 +152,21 @@ def _config_value_sources(
else:
raise KeyError(f"missing tox environment with name {env}")
- # if we have a section name specified take only from there
- if section is not None:
- # special handle the core section under name tox
- if section == CORE_PREFIX:
- yield conf.core # try via registered configs
- value = loader.get_section(section) # fallback to section
- if value is not None:
- yield value
+ if section is None:
+ # if no section specified perhaps it's an unregistered config:
+ # 1. try first from core conf
+ yield conf.core
+ # 2. and then fallback to our own environment
+ if current_env is not None:
+ yield conf.get_env(current_env)
return
- # otherwise try first from core conf, and fallback to our own environment
- yield conf.core
- if current_env is not None:
- yield conf.get_env(current_env)
+ # if there's a section, special handle the core section under name tox
+ if section == CORE_PREFIX:
+ yield conf.core # try via registered configs
+ value = loader.get_section(section) # fallback to section
+ if value is not None:
+ yield value
def replace_pos_args(args: List[str], pos_args: Optional[Sequence[str]]) -> str:
diff --git a/src/tox/config/loader/stringify.py b/src/tox/config/loader/stringify.py
index da432252..0305534e 100644
--- a/src/tox/config/loader/stringify.py
+++ b/src/tox/config/loader/stringify.py
@@ -4,6 +4,7 @@ from typing import Any, Mapping, Sequence, Set, Tuple
from tox.config.set_env import SetEnv
from tox.config.types import Command, EnvList
+from tox.tox_env.python.req_file import RequirementsFile
def stringify(value: Any) -> Tuple[str, bool]:
@@ -29,6 +30,8 @@ def stringify(value: Any) -> Tuple[str, bool]:
return value.shell, True
if isinstance(value, SetEnv):
return stringify({k: value.load(k) for k in sorted(list(value))})
+ if isinstance(value, RequirementsFile):
+ return stringify(value.validate_and_expand())
return str(value), False
diff --git a/src/tox/config/sets.py b/src/tox/config/sets.py
index d8726d34..7d5d062e 100644
--- a/src/tox/config/sets.py
+++ b/src/tox/config/sets.py
@@ -87,9 +87,11 @@ class ConfigSet:
config_definition = self._defined[item]
if chain is None:
chain = []
- if item in chain:
- raise ValueError(f"circular chain detected {', '.join(chain[chain.index(item):])}")
- chain.append(item)
+ env_name = "tox" if self._name is None else f"testenv:{self._name}"
+ key = f"{env_name}.{item}"
+ if key in chain:
+ raise ValueError(f"circular chain detected {', '.join(chain[chain.index(key):])}")
+ chain.append(key)
return config_definition(self._conf, item, self.loaders, chain)
def __repr__(self) -> str:
diff --git a/src/tox/session/cmd/show_config.py b/src/tox/session/cmd/show_config.py
index d31606b7..18978df3 100644
--- a/src/tox/session/cmd/show_config.py
+++ b/src/tox/session/cmd/show_config.py
@@ -5,6 +5,8 @@ Show materialized configuration of tox environments.
from textwrap import indent
from typing import Iterable, List, Set
+from colorama import Fore
+
from tox.config.cli.parser import ToxParser
from tox.config.loader.stringify import stringify
from tox.config.sets import ConfigSet
@@ -29,6 +31,7 @@ def tox_add_option(parser: ToxParser) -> None:
def show_config(state: State) -> int:
+ is_colored = state.options.is_colored
keys: List[str] = state.options.list_keys_only
is_first = True
selected = state.options.env
@@ -39,10 +42,10 @@ def show_config(state: State) -> int:
is_first = False
else:
print("")
- print(f"[testenv:{tox_env.conf.name}]")
+ print_section_header(is_colored, f"[testenv:{tox_env.conf.name}]")
if not keys:
- print(f"type = {type(tox_env).__name__}")
- print_conf(tox_env.conf, keys)
+ print_key_value(is_colored, "type", type(tox_env).__name__)
+ print_conf(is_colored, tox_env.conf, keys)
envs = list(state.env_list(everything=True))
done_pkg_envs: Set[str] = set()
@@ -63,27 +66,48 @@ def show_config(state: State) -> int:
# environments may define core configuration flags, so we must exhaust first the environments to tell the core part
if selected.all or state.options.show_core:
print("")
- print("[tox]")
- print_conf(state.conf.core, keys)
+ print_section_header(is_colored, "[tox]")
+ print_conf(is_colored, state.conf.core, keys)
return 0
-def print_conf(conf: ConfigSet, keys: Iterable[str]) -> None:
+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
try:
value = conf[key]
except Exception as exception: # because e.g. the interpreter cannot be found
- as_str, multi_line = f"# Exception: {exception!r}", False
+ as_str, multi_line = _colored(is_colored, Fore.LIGHTRED_EX, f"# Exception: {exception!r}"), False
else:
as_str, multi_line = stringify(value)
if multi_line and "\n" not in as_str:
multi_line = False
- if multi_line and as_str.strip():
- print(f"{key} =\n{indent(as_str, prefix=' ')}")
- else:
- print(f"{key} ={' ' if as_str else ''}{as_str}")
+ print_key_value(is_colored, key, as_str, multi_line=multi_line)
unused = conf.unused()
if unused and not keys:
- print(f"# !!! unused: {', '.join(unused)}")
+ print_comment(is_colored, f"# !!! unused: {', '.join(unused)}")
diff --git a/src/tox/tox_env/python/api.py b/src/tox/tox_env/python/api.py
index fa5297a9..f2950dd7 100644
--- a/src/tox/tox_env/python/api.py
+++ b/src/tox/tox_env/python/api.py
@@ -79,6 +79,7 @@ class Python(ToxEnv, ABC):
super().__init__(conf, core, options, journal, log_handler)
def register_config(self) -> None:
+ super().register_config()
self.conf.add_config(
keys=["base_python", "basepython"],
of_type=List[str],
@@ -100,7 +101,6 @@ class Python(ToxEnv, ABC):
desc="python executable from within the tox environment",
value=lambda: self.env_python(),
)
- super().register_config()
def default_pass_env(self) -> List[str]:
env = super().default_pass_env()
diff --git a/src/tox/tox_env/runner.py b/src/tox/tox_env/runner.py
index 904d770c..1a44d7c0 100644
--- a/src/tox/tox_env/runner.py
+++ b/src/tox/tox_env/runner.py
@@ -24,7 +24,6 @@ class RunToxEnv(ToxEnv, ABC):
super().__init__(conf, core, options, journal, log_handler)
def register_config(self) -> None:
- super().register_config()
self.conf.add_config(
keys=["description"],
of_type=str,
@@ -32,11 +31,12 @@ class RunToxEnv(ToxEnv, ABC):
desc="description attached to the tox environment",
)
self.conf.add_config(
- keys=["commands"],
- of_type=List[Command],
- default=[],
- desc="the commands to be called for testing",
+ "depends",
+ of_type=EnvList,
+ desc="tox environments that this environment depends on (must be run after those)",
+ default=EnvList([]),
)
+ super().register_config()
self.conf.add_config(
keys=["commands_pre"],
of_type=List[Command],
@@ -44,6 +44,12 @@ class RunToxEnv(ToxEnv, ABC):
desc="the commands to be called before testing",
)
self.conf.add_config(
+ keys=["commands"],
+ of_type=List[Command],
+ default=[],
+ desc="the commands to be called for testing",
+ )
+ self.conf.add_config(
keys=["commands_post"],
of_type=List[Command],
default=[],
@@ -55,12 +61,6 @@ class RunToxEnv(ToxEnv, ABC):
default=lambda conf, name: cast(Path, conf.core["tox_root"]),
desc="Change to this working directory when executing the test command.",
)
- self.conf.add_config(
- "depends",
- of_type=EnvList,
- desc="tox environments that this environment depends on (must be run after those)",
- default=EnvList([]),
- )
self.has_package = self.add_package_conf()
def add_package_conf(self) -> bool: