-
-
Notifications
You must be signed in to change notification settings - Fork 526
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Bernát Gábor <bgabor8@bloomberg.net>
- Loading branch information
1 parent
f5eba31
commit 7cc25cf
Showing
17 changed files
with
664 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Native TOML configuration support - by :user:`gaborbernat`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
from __future__ import annotations | ||
|
||
from pathlib import Path | ||
from typing import TYPE_CHECKING, Dict, Iterator, List, Mapping, Set, TypeVar, cast | ||
|
||
from tox.config.loader.api import Loader, Override | ||
from tox.config.types import Command, EnvList | ||
|
||
from ._abc import TomlTypes | ||
from ._validate import validate | ||
|
||
if TYPE_CHECKING: | ||
from tox.config.loader.section import Section | ||
from tox.config.main import Config | ||
|
||
_T = TypeVar("_T") | ||
_V = TypeVar("_V") | ||
|
||
|
||
class TomlLoader(Loader[TomlTypes]): | ||
"""Load configuration from a pyproject.toml file.""" | ||
|
||
def __init__( | ||
self, | ||
section: Section, | ||
overrides: list[Override], | ||
content: Mapping[str, TomlTypes], | ||
unused_exclude: set[str], | ||
) -> None: | ||
self.content = content | ||
self._unused_exclude = unused_exclude | ||
super().__init__(section, overrides) | ||
|
||
def __repr__(self) -> str: | ||
return f"{self.__class__.__name__}({self.section.name}, {self.content!r})" | ||
|
||
def load_raw(self, key: str, conf: Config | None, env_name: str | None) -> TomlTypes: # noqa: ARG002 | ||
return self.content[key] | ||
|
||
def found_keys(self) -> set[str]: | ||
return set(self.content.keys()) - self._unused_exclude | ||
|
||
@staticmethod | ||
def to_str(value: TomlTypes) -> str: | ||
return validate(value, str) # type: ignore[return-value] # no mypy support | ||
|
||
@staticmethod | ||
def to_bool(value: TomlTypes) -> bool: | ||
return validate(value, bool) | ||
|
||
@staticmethod | ||
def to_list(value: TomlTypes, of_type: type[_T]) -> Iterator[_T]: | ||
of = List[of_type] # type: ignore[valid-type] # no mypy support | ||
return iter(validate(value, of)) # type: ignore[call-overload,no-any-return] | ||
|
||
@staticmethod | ||
def to_set(value: TomlTypes, of_type: type[_T]) -> Iterator[_T]: | ||
of = Set[of_type] # type: ignore[valid-type] # no mypy support | ||
return iter(validate(value, of)) # type: ignore[call-overload,no-any-return] | ||
|
||
@staticmethod | ||
def to_dict(value: TomlTypes, of_type: tuple[type[_T], type[_V]]) -> Iterator[tuple[_T, _V]]: | ||
of = Dict[of_type[0], of_type[1]] # type: ignore[valid-type] # no mypy support | ||
return validate(value, of).items() # type: ignore[attr-defined,no-any-return] | ||
|
||
@staticmethod | ||
def to_path(value: TomlTypes) -> Path: | ||
return Path(TomlLoader.to_str(value)) | ||
|
||
@staticmethod | ||
def to_command(value: TomlTypes) -> Command: | ||
return Command(args=cast(List[str], value)) # validated during load in _ensure_type_correct | ||
|
||
@staticmethod | ||
def to_env_list(value: TomlTypes) -> EnvList: | ||
return EnvList(envs=list(TomlLoader.to_list(value, str))) | ||
|
||
|
||
__all__ = [ | ||
"TomlLoader", | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
from __future__ import annotations | ||
|
||
from typing import TYPE_CHECKING, Dict, List, Union | ||
|
||
if TYPE_CHECKING: | ||
import sys | ||
|
||
if sys.version_info >= (3, 10): # pragma: no cover (py310+) | ||
from typing import TypeAlias | ||
else: # pragma: no cover (py310+) | ||
from typing_extensions import TypeAlias | ||
|
||
TomlTypes: TypeAlias = Union[Dict[str, "TomlTypes"], List["TomlTypes"], str, int, float, bool, None] | ||
|
||
__all__ = [ | ||
"TomlTypes", | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
from __future__ import annotations | ||
|
||
from inspect import isclass | ||
from typing import ( | ||
TYPE_CHECKING, | ||
Any, | ||
Dict, | ||
List, | ||
Literal, | ||
Set, | ||
TypeVar, | ||
Union, | ||
cast, | ||
) | ||
|
||
from tox.config.types import Command | ||
|
||
if TYPE_CHECKING: | ||
import sys | ||
|
||
from ._abc import TomlTypes | ||
|
||
if sys.version_info >= (3, 11): # pragma: no cover (py311+) | ||
from typing import TypeGuard | ||
else: # pragma: no cover (py311+) | ||
from typing_extensions import TypeGuard | ||
|
||
T = TypeVar("T") | ||
|
||
|
||
def validate(val: TomlTypes, of_type: type[T]) -> TypeGuard[T]: # noqa: C901, PLR0912 | ||
casting_to = getattr(of_type, "__origin__", of_type.__class__) | ||
msg = "" | ||
if casting_to in {list, List}: | ||
entry_type = of_type.__args__[0] # type: ignore[attr-defined] | ||
if isinstance(val, list): | ||
for va in val: | ||
validate(va, entry_type) | ||
else: | ||
msg = f"{val!r} is not list" | ||
elif isclass(of_type) and issubclass(of_type, Command): | ||
# first we cast it to list then create commands, so for now validate it as a nested list | ||
validate(val, List[str]) | ||
elif casting_to in {set, Set}: | ||
entry_type = of_type.__args__[0] # type: ignore[attr-defined] | ||
if isinstance(val, set): | ||
for va in val: | ||
validate(va, entry_type) | ||
else: | ||
msg = f"{val!r} is not set" | ||
elif casting_to in {dict, Dict}: | ||
key_type, value_type = of_type.__args__[0], of_type.__args__[1] # type: ignore[attr-defined] | ||
if isinstance(val, dict): | ||
for va in val: | ||
validate(va, key_type) | ||
for va in val.values(): | ||
validate(va, value_type) | ||
else: | ||
msg = f"{val!r} is not dictionary" | ||
elif casting_to == Union: # handle Optional values | ||
args: list[type[Any]] = of_type.__args__ # type: ignore[attr-defined] | ||
for arg in args: | ||
try: | ||
validate(val, arg) | ||
break | ||
except TypeError: | ||
pass | ||
else: | ||
msg = f"{val!r} is not union of {', '.join(a.__name__ for a in args)}" | ||
elif casting_to in {Literal, type(Literal)}: | ||
choice = of_type.__args__ # type: ignore[attr-defined] | ||
if val not in choice: | ||
msg = f"{val!r} is not one of literal {','.join(repr(i) for i in choice)}" | ||
elif not isinstance(val, of_type): | ||
msg = f"{val!r} is not of type {of_type.__name__!r}" | ||
if msg: | ||
raise TypeError(msg) | ||
return cast(T, val) # type: ignore[return-value] # logic too complicated for mypy | ||
|
||
|
||
__all__ = [ | ||
"validate", | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.