flake8/tests/unit/test_options_config.py

259 lines
8 KiB
Python

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