Passed
Push — master ( f8c337...4ae1c7 )
by Fabien
01:20
created

OpinionatedConfigParser.__init__()   A

Complexity

Conditions 3

Size

Total Lines 26
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 21
dl 0
loc 26
rs 9.376
c 0
b 0
f 0
cc 3
nop 8

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
import configparser
2
import sys
3
import os
4
5
try:
6
    from envtpl import render_string
7
except Exception:
8
    def render_string(*args, **kwargs):
9
        raise Exception("envtpl.render_string() not available")
10
11
12
MFCONFIG = os.environ.get("MFCONFIG", "GENERIC").lower()
13
14
15
def get_real_option(option):
16
    return option.split("[")[0]
17
18
19
def get_variant(option):
20
    if "[" not in option or "]" not in option:
21
        return None
22
    tmp = option.split("[")[1].split("]")[0]
23
    if len(tmp) == 0:
24
        return None
25
    return tmp
26
27
28
def get_score(variant, configuration_name):
29
    if variant == configuration_name:
30
        return sys.maxsize
31
    if variant is None:
32
        return 0.5
33
    tmp = configuration_name.split("_")
34
    if len(tmp) > 1:
35
        for i in range(len(tmp) - 1, 0, -1):
36
            tmp2 = "_".join(tmp[0:i])
37
            if variant == tmp2:
38
                return i
39
    return 0
40
41
42
class OpinionatedConfigParser(configparser.ConfigParser):
43
    def __init__(
44
        self,
45
        configuration_name=None,
46
        ignore_sections_starting_with="_",
47
        use_envtpl=False,
48
        envtpl_extra_variables={},
49
        envtpl_extra_search_paths=[],
50
        *args,
51
        **kwargs
52
    ):
53
        if configuration_name is not None:
54
            self.configuration_name = configuration_name.lower()
55
        else:
56
            self.configuration_name = MFCONFIG
57
        if "default_section" in kwargs:
58
            # we can't use configparser default_section feature
59
            # so we will emulate later in the code
60
            self.__default_section = kwargs["default_section"]
61
        else:
62
            self.__default_section = None
63
        kwargs["default_section"] = None
64
        self.use_envtpl = use_envtpl
65
        self.envtpl_extra_variables = envtpl_extra_variables
66
        self.envtpl_extra_search_paths = envtpl_extra_search_paths
67
        self.ignore_sections_starting_with = ignore_sections_starting_with
68
        configparser.ConfigParser.__init__(self, *args, **kwargs)
69
70
    def read(self, *args, **kwargs):
71
        configparser.ConfigParser.read(self, *args, **kwargs)
72
        self._resolve_variant()
73
74
    def read_dict(self, *args, **kwargs):
75
        configparser.ConfigParser.read_dict(self, *args, **kwargs)
76
        self._resolve_variant()
77
78
    def read_string(self, *args, **kwargs):
79
        configparser.ConfigParser.read_string(self, *args, **kwargs)
80
        self._resolve_variant()
81
82
    def read_file(self, *args, **kwargs):
83
        configparser.ConfigParser.read_file(self, *args, **kwargs)
84
        self._resolve_variant()
85
86
    def _resolve_variant(self):
87
        def deal_with_option(tmp, read_section, write_section, option):
88
            real_option = get_real_option(option)
89
            variant = get_variant(option)
90
            score = get_score(variant, self.configuration_name)
91
            if score == 0:
92
                return
93
            if real_option in tmp[write_section]:
94
                if score <= tmp[write_section][real_option][0]:
95
                    # not better score
96
                    return
97
            value = self.get(read_section, option)
98
            if self.use_envtpl:
99
                value = render_string(
100
                    value,
101
                    die_on_missing_variable=False,
102
                    extra_variables=self.envtpl_extra_variables,
103
                    extra_search_paths=self.envtpl_extra_search_paths,
104
                )
105
            tmp[write_section][real_option] = (score, value)
106
107
        has_default = (
108
            self.__default_section is not None
109
            and self.__default_section in self.sections()
110
        )
111
        # first pass
112
        tmp = {}
113
        for section in self.sections():
114
            tmp[section] = {}
115
            for option in self.options(section):
116
                deal_with_option(tmp, section, section, option)
117
            if has_default:
118
                for option in self.options(self.__default_section):
119
                    deal_with_option(
120
                        tmp, self.__default_section, section, option
121
                    )
122
        # clear
123
        self.clear()
124
        # second pass
125
        for section in tmp.keys():
126
            if self.ignore_sections_starting_with and section.startswith(
127
                self.ignore_sections_starting_with
128
            ):
129
                continue
130
            for real_option in tmp[section].keys():
131
                value = tmp[section][real_option][1]
132
                if not self.has_section(section):
133
                    self.add_section(section)
134
                self.set(section, real_option, value)
135