Skip to content

Commit 27733ab

Browse files
authored
Expose the configuration load mechanism to plugins (#2217)
1 parent 9d1a46a commit 27733ab

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+1124
-647
lines changed

.pre-commit-config.yaml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ repos:
1212
- id: end-of-file-fixer
1313
- id: trailing-whitespace
1414
- repo: https://github.com/asottile/pyupgrade
15-
rev: v2.25.1
15+
rev: v2.26.0
1616
hooks:
1717
- id: pyupgrade
1818
args: ["--py36-plus"]
@@ -66,8 +66,11 @@ repos:
6666
hooks:
6767
- id: flake8
6868
additional_dependencies:
69-
- flake8-bugbear==21.4.3
69+
- flake8-bugbear==21.9.1
7070
- flake8-comprehensions==3.6.1
7171
- flake8-pytest-style==1.5
7272
- flake8-spellcheck==0.24
7373
- flake8-unused-arguments==0.0.6
74+
- flake8-noqa==1.1.0
75+
- flake8-eradicate==1.1.0
76+
- pep8-naming==0.12.1

docs/changelog.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ Improved Documentation - 4.0.0a7
9797
- Start documenting the plugin interface. Added :meth:`tox_register_tox_env <tox.plugin.spec.tox_register_tox_env>`,
9898
:meth:`tox_add_option <tox.plugin.spec.tox_add_option>`,
9999
:meth:`tox_add_core_config <tox.plugin.spec.tox_add_core_config>`,
100-
:meth:`tox_configure <tox.plugin.spec.tox_configure>` - by :user:`gaborbernat`. (`#1991 <https://github.com/tox-dev/tox/issues/1991>`_)
100+
``tox_configure`` - by :user:`gaborbernat`. (`#1991 <https://github.com/tox-dev/tox/issues/1991>`_)
101101
- Explain how ``-v`` and ``-q`` flags play together to determine CLI verbosity level - by :user:`jugmac00`. (`#2005 <https://github.com/tox-dev/tox/issues/2005>`_)
102102
- Start polishing the documentation for the upcoming final release - by :user:`jugmac00`. (`#2006 <https://github.com/tox-dev/tox/issues/2006>`_)
103103
- Update documentation about changelog entries for trivial changes - by :user:`jugmac00`. (`#2007 <https://github.com/tox-dev/tox/issues/2007>`_)

docs/changelog/2191.bugfix.rst

Lines changed: 0 additions & 1 deletion
This file was deleted.

docs/changelog/2200.feature.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Expose the configuration loading mechanism to plugins to define and load their own sections. Add
2+
:meth:`tox_add_env_config <tox.plugin.spec.tox_add_env_config>` plugin hook called after the configuration environment
3+
is created for a tox environment and removed ``tox_configure``. Add the main configuration object as argument to
4+
:meth:`tox_add_core_config <tox.plugin.spec.tox_add_core_config>`. Move the environment list method from the state to
5+
the main configuration object to allow its use within plugins -- by :user:`gaborbernat`.

docs/conf.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,13 @@ def resolve_xref(
132132
"tox.config.loader.convert.T": "typing.TypeVar",
133133
"tox.tox_env.installer.T": "typing.TypeVar",
134134
"ToxParserT": "typing.TypeVar",
135+
"_Section": "Section",
135136
}
136137
if target in mapping:
137138
node["reftarget"] = mapping[target]
139+
if target == "_Section":
140+
target = "Section"
141+
contnode = Text(target, target)
138142

139143
return super().resolve_xref(env, fromdocname, builder, type, target, node, contnode)
140144

docs/plugins_api.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ config
2929
:members:
3030
:exclude-members: __init__, make
3131

32+
.. autoclass:: tox.config.loader.section.Section
33+
:members:
34+
35+
.. autoclass:: tox.config.loader.api.ConfigLoadArgs
36+
:members:
37+
3238
.. autoclass:: tox.config.sets.ConfigSet
3339
:members:
3440
:special-members: __iter__, __contains__

src/tox/config/cli/env_var.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ def get_env_var(key: str, of_type: Type[Any]) -> Optional[Tuple[Any, str]]:
2323
value = os.environ[environ_key]
2424
try:
2525
source = f"env var {environ_key}"
26-
result = CONVERT.to(raw=value, of_type=of_type, kwargs={})
26+
result = CONVERT.to(raw=value, of_type=of_type, factory=None)
2727
return result, source
28-
except Exception as exception: # noqa
28+
except Exception as exception:
2929
logging.warning(
3030
"env var %s=%r cannot be transformed to %r because %r",
3131
environ_key,

src/tox/config/cli/ini.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99

1010
from platformdirs import user_config_dir
1111

12+
from tox.config.loader.api import ConfigLoadArgs
1213
from tox.config.loader.ini import IniLoader
14+
from tox.config.source.ini_section import CORE
1315

1416
DEFAULT_CONFIG_FILE = Path(user_config_dir("tox")) / "config.ini"
1517

@@ -18,8 +20,6 @@ class IniConfig:
1820
TOX_CONFIG_FILE_ENV_VAR = "TOX_CONFIG_FILE"
1921
STATE = {None: "failed to parse", True: "active", False: "missing"}
2022

21-
section = "tox"
22-
2323
def __init__(self) -> None:
2424
config_file = os.environ.get(self.TOX_CONFIG_FILE_ENV_VAR, None)
2525
self.is_env_var = config_file is not None
@@ -35,8 +35,9 @@ def __init__(self) -> None:
3535
parser = ConfigParser()
3636
with self.config_file.open() as file_handler:
3737
parser.read_file(file_handler)
38-
self.has_tox_section = parser.has_section("tox")
39-
self.ini = IniLoader("tox", parser, overrides=[], core_prefix="") if self.has_tox_section else None
38+
self.has_tox_section = parser.has_section(CORE.key)
39+
if self.has_tox_section:
40+
self.ini = IniLoader(CORE, parser, overrides=[], core_section=CORE)
4041
except Exception as exception:
4142
logging.error("failed to read config file %s because %r", config_file, exception)
4243
self.has_config_file = None
@@ -51,11 +52,12 @@ def get(self, key: str, of_type: Type[Any]) -> Any:
5152
result = None
5253
else:
5354
source = "file"
54-
value = self.ini.load(key, of_type=of_type, conf=None, env_name="tox", chain=[key], kwargs={})
55+
args = ConfigLoadArgs(chain=[key], name=CORE.prefix, env_name=None)
56+
value = self.ini.load(key, of_type=of_type, conf=None, factory=None, args=args)
5557
result = value, source
5658
except KeyError: # just not found
5759
result = None
58-
except Exception as exception: # noqa
60+
except Exception as exception:
5961
logging.warning("%s key %s as type %r failed with %r", self.config_file, key, of_type, exception)
6062
result = None
6163
self._cache[cache_key] = result

src/tox/config/cli/parse.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def _get_base(args: Sequence[str]) -> Tuple[int, ToxHandler, Source]:
3535
parsed, _ = tox_parser.parse_known_args(args)
3636
guess_verbosity = parsed.verbosity
3737
handler = setup_report(guess_verbosity, parsed.is_colored)
38-
from tox.plugin.manager import MANAGER # noqa # load the plugin system right after we set up report
38+
from tox.plugin.manager import MANAGER # load the plugin system right after we set up report
3939

4040
source = discover_source(parsed.config_file, parsed.root_dir)
4141

@@ -55,7 +55,7 @@ def _get_all(args: Sequence[str]) -> Tuple[Parsed, Handlers]:
5555
def _get_parser() -> ToxParser:
5656
tox_parser = ToxParser.core() # load the core options
5757
# plus options setup by plugins
58-
from tox.plugin.manager import MANAGER # noqa
58+
from tox.plugin.manager import MANAGER
5959

6060
MANAGER.tox_add_option(tox_parser)
6161
tox_parser.fix_defaults()

src/tox/config/cli/parser.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ def fix_default(self, action: Action) -> None:
4848
if outcome is not None:
4949
action.default, default_value = outcome
5050
action.default_source = default_value # type: ignore[attr-defined]
51-
if isinstance(action, argparse._SubParsersAction): # noqa
52-
for values in action.choices.values(): # noqa
51+
if isinstance(action, argparse._SubParsersAction):
52+
for values in action.choices.values():
5353
if not isinstance(values, ToxParser): # pragma: no cover
5454
raise RuntimeError("detected sub-parser added without using our own add command")
5555
values.fix_defaults()
@@ -58,16 +58,16 @@ def fix_default(self, action: Action) -> None:
5858
def get_type(action: Action) -> Type[Any]:
5959
of_type: Optional[Type[Any]] = getattr(action, "of_type", None)
6060
if of_type is None:
61-
if isinstance(action, argparse._AppendAction): # noqa
61+
if isinstance(action, argparse._AppendAction):
6262
of_type = List[action.type] # type: ignore[name-defined]
63-
elif isinstance(action, argparse._StoreAction) and action.choices: # noqa
63+
elif isinstance(action, argparse._StoreAction) and action.choices:
6464
loc = locals()
6565
loc["Literal"] = Literal
6666
as_literal = f"Literal[{', '.join(repr(i) for i in action.choices)}]"
6767
of_type = eval(as_literal, globals(), loc)
6868
elif action.default is not None:
6969
of_type = type(action.default)
70-
elif isinstance(action, argparse._StoreConstAction) and action.const is not None: # noqa
70+
elif isinstance(action, argparse._StoreConstAction) and action.const is not None:
7171
of_type = type(action.const)
7272
else:
7373
raise TypeError(action)
@@ -84,7 +84,7 @@ def __init__(self, prog: str) -> None:
8484

8585
def _get_help_string(self, action: Action) -> Optional[str]:
8686

87-
text: str = super()._get_help_string(action) or "" # noqa
87+
text: str = super()._get_help_string(action) or ""
8888
if hasattr(action, "default_source"):
8989
default = " (default: %(default)s)"
9090
if text.endswith(default): # pragma: no branch

0 commit comments

Comments
 (0)