File: config_parser.py

package info (click to toggle)
diff-cover 10.1.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,252 kB
  • sloc: python: 6,425; xml: 218; cpp: 18; sh: 12; makefile: 10
file content (107 lines) | stat: -rw-r--r-- 2,844 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
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