1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
|
from collections import OrderedDict
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
from tox.config.loader.memory import MemoryLoader
from tox.config.main import Config
from tox.config.sets import ConfigSet, EnvConfigSet
from tox.config.source.api import Section
from tox.pytest import ToxProjectCreator
ConfBuilder = Callable[[str], ConfigSet]
@pytest.fixture(name="conf_builder")
def _conf_builder(tox_ini_conf: ToxIniCreator) -> ConfBuilder: # noqa: PT005
def _make(conf_str: str) -> ConfigSet:
return tox_ini_conf(f"[tox]\nenvlist=py39\n[testenv]\n{conf_str}").get_env("py39")
return _make
def test_config_str(conf_builder: ConfBuilder) -> None:
config_set = conf_builder("deps-x = 1\n other: 2")
config_set.add_config(keys="deps-x", of_type=str, default="", desc="ok")
result = config_set["deps-x"]
assert result == "1"
def test_config_path(conf_builder: ConfBuilder) -> None:
config_set = conf_builder("path = path")
config_set.add_config(keys="path", of_type=Path, default=Path(), desc="path")
path_materialize = config_set["path"]
assert path_materialize == Path("path")
def test_config_set(conf_builder: ConfBuilder) -> None:
config_set = conf_builder("set = 1\n 2\n 3")
config_set.add_config(keys="set", of_type=Set[int], default=set(), desc="set")
set_materialize = config_set["set"]
assert set_materialize == {1, 2, 3}
def test_config_optional_none(conf_builder: ConfBuilder) -> None:
config_set = conf_builder("")
config_set.add_config(
keys="optional_none",
of_type=Optional[int], # type: ignore[arg-type]
default=None,
desc="optional_none",
)
optional_none = config_set["optional_none"]
assert optional_none is None
def test_config_dict(conf_builder: ConfBuilder) -> None:
config_set = conf_builder("dict = a=1\n b=2\n c=3")
config_set.add_config(keys="dict", of_type=Dict[str, int], default={}, desc="dict")
dict_val = config_set["dict"]
assert dict_val == OrderedDict([("a", 1), ("b", 2), ("c", 3)])
def test_config_bad_type(conf_builder: ConfBuilder) -> None:
config_set = conf_builder("crazy = something-bad")
config_set.add_config(keys="crazy", of_type=TypeVar, default=TypeVar("V"), desc="crazy")
with pytest.raises(TypeError) as context:
assert config_set["crazy"]
assert str(context.value) == f"something-bad cannot cast to {TypeVar!r}"
def test_config_bad_dict(conf_builder: ConfBuilder) -> None:
config_set = conf_builder("bad_dict = something")
config_set.add_config(keys="bad_dict", of_type=Dict[str, str], default={}, desc="bad_dict")
with pytest.raises(TypeError) as context:
assert config_set["bad_dict"]
assert str(context.value) == "dictionary lines must be of form key=value, found 'something'"
def test_config_bad_bool(conf_builder: ConfBuilder) -> None:
config_set = conf_builder("bad_bool = whatever")
config_set.add_config(keys="bad_bool", of_type=bool, default=False, desc="bad_bool")
with pytest.raises(TypeError) as context:
assert config_set["bad_bool"]
error = "value whatever cannot be transformed to bool, valid: , 0, 1, false, no, off, on, true, yes"
assert str(context.value) == error
def test_config_constant(conf_builder: ConfBuilder) -> None:
config_set = conf_builder("")
config_set.add_constant(keys="a", value=1, desc="ok")
const = config_set["a"]
assert const == 1
def test_config_lazy_constant(conf_builder: ConfBuilder) -> None:
config_set = conf_builder("")
config_set.add_constant(keys="b", value=lambda: 2, desc="ok")
lazy_const = config_set["b"]
assert lazy_const == 2
def test_config_constant_repr(conf_builder: ConfBuilder) -> None:
config_set = conf_builder("")
defined = config_set.add_constant(keys="a", value=1, desc="ok")
assert repr(defined)
def test_config_dynamic_repr(conf_builder: ConfBuilder) -> None:
config_set = conf_builder("path = path")
defined = config_set.add_config(keys="path", of_type=Path, default=Path(), desc="path")
assert repr(defined)
def test_config_redefine_constant_fail(conf_builder: ConfBuilder) -> None:
config_set = conf_builder("path = path")
config_set.add_constant(keys="path", desc="desc", value="value")
with pytest.raises(ValueError, match="config path already defined"):
config_set.add_constant(keys="path", desc="desc2", value="value")
def test_config_redefine_dynamic_fail(conf_builder: ConfBuilder) -> None:
config_set = conf_builder("path = path")
config_set.add_config(keys="path", of_type=str, default="default_1", desc="path")
with pytest.raises(ValueError, match="config path already defined"):
config_set.add_config(keys="path", of_type=str, default="default_2", desc="path")
def test_config_dynamic_not_equal(conf_builder: ConfBuilder) -> None:
config_set = conf_builder("")
path = config_set.add_config(keys="path", of_type=Path, default=Path(), desc="path")
paths = config_set.add_config(keys="paths", of_type=Path, default=Path(), desc="path")
assert path != paths
def test_define_custom_set(tox_project: ToxProjectCreator) -> None:
class MagicConfigSet(ConfigSet):
SECTION = Section(None, "magic")
def register_config(self) -> None:
self.add_config("a", of_type=int, default=0, desc="number")
self.add_config("b", of_type=str, default="", desc="string")
project = tox_project({"tox.ini": "[testenv]\npackage=skip\n[A]\na=1\n[magic]\nb = ok"})
result = project.run()
section = MagicConfigSet.SECTION
conf = result.state.conf.get_section_config(section, base=["A"], of_type=MagicConfigSet, for_env=None)
assert conf["a"] == 1
assert conf["b"] == "ok"
exp = "MagicConfigSet(loaders=[IniLoader(section=magic, overrides={}), " "IniLoader(section=A, overrides={})])"
assert repr(conf) == exp
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
def test_set_env_raises_on_non_str(mocker: MockerFixture) -> None:
env_set = EnvConfigSet(mocker.create_autospec(Config), Section("a", "b"), "b")
env_set.loaders.insert(0, MemoryLoader(set_env=1))
with pytest.raises(TypeError, match="1"):
assert env_set["set_env"]
|