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
|
import abc
import enum
try:
import tomli as toml
_HAS_TOML = True
except ImportError: # pragma: no cover
try:
import tomllib as toml
_HAS_TOML = True
except ImportError:
_HAS_TOML = False
class Tool(enum.Enum):
DIFF_COVER = enum.auto()
DIFF_QUALITY = enum.auto()
class ParserError(Exception):
pass
class ConfigParser(abc.ABC):
def __init__(self, file_name, tool):
self._file_name = file_name
self._tool = tool
@abc.abstractmethod
def parse(self):
"""Returns a dict of the parsed data or None if the file cannot be handled."""
class TOMLParser(ConfigParser):
def __init__(self, file_name, tool):
super().__init__(file_name, tool)
self._section = "diff_cover" if tool == Tool.DIFF_COVER else "diff_quality"
def parse(self):
if not self._file_name.endswith(".toml"):
return None
if not _HAS_TOML:
raise ParserError("No Toml lib installed")
with open(self._file_name, "rb") as file_handle:
config = toml.load(file_handle)
config = config.get("tool", {}).get(self._section, {})
if not config:
raise ParserError(f"No 'tool.{self._section}' configuration available")
return config
_PARSERS = [TOMLParser]
def _parse_config_file(file_name, tool):
for parser_class in _PARSERS:
parser = parser_class(file_name, tool)
config = parser.parse()
if config:
return config
raise ParserError(f"No config parser could handle {file_name}")
def _normalize_patterns(patterns):
"""
Normalize exclude/include patterns to always be a list.
:param patterns: Pattern(s) from config (None, str, or list)
:returns: Normalized list or None
"""
if patterns is None:
return None
if isinstance(patterns, str):
return [patterns]
return patterns
def get_config(parser, argv, defaults, tool):
cli_config = vars(parser.parse_args(argv))
if cli_config["config_file"]:
file_config = _parse_config_file(cli_config["config_file"], tool)
else:
file_config = {}
config = defaults
for config_dict in [file_config, cli_config]:
for key, value in config_dict.items():
if value is None:
# if the value is None, it's a default one; only override if not present
config.setdefault(key, value)
else:
# else just override the existing value
config[key] = value
# Normalize exclude and include patterns to always be lists
if "exclude" in config:
config["exclude"] = _normalize_patterns(config["exclude"])
if "include" in config:
config["include"] = _normalize_patterns(config["include"])
return config
|