diff options
author | Bernát Gábor <bgabor8@bloomberg.net> | 2021-01-13 18:34:16 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-01-13 18:34:16 +0000 |
commit | bad3dc570438385ccd84648a6050a89cb5ced0fa (patch) | |
tree | e14e0a0b8d3f0cb2e59f797fa1a693c4c9cfe6b1 /src | |
parent | 41c7eb4af57f5917926e0e0b348e1bc4b8c3bb70 (diff) | |
download | tox-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.py | 29 | ||||
-rw-r--r-- | src/tox/config/loader/stringify.py | 3 | ||||
-rw-r--r-- | src/tox/config/sets.py | 8 | ||||
-rw-r--r-- | src/tox/session/cmd/show_config.py | 48 | ||||
-rw-r--r-- | src/tox/tox_env/python/api.py | 2 | ||||
-rw-r--r-- | src/tox/tox_env/runner.py | 22 |
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: |