Passed
Push — master ( c1256c...895128 )
by Fabien
01:22
created

OpinionatedConfigParser._resolve_variant()   F

Complexity

Conditions 14

Size

Total Lines 49
Code Lines 40

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 40
dl 0
loc 49
rs 3.6
c 0
b 0
f 0
cc 14
nop 1

How to fix   Complexity   

Complexity

Complex classes like opinionated_configparser.OpinionatedConfigParser._resolve_variant() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

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 "delimiters" not in kwargs:
58
            kwargs["delimiters"] = ("=",)
59
        if "comment_prefixes" not in kwargs:
60
            kwargs["comment_prefixes"] = ("#",)
61
        if "interpolation" not in kwargs:
62
            kwargs["interpolation"] = configparser.ExtendedInterpolation()
63
        if "default_section" in kwargs:
64
            # we can't use configparser default_section feature
65
            # so we will emulate later in the code
66
            self.__default_section = kwargs["default_section"]
67
        else:
68
            self.__default_section = None
69
        kwargs["default_section"] = None
70
        self.use_envtpl = use_envtpl
71
        self.envtpl_extra_variables = envtpl_extra_variables
72
        self.envtpl_extra_search_paths = envtpl_extra_search_paths
73
        self.ignore_sections_starting_with = ignore_sections_starting_with
74
        configparser.ConfigParser.__init__(self, *args, **kwargs)
75
76
    def read(self, *args, **kwargs):
77
        configparser.ConfigParser.read(self, *args, **kwargs)
78
        self._resolve_variant()
79
80
    def read_dict(self, *args, **kwargs):
81
        configparser.ConfigParser.read_dict(self, *args, **kwargs)
82
        self._resolve_variant()
83
84
    def read_string(self, *args, **kwargs):
85
        configparser.ConfigParser.read_string(self, *args, **kwargs)
86
        self._resolve_variant()
87
88
    def read_file(self, *args, **kwargs):
89
        configparser.ConfigParser.read_file(self, *args, **kwargs)
90
        self._resolve_variant()
91
92
    def _resolve_variant(self):
93
        def deal_with_option(tmp, read_section, write_section, option):
94
            real_option = get_real_option(option)
95
            variant = get_variant(option)
96
            score = get_score(variant, self.configuration_name)
97
            if score == 0:
98
                return
99
            if real_option in tmp[write_section]:
100
                if score <= tmp[write_section][real_option][0]:
101
                    # not better score
102
                    return
103
            value = self.get(read_section, option)
104
            if self.use_envtpl:
105
                value = render_string(
106
                    value,
107
                    die_on_missing_variable=False,
108
                    extra_variables=self.envtpl_extra_variables,
109
                    extra_search_paths=self.envtpl_extra_search_paths,
110
                )
111
            tmp[write_section][real_option] = (score, value)
112
113
        has_default = (
114
            self.__default_section is not None
115
            and self.__default_section in self.sections()
116
        )
117
        # first pass
118
        tmp = {}
119
        for section in self.sections():
120
            tmp[section] = {}
121
            for option in self.options(section):
122
                deal_with_option(tmp, section, section, option)
123
            if has_default:
124
                for option in self.options(self.__default_section):
125
                    deal_with_option(
126
                        tmp, self.__default_section, section, option
127
                    )
128
        # clear
129
        self.clear()
130
        # second pass
131
        for section in tmp.keys():
132
            if self.ignore_sections_starting_with and section.startswith(
133
                self.ignore_sections_starting_with
134
            ):
135
                continue
136
            for real_option in tmp[section].keys():
137
                value = tmp[section][real_option][1]
138
                if not self.has_section(section):
139
                    self.add_section(section)
140
                self.set(section, real_option, value)
141