File: test_options_config.py

package info (click to toggle)
python-flake8 7.1.1-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,212 kB
  • sloc: python: 6,592; sh: 21; makefile: 19
file content (259 lines) | stat: -rw-r--r-- 8,223 bytes parent folder | download
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
from __future__ import annotations

import configparser
import os.path
from unittest import mock

import pytest

from flake8 import exceptions
from flake8.main.options import register_default_options
from flake8.options import config
from flake8.options.manager import OptionManager


def test_config_not_found_returns_none(tmp_path):
    assert config._find_config_file(str(tmp_path)) is None


def test_config_file_without_section_is_not_considered(tmp_path):
    tmp_path.joinpath("setup.cfg").touch()

    assert config._find_config_file(str(tmp_path)) is None


def test_config_file_with_parse_error_is_not_considered(tmp_path, caplog):
    # the syntax error here is deliberately to trigger a partial parse
    # https://github.com/python/cpython/issues/95546
    tmp_path.joinpath("setup.cfg").write_text("[flake8]\nx = 1\n...")

    assert config._find_config_file(str(tmp_path)) is None

    assert len(caplog.record_tuples) == 1
    ((mod, level, msg),) = caplog.record_tuples
    assert (mod, level) == ("flake8.options.config", 30)
    assert msg.startswith("ignoring unparseable config ")


def test_config_file_with_encoding_error_is_not_considered(tmp_path, caplog):
    tmp_path.joinpath("setup.cfg").write_bytes(b"\xa0\xef\xfe\x12")

    assert config._find_config_file(str(tmp_path)) is None

    assert len(caplog.record_tuples) == 1
    ((mod, level, msg),) = caplog.record_tuples
    assert (mod, level) == ("flake8.options.config", 30)
    assert msg.startswith("ignoring unparseable config ")


@pytest.mark.parametrize("cfg_name", ("setup.cfg", "tox.ini", ".flake8"))
def test_find_config_file_exists_at_path(tmp_path, cfg_name):
    expected = tmp_path.joinpath(cfg_name)
    expected.write_text("[flake8]")

    assert config._find_config_file(str(tmp_path)) == str(expected)


@pytest.mark.parametrize("section", ("flake8", "flake8:local-plugins"))
def test_find_config_either_section(tmp_path, section):
    expected = tmp_path.joinpath("setup.cfg")
    expected.write_text(f"[{section}]")

    assert config._find_config_file(str(tmp_path)) == str(expected)


def test_find_config_searches_upwards(tmp_path):
    subdir = tmp_path.joinpath("d")
    subdir.mkdir()

    expected = tmp_path.joinpath("setup.cfg")
    expected.write_text("[flake8]")

    assert config._find_config_file(str(subdir)) == str(expected)


def test_find_config_ignores_homedir(tmp_path):
    subdir = tmp_path.joinpath("d")
    subdir.mkdir()

    tmp_path.joinpath(".flake8").write_text("[flake8]")

    with mock.patch.object(os.path, "expanduser", return_value=str(tmp_path)):
        assert config._find_config_file(str(subdir)) is None


def test_find_config_ignores_unknown_homedir(tmp_path):
    subdir = tmp_path.joinpath("d")

    with mock.patch.object(os.path, "expanduser", return_value=str(subdir)):
        assert config._find_config_file(str(tmp_path)) is None


def test_load_config_config_specified_skips_discovery(tmpdir):
    tmpdir.join("setup.cfg").write("[flake8]\nindent-size=2\n")
    custom_cfg = tmpdir.join("custom.cfg")
    custom_cfg.write("[flake8]\nindent-size=8\n")

    with tmpdir.as_cwd():
        cfg, cfg_dir = config.load_config(str(custom_cfg), [], isolated=False)

    assert cfg.get("flake8", "indent-size") == "8"
    assert cfg_dir == str(tmpdir)


def test_load_config_no_config_file_does_discovery(tmpdir):
    tmpdir.join("setup.cfg").write("[flake8]\nindent-size=2\n")

    with tmpdir.as_cwd():
        cfg, cfg_dir = config.load_config(None, [], isolated=False)

    assert cfg.get("flake8", "indent-size") == "2"
    assert cfg_dir == str(tmpdir)


def test_load_config_no_config_found_sets_cfg_dir_to_pwd(tmpdir):
    with tmpdir.as_cwd():
        cfg, cfg_dir = config.load_config(None, [], isolated=False)

    assert cfg.sections() == []
    assert cfg_dir == str(tmpdir)


def test_load_config_isolated_ignores_configuration(tmpdir):
    tmpdir.join("setup.cfg").write("[flake8]\nindent-size=2\n")

    with tmpdir.as_cwd():
        cfg, cfg_dir = config.load_config(None, [], isolated=True)

    assert cfg.sections() == []
    assert cfg_dir == str(tmpdir)


def test_load_config_append_config(tmpdir):
    tmpdir.join("setup.cfg").write("[flake8]\nindent-size=2\n")
    other = tmpdir.join("other.cfg")
    other.write("[flake8]\nindent-size=8\n")

    with tmpdir.as_cwd():
        cfg, cfg_dir = config.load_config(None, [str(other)], isolated=False)

    assert cfg.get("flake8", "indent-size") == "8"
    assert cfg_dir == str(tmpdir)


NON_ASCII_CONFIG = "# ☃\n[flake8]\nindent-size=8\n"


def test_load_auto_config_utf8(tmpdir):
    tmpdir.join("setup.cfg").write_text(NON_ASCII_CONFIG, encoding="UTF-8")
    with tmpdir.as_cwd():
        cfg, cfg_dir = config.load_config(None, [], isolated=False)
    assert cfg["flake8"]["indent-size"] == "8"


def test_load_explicit_config_utf8(tmpdir):
    tmpdir.join("t.cfg").write_text(NON_ASCII_CONFIG, encoding="UTF-8")
    with tmpdir.as_cwd():
        cfg, cfg_dir = config.load_config("t.cfg", [], isolated=False)
    assert cfg["flake8"]["indent-size"] == "8"


def test_load_extra_config_utf8(tmpdir):
    tmpdir.join("setup.cfg").write("[flake8]\nindent-size=2\n")
    tmpdir.join("t.cfg").write_text(NON_ASCII_CONFIG, encoding="UTF-8")
    with tmpdir.as_cwd():
        cfg, cfg_dir = config.load_config(None, ["t.cfg"], isolated=False)
    assert cfg["flake8"]["indent-size"] == "8"


@pytest.fixture
def opt_manager():
    ret = OptionManager(
        version="123", plugin_versions="", parents=[], formatter_names=[]
    )
    register_default_options(ret)
    return ret


def test_parse_config_no_values(tmp_path, opt_manager):
    cfg = configparser.RawConfigParser()
    ret = config.parse_config(opt_manager, cfg, tmp_path)
    assert ret == {}


def test_parse_config_typed_values(tmp_path, opt_manager):
    cfg = configparser.RawConfigParser()
    cfg.add_section("flake8")
    cfg.set("flake8", "indent_size", "2")
    cfg.set("flake8", "hang_closing", "true")
    # test normalizing dashed-options
    cfg.set("flake8", "extend-exclude", "d/1,d/2")

    ret = config.parse_config(opt_manager, cfg, str(tmp_path))
    assert ret == {
        "indent_size": 2,
        "hang_closing": True,
        "extend_exclude": [
            str(tmp_path.joinpath("d/1")),
            str(tmp_path.joinpath("d/2")),
        ],
    }


def test_parse_config_ignores_unknowns(tmp_path, opt_manager, caplog):
    cfg = configparser.RawConfigParser()
    cfg.add_section("flake8")
    cfg.set("flake8", "wat", "wat")

    ret = config.parse_config(opt_manager, cfg, str(tmp_path))
    assert ret == {}

    assert caplog.record_tuples == [
        (
            "flake8.options.config",
            10,
            'Option "wat" is not registered. Ignoring.',
        )
    ]


def test_load_config_missing_file_raises_exception(capsys):
    with pytest.raises(exceptions.ExecutionError):
        config.load_config("foo.cfg", [])


def test_load_config_missing_append_config_raise_exception():
    with pytest.raises(exceptions.ExecutionError):
        config.load_config(None, ["dont_exist_config.cfg"], isolated=False)


def test_invalid_ignore_codes_raise_error(tmpdir, opt_manager):
    tmpdir.join("setup.cfg").write("[flake8]\nignore = E203, //comment")
    with tmpdir.as_cwd():
        cfg, _ = config.load_config("setup.cfg", [], isolated=False)

    with pytest.raises(ValueError) as excinfo:
        config.parse_config(opt_manager, cfg, tmpdir)

    expected = (
        "Error code '//comment' supplied to 'ignore' option "
        "does not match '^[A-Z]{1,3}[0-9]{0,3}$'"
    )
    (msg,) = excinfo.value.args
    assert msg == expected


def test_invalid_extend_ignore_codes_raise_error(tmpdir, opt_manager):
    tmpdir.join("setup.cfg").write("[flake8]\nextend-ignore = E203, //comment")
    with tmpdir.as_cwd():
        cfg, _ = config.load_config("setup.cfg", [], isolated=False)

    with pytest.raises(ValueError) as excinfo:
        config.parse_config(opt_manager, cfg, tmpdir)

    expected = (
        "Error code '//comment' supplied to 'extend-ignore' option "
        "does not match '^[A-Z]{1,3}[0-9]{0,3}$'"
    )
    (msg,) = excinfo.value.args
    assert msg == expected