-
-
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 <[email protected]>
- Loading branch information
1 parent
f5eba31
commit 9a8a916
Showing
15 changed files
with
636 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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,7 +24,7 @@ repos: | |
hooks: | ||
- id: pyproject-fmt | ||
- repo: https://github.com/astral-sh/ruff-pre-commit | ||
rev: "v0.6.7" | ||
rev: "v0.6.8" | ||
hooks: | ||
- id: ruff-format | ||
- id: ruff | ||
|
@@ -39,12 +39,9 @@ repos: | |
hooks: | ||
- id: rst-backticks | ||
- repo: https://github.com/rbubley/mirrors-prettier | ||
rev: "v3.3.3" # Use the sha / tag you want to point at | ||
rev: "v3.3.3" | ||
hooks: | ||
- id: prettier | ||
additional_dependencies: | ||
- [email protected] | ||
- "@prettier/[email protected]" | ||
- repo: local | ||
hooks: | ||
- id: changelogs-rst | ||
|
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,153 @@ | ||
from __future__ import annotations | ||
|
||
import sys | ||
from inspect import isclass | ||
from pathlib import Path | ||
from typing import ( | ||
TYPE_CHECKING, | ||
Any, | ||
Dict, | ||
Iterator, | ||
List, | ||
Literal, | ||
Mapping, | ||
Set, | ||
TypeVar, | ||
Union, | ||
cast, | ||
) | ||
|
||
from tox.config.loader.api import Loader, Override | ||
from tox.config.types import Command, EnvList | ||
|
||
if TYPE_CHECKING: | ||
from tox.config.loader.section import Section | ||
from tox.config.main import Config | ||
|
||
if sys.version_info >= (3, 11): # pragma: no cover (py311+) | ||
from typing import TypeGuard | ||
else: # pragma: no cover (py311+) | ||
from typing_extensions import TypeGuard | ||
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] | ||
|
||
|
||
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 _ensure_type_correct(value, str) # type: ignore[return-value] # no mypy support | ||
|
||
@staticmethod | ||
def to_bool(value: TomlTypes) -> bool: | ||
return _ensure_type_correct(value, bool) | ||
|
||
@staticmethod | ||
def to_list(value: TomlTypes, of_type: type[Any]) -> Iterator[_T]: | ||
of = List[of_type] # type: ignore[valid-type] # no mypy support | ||
return iter(_ensure_type_correct(value, of)) # type: ignore[call-overload,no-any-return] | ||
|
||
@staticmethod | ||
def to_set(value: TomlTypes, of_type: type[Any]) -> Iterator[_T]: | ||
of = Set[of_type] # type: ignore[valid-type] # no mypy support | ||
return iter(_ensure_type_correct(value, of)) # type: ignore[call-overload,no-any-return] | ||
|
||
@staticmethod | ||
def to_dict(value: TomlTypes, of_type: tuple[type[Any], type[Any]]) -> Iterator[tuple[_T, _T]]: | ||
of = Dict[of_type[0], of_type[1]] # type: ignore[valid-type] # no mypy support | ||
return _ensure_type_correct(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))) | ||
|
||
|
||
_T = TypeVar("_T") | ||
|
||
|
||
def _ensure_type_correct(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: | ||
_ensure_type_correct(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 just validate is a nested list | ||
_ensure_type_correct(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: | ||
_ensure_type_correct(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: | ||
_ensure_type_correct(va, key_type) | ||
for va in val.values(): | ||
_ensure_type_correct(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: | ||
_ensure_type_correct(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__ = [ | ||
"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
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.