summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBernát Gábor <bgabor8@bloomberg.net>2021-09-10 16:23:50 +0100
committerGitHub <noreply@github.com>2021-09-10 16:23:50 +0100
commit957a280af356575b00ac6bee34fb02919e95766e (patch)
tree69a9028665391f3c1c14d9135bb207eb095e5a33
parent6a4174e0aeef61511a1bde5f9c00c731d27c56fa (diff)
downloadtox-git-957a280af356575b00ac6bee34fb02919e95766e.tar.gz
Make ConfigSet ABC and add contains to Loader (#2209)
The ConfigSet should be always specialized via subclassing. The contains is a quality of life imporvement for plugins. Also bumped the tools while at it. Signed-off-by: Bernát Gábor <gaborjbernat@gmail.com>
-rw-r--r--.pre-commit-config.yaml10
-rw-r--r--docs/changelog/2209.bugfix.rst2
-rw-r--r--src/tox/config/loader/api.py5
-rw-r--r--src/tox/config/sets.py10
-rw-r--r--tests/config/loader/test_memory_loader.py6
-rw-r--r--tests/config/test_sets.py11
6 files changed, 37 insertions, 7 deletions
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 72dc1bfd..d6dd3e68 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -12,7 +12,7 @@ repos:
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/asottile/pyupgrade
- rev: v2.23.3
+ rev: v2.25.0
hooks:
- id: pyupgrade
args: ["--py36-plus"]
@@ -24,7 +24,7 @@ repos:
hooks:
- id: isort
- repo: https://github.com/psf/black
- rev: 21.7b0
+ rev: 21.8b0
hooks:
- id: black
args:
@@ -44,11 +44,11 @@ repos:
- id: tox-ini-fmt
args: [ "-p", "fix" ]
- repo: https://github.com/asottile/blacken-docs
- rev: v1.10.0
+ rev: v1.11.0
hooks:
- id: blacken-docs
additional_dependencies:
- - black==21.7b0
+ - black==21.8b0
- repo: https://github.com/pre-commit/pygrep-hooks
rev: v1.9.0
hooks:
@@ -67,7 +67,7 @@ repos:
- id: flake8
additional_dependencies:
- flake8-bugbear==21.4.3
- - flake8-comprehensions==3.5
+ - flake8-comprehensions==3.6.1
- flake8-pytest-style==1.5
- flake8-spellcheck==0.24
- flake8-unused-arguments==0.0.6
diff --git a/docs/changelog/2209.bugfix.rst b/docs/changelog/2209.bugfix.rst
new file mode 100644
index 00000000..ec4e97c8
--- /dev/null
+++ b/docs/changelog/2209.bugfix.rst
@@ -0,0 +1,2 @@
+Do not allow constructing ``ConfigSet`` directly and implement ``__contains__`` for ``Loader`` -- by
+:user:`gaborbernat`.
diff --git a/src/tox/config/loader/api.py b/src/tox/config/loader/api.py
index f436a1ff..1f664eb5 100644
--- a/src/tox/config/loader/api.py
+++ b/src/tox/config/loader/api.py
@@ -77,6 +77,9 @@ class Loader(Convert[T]):
def __repr__(self) -> str:
return f"{type(self).__name__}"
+ def __contains__(self, item: str) -> bool:
+ return item in self.found_keys()
+
def load(
self,
key: str,
@@ -91,8 +94,10 @@ class Loader(Convert[T]):
:param key: the key under it lives
:param of_type: the type to convert to
+ :param kwargs: keyword arguments to forward
:param conf: the configuration object of this tox session (needed to manifest the value)
:param env_name: env name
+ :param chain: a chain of lookups
:return: the converted type
"""
if key in self.overrides:
diff --git a/src/tox/config/sets.py b/src/tox/config/sets.py
index dc8c3eea..c11f7d82 100644
--- a/src/tox/config/sets.py
+++ b/src/tox/config/sets.py
@@ -1,3 +1,4 @@
+from abc import ABC, abstractmethod
from pathlib import Path
from typing import (
TYPE_CHECKING,
@@ -27,7 +28,7 @@ if TYPE_CHECKING:
V = TypeVar("V")
-class ConfigSet:
+class ConfigSet(ABC):
"""A set of configuration that belong together (such as a tox environment settings, core tox settings)"""
def __init__(self, conf: "Config"):
@@ -118,8 +119,9 @@ class ConfigSet:
return config_definition.__call__(self._conf, self.loaders, self.name, chain)
@property
+ @abstractmethod
def name(self) -> Optional[str]:
- return None
+ raise NotImplementedError
def __repr__(self) -> str:
return f"{self.__class__.__name__}(loaders={self.loaders!r})"
@@ -197,6 +199,10 @@ class CoreConfigSet(ConfigSet):
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
+ @property
+ def name(self) -> Optional[str]:
+ return None
+
class EnvConfigSet(ConfigSet):
"""Configuration set for a tox environment"""
diff --git a/tests/config/loader/test_memory_loader.py b/tests/config/loader/test_memory_loader.py
index 814148cc..6b35e300 100644
--- a/tests/config/loader/test_memory_loader.py
+++ b/tests/config/loader/test_memory_loader.py
@@ -45,3 +45,9 @@ def test_memory_loader(value: Any, of_type: Type[Any]) -> None:
def test_memory_found_keys() -> None:
loader = MemoryLoader(a=1, c=2)
assert loader.found_keys() == {"a", "c"}
+
+
+def test_memory_loader_contains() -> None:
+ loader = MemoryLoader(a=1)
+ assert "a" in loader
+ assert "b" not in loader
diff --git a/tests/config/test_sets.py b/tests/config/test_sets.py
index 9c03c71d..1f61486b 100644
--- a/tests/config/test_sets.py
+++ b/tests/config/test_sets.py
@@ -3,6 +3,7 @@ from pathlib import Path
from typing import Callable, Dict, Optional, Set, TypeVar
import pytest
+from pytest_mock import MockerFixture
from tests.conftest import ToxIniCreator
from tox.config.cli.parser import Parsed
@@ -134,6 +135,7 @@ def test_config_dynamic_not_equal(conf_builder: ConfBuilder) -> None:
def test_define_custom_set(tox_project: ToxProjectCreator) -> None:
class MagicConfigSet(ConfigSet):
+
SECTION = "magic"
def __init__(self, conf: Config):
@@ -141,6 +143,10 @@ def test_define_custom_set(tox_project: ToxProjectCreator) -> None:
self.add_config("a", of_type=int, default=0, desc="number")
self.add_config("b", of_type=str, default="", desc="string")
+ @property
+ def name(self) -> Optional[str]:
+ return self.SECTION
+
project = tox_project({"tox.ini": "[testenv]\npackage=skip\n[magic]\na = 1\nb = ok"})
result = project.run()
@@ -150,3 +156,8 @@ def test_define_custom_set(tox_project: ToxProjectCreator) -> None:
assert repr(conf) == "MagicConfigSet(loaders=[IniLoader(section=<Section: magic>, overrides={})])"
assert isinstance(result.state.conf.options, Parsed)
+
+
+def test_do_not_allow_create_config_set(mocker: MockerFixture) -> None:
+ with pytest.raises(TypeError, match="Can't instantiate"):
+ ConfigSet(mocker.create_autospec(Config)) # type: ignore # the type checker also warns that ABC