Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better selection support #2290

Merged
merged 5 commits into from
Jan 4, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 16 additions & 7 deletions src/tox/config/cli/parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,26 @@
"""
from __future__ import annotations

from typing import Dict, Sequence, cast
from typing import TYPE_CHECKING, Callable, NamedTuple, Sequence, cast

from tox.config.source import Source, discover_source
from tox.report import ToxHandler, setup_report

from .parser import Handler, Parsed, ToxParser
from .parser import Parsed, ToxParser

Handlers = Dict[str, Handler]
if TYPE_CHECKING:
from tox.session.state import State


def get_options(*args: str) -> tuple[Parsed, Handlers, Sequence[str] | None, ToxHandler, Source]:
class Options(NamedTuple):
parsed: Parsed
pos_args: Sequence[str] | None
source: Source
cmd_handlers: dict[str, Callable[[State], int]]
log_handler: ToxHandler


def get_options(*args: str) -> Options:
pos_args: tuple[str, ...] | None = None
try: # remove positional arguments passed to parser if specified, they are pulled directly from sys.argv
pos_arg_at = args.index("--")
Expand All @@ -27,7 +36,7 @@ def get_options(*args: str) -> tuple[Parsed, Handlers, Sequence[str] | None, Tox
parsed, cmd_handlers = _get_all(args)
if guess_verbosity != parsed.verbosity:
setup_report(parsed.verbosity, parsed.is_colored) # pragma: no cover
return parsed, cmd_handlers, pos_args, log_handler, source
return Options(parsed, pos_args, source, cmd_handlers, log_handler)


def _get_base(args: Sequence[str]) -> tuple[int, ToxHandler, Source]:
Expand All @@ -45,7 +54,7 @@ def _get_base(args: Sequence[str]) -> tuple[int, ToxHandler, Source]:
return guess_verbosity, handler, source


def _get_all(args: Sequence[str]) -> tuple[Parsed, Handlers]:
def _get_all(args: Sequence[str]) -> tuple[Parsed, dict[str, Callable[[State], int]]]:
"""Parse all the options."""
tox_parser = _get_parser()
parsed = cast(Parsed, tox_parser.parse_args(args))
Expand Down Expand Up @@ -75,5 +84,5 @@ def _get_parser_doc() -> ToxParser:

__all__ = (
"get_options",
"Handlers",
"Options",
)
19 changes: 12 additions & 7 deletions src/tox/config/cli/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@
import sys
from argparse import SUPPRESS, Action, ArgumentDefaultsHelpFormatter, ArgumentParser, Namespace
from pathlib import Path
from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Type, TypeVar, cast
from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Sequence, Tuple, Type, TypeVar, cast

from tox.config.loader.str_convert import StrConvert
from tox.plugin import NAME
from tox.session.state import State

from .env_var import get_env_var
from .ini import IniConfig
Expand All @@ -23,6 +22,9 @@
else: # pragma: no cover (py38+)
from typing_extensions import Literal

if TYPE_CHECKING:
from tox.session.state import State


class ArgumentParserWithEnvAndConfig(ArgumentParser):
"""
Expand Down Expand Up @@ -93,8 +95,6 @@ def _get_help_string(self, action: Action) -> str | None:
return text


Handler = Callable[[State], int]

ToxParserT = TypeVar("ToxParserT", bound="ToxParser")
DEFAULT_VERBOSITY = 2

Expand Down Expand Up @@ -122,7 +122,7 @@ class ToxParser(ArgumentParserWithEnvAndConfig):

def __init__(self, *args: Any, root: bool = False, add_cmd: bool = False, **kwargs: Any) -> None:
self.of_cmd: str | None = None
self.handlers: dict[str, tuple[Any, Handler]] = {}
self.handlers: dict[str, tuple[Any, Callable[[State], int]]] = {}
self._arguments: list[ArgumentArgs] = []
self._groups: list[tuple[Any, dict[str, Any], list[tuple[dict[str, Any], list[ArgumentArgs]]]]] = []
super().__init__(*args, **kwargs)
Expand All @@ -136,7 +136,13 @@ def __init__(self, *args: Any, root: bool = False, add_cmd: bool = False, **kwar
else:
self._cmd = None

def add_command(self, cmd: str, aliases: Sequence[str], help_msg: str, handler: Handler) -> ArgumentParser:
def add_command(
self,
cmd: str,
aliases: Sequence[str],
help_msg: str,
handler: Callable[[State], int],
) -> ArgumentParser:
if self._cmd is None:
raise RuntimeError("no sub-command group allowed")
sub_parser: ToxParser = self._cmd.add_parser(
Expand Down Expand Up @@ -315,5 +321,4 @@ def add_core_arguments(parser: ArgumentParser) -> None:
"DEFAULT_VERBOSITY",
"Parsed",
"ToxParser",
"Handler",
)
8 changes: 5 additions & 3 deletions src/tox/config/loader/memory.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
from __future__ import annotations

from pathlib import Path
from typing import Any, Iterator, cast
from typing import TYPE_CHECKING, Any, Iterator, TypeVar, cast

from tox.config.loader.convert import T
from tox.config.main import Config
from tox.config.types import Command, EnvList

from .api import Loader
from .section import Section
from .str_convert import StrConvert

if TYPE_CHECKING:
from tox.config.main import Config
T = TypeVar("T")


class MemoryLoader(Loader[Any]):
def __init__(self, **kwargs: Any) -> None:
Expand Down
41 changes: 6 additions & 35 deletions src/tox/config/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@
import os
from collections import OrderedDict, defaultdict
from pathlib import Path
from typing import TYPE_CHECKING, Any, Callable, Iterator, Sequence, TypeVar
from typing import TYPE_CHECKING, Any, Iterator, Sequence, TypeVar

from tox.config.loader.api import Loader, OverrideMap

from ..session.common import CliEnv
from .loader.section import Section
from .sets import ConfigSet, CoreConfigSet, EnvConfigSet
from .source import Source

if TYPE_CHECKING:
from .cli.parser import Parsed


T = TypeVar("T", bound=ConfigSet)


Expand All @@ -29,6 +29,7 @@ def __init__(
pos_args: Sequence[str] | None,
work_dir: Path,
) -> None:

self._pos_args = None if pos_args is None else tuple(pos_args)
self._work_dir = work_dir
self._root = root
Expand All @@ -42,9 +43,6 @@ def __init__(
self._key_to_conf_set: dict[tuple[str, str], ConfigSet] = OrderedDict()
self._core_set: CoreConfigSet | None = None

def register_config_set(self, name: str, env_config_set: EnvConfigSet) -> None: # noqa: U100
raise NotImplementedError # this should be overwritten by the state object before called

def pos_args(self, to_path: Path | None) -> tuple[str, ...] | None:
"""
:param to_path: if not None rewrite relative posargs paths from cwd to to_path
Expand Down Expand Up @@ -116,9 +114,6 @@ def core(self) -> CoreConfigSet:
core = CoreConfigSet(self, core_section, self._root, self.src_path)
core.loaders.extend(self._src.get_loaders(core_section, base=[], override_map=self._overrides, conf=core))
self._core_set = core
from tox.plugin.manager import MANAGER

MANAGER.tox_add_core_config(core, self)
return core

def get_section_config(
Expand All @@ -128,7 +123,6 @@ def get_section_config(
of_type: type[T],
for_env: str | None,
loaders: Sequence[Loader[Any]] | None = None,
initialize: Callable[[T], None] | None = None,
) -> T:
key = section.key, for_env or ""
try:
Expand All @@ -140,8 +134,6 @@ def get_section_config(
conf_set.loaders.append(loader)
if loaders is not None:
conf_set.loaders.extend(loaders)
if initialize is not None:
initialize(conf_set)
return conf_set

def get_env(
Expand All @@ -165,33 +157,12 @@ def get_env(
of_type=EnvConfigSet,
for_env=item,
loaders=loaders,
initialize=lambda e: self.register_config_set(item, e),
)
from tox.plugin.manager import MANAGER

MANAGER.tox_add_env_config(conf_set, self)
return conf_set

def env_list(self, everything: bool = False) -> Iterator[str]:
"""
:param everything: if ``True`` returns all discovered tox environment names from the configuration

:return: Return the tox environment names, by default only the default env list entries.
"""
fallback_env = "py"
use_env_list: CliEnv | None = 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, 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.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 clear_env(self, name: str) -> None:
section, _ = self._src.get_tox_env_section(name)
del self._key_to_conf_set[(section.key, name)]


___all__ = [
Expand Down
8 changes: 2 additions & 6 deletions src/tox/config/sets.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ def __init__(self, conf: Config, section: Section, root: Path, src_path: Path) -
self._root = root
self._src_path = src_path
super().__init__(conf, section=section, env_name=None)
desc = "define environments to automatically run"
self.add_config(keys=["env_list", "envlist"], of_type=EnvList, default=EnvList([]), desc=desc)

def register_config(self) -> None:
self.add_constant(keys=["config_file_path"], desc="path to the configuration file", value=self._src_path)
Expand All @@ -192,12 +194,6 @@ def work_dir_builder(conf: Config, env_name: str | None) -> Path: # noqa: U100
default=lambda conf, _: cast(Path, self["tox_root"]) / ".temp", # noqa: U100, U101
desc="temporary directory cleaned at start",
)
self.add_config(
keys=["env_list", "envlist"],
of_type=EnvList,
default=EnvList([]),
desc="define environments to automatically run",
)

def _on_duplicate_conf(self, key: str, definition: ConfigDefinition[V]) -> None: # noqa: U100
pass # core definitions may be defined multiple times as long as all their options match, first defined wins
Expand Down
4 changes: 0 additions & 4 deletions src/tox/config/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,6 @@ def __iter__(self) -> Iterator[str]:
""":return: iterator that goes through the defined env-list"""
return iter(self.envs)

def __bool__(self) -> bool:
""":return: ``True`` if there are any environments defined"""
return bool(self.envs)


__all__ = (
"Command",
Expand Down
15 changes: 8 additions & 7 deletions src/tox/plugin/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,14 @@
from tox.config.cli.parser import ToxParser
from tox.config.loader import api as loader_api
from tox.config.sets import ConfigSet, EnvConfigSet
from tox.session import state
from tox.session.cmd import depends, devenv, exec_, legacy, list_env, quickstart, show_config, version_flag
from tox.session.cmd.run import parallel, sequential
from tox.tox_env import package as package_api
from tox.tox_env.python.virtual_env import runner
from tox.tox_env.python.virtual_env.package import cmd_builder, pep517
from tox.tox_env.register import REGISTER, ToxEnvRegister

from ..config.main import Config
from ..execute import Outcome
from ..session.state import State
from ..tox_env.api import ToxEnv
from . import NAME, spec
from .inline import load_inline
Expand All @@ -30,6 +28,9 @@ def __init__(self) -> None:
self.manager: pluggy.PluginManager = pluggy.PluginManager(NAME)
self.manager.add_hookspecs(spec)

from tox.session import state
from tox.session.cmd import depends, devenv, exec_, legacy, list_env, quickstart, show_config, version_flag

internal_plugins = (
loader_api,
provision,
Expand Down Expand Up @@ -58,11 +59,11 @@ def __init__(self) -> None:
def tox_add_option(self, parser: ToxParser) -> None:
self.manager.hook.tox_add_option(parser=parser)

def tox_add_core_config(self, core_conf: ConfigSet, config: Config) -> None:
self.manager.hook.tox_add_core_config(core_conf=core_conf, config=config)
def tox_add_core_config(self, core_conf: ConfigSet, state: State) -> None:
self.manager.hook.tox_add_core_config(core_conf=core_conf, state=state)

def tox_add_env_config(self, env_conf: EnvConfigSet, config: Config) -> None:
self.manager.hook.tox_add_env_config(env_conf=env_conf, config=config)
def tox_add_env_config(self, env_conf: EnvConfigSet, state: State) -> None:
self.manager.hook.tox_add_env_config(env_conf=env_conf, state=state)

def tox_register_tox_env(self, register: ToxEnvRegister) -> None:
self.manager.hook.tox_register_tox_env(register=register)
Expand Down
10 changes: 5 additions & 5 deletions src/tox/plugin/spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@

import pluggy

from tox.config.main import Config
from tox.config.sets import ConfigSet, EnvConfigSet
from tox.tox_env.register import ToxEnvRegister

from ..config.cli.parser import ToxParser
from ..execute import Outcome
from ..session.state import State
from ..tox_env.api import ToxEnv
from . import NAME

Expand Down Expand Up @@ -44,22 +44,22 @@ def tox_add_option(parser: ToxParser) -> None: # noqa: U100


@_spec
def tox_add_core_config(core_conf: ConfigSet, config: Config) -> None: # noqa: U100
def tox_add_core_config(core_conf: ConfigSet, state: State) -> None: # noqa: U100
"""
Called when the core configuration is built for a tox environment.

:param core_conf: the core configuration object
:param config: the global tox config object
:param state: the global tox state object
"""


@_spec
def tox_add_env_config(env_conf: EnvConfigSet, config: Config) -> None: # noqa: U100
def tox_add_env_config(env_conf: EnvConfigSet, state: State) -> None: # noqa: U100
"""
Called when configuration is built for a tox environment.

:param env_conf: the core configuration object
:param config: the global tox config object
:param state: the global tox state object
"""


Expand Down
Loading