Completed
Pull Request — master (#1181)
by Lasse
01:41
created

coalib.settings.Section.__setitem__()   A

Complexity

Conditions 2

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 2
dl 0
loc 13
rs 9.4286
1
from collections import OrderedDict
2
import copy
3
import os
4
5
from coalib.misc.Decorators import generate_repr, enforce_signature
6
from coalib.settings.Setting import Setting, path_list
7
from coalib.misc.DictUtilities import update_ordered_dict_key
8
from coalib.misc.Constants import Constants
9
10
11
def append_to_sections(sections,
12
                       key,
13
                       value,
14
                       origin,
15
                       section_name=None,
16
                       from_cli=False):
17
    """
18
    Appends the given data as a Setting to a Section with the given name. If
19
    the Section does not exist before it will be created empty.
20
21
    :param sections:     The sections dictionary to add to.
22
    :param key:          The key of the setting to add.
23
    :param value:        The value of the setting to add.
24
    :param origin:       The origin value of the setting to add.
25
    :param section_name: The name of the section to add to.
26
    :param from_cli:     Whether or not this data comes from the CLI.
27
    """
28
    if key == '' or value is None:
29
        return
30
31
    if section_name == "" or section_name is None:
32
        section_name = "default"
33
34
    if not section_name.lower() in sections:
35
        sections[section_name.lower()] = Section(section_name)
36
37
    sections[section_name.lower()].append(
38
        Setting(key, str(value), origin, from_cli=from_cli))
39
40
41
@generate_repr()
42
class Section:
43
    """
44
    This class holds a set of settings.
45
    """
46
47
    @staticmethod
48
    def __prepare_key(key):
49
        return str(key).lower().strip()
50
51
    def __init__(self,
52
                 name,
53
                 defaults=None):
54
        if defaults is not None and not isinstance(defaults, Section):
55
            raise TypeError("defaults has to be a Section object or None.")
56
        if defaults is self:
57
            raise ValueError("defaults may not be self for non-recursivity.")
58
59
        self.name = str(name)
60
        self.defaults = defaults
61
        self.contents = OrderedDict()
62
63
    def bear_dirs(self):
64
        bear_dirs = path_list(self.get("bear_dirs", ""))
65
        bear_dirs.append(os.path.join(Constants.coalib_bears_root, "**"))
66
67
        return bear_dirs
68
69
    def is_enabled(self, targets):
70
        """
71
        Checks if this section is enabled or, if targets is not empty, if it is
72
        included in the targets list.
73
74
        :param targets: List of target section names, all lower case.
75
        :return:        True or False
76
        """
77
        if len(targets) == 0:
78
            return bool(self.get("enabled", "true"))
79
80
        return self.name.lower() in targets
81
82
    def append(self, setting, custom_key=None):
83
        if not isinstance(setting, Setting):
84
            raise TypeError
85
        if custom_key is None:
86
            key = self.__prepare_key(setting.key)
87
        else:
88
            key = self.__prepare_key(custom_key)
89
90
        # Setting asserts key != "" for us
91
        self.contents[key] = setting
92
93
    def add_or_create_setting(self,
94
                              setting,
95
                              custom_key=None,
96
                              allow_appending=True):
97
        """
98
        Adds the value of the setting to an existing setting if there is
99
        already a setting  with the key. Otherwise creates a new setting.
100
        """
101
        if custom_key is None:
102
            key = setting.key
103
        else:
104
            key = custom_key
105
106
        if self.__contains__(key, ignore_defaults=True) and allow_appending:
107
            val = self[key]
108
            val.value = str(val.value) + "\n" + setting.value
109
        else:
110
            self.append(setting, custom_key=key)
111
112
    @enforce_signature
113
    def __setitem__(self, key: str, value: (str, Setting)):
114
        """
115
        TODO
116
117
        :param key:
118
        :param value:
119
        :return:
120
        """
121
        if isinstance(value, Setting):
122
            self.append(value, custom_key=key)
123
        else:  # It must be a string since signature is enforced
124
            self.append(Setting(key, value))
125
126
    def __iter__(self, ignore_defaults=False):
127
        joined = self.contents.copy()
128
        if self.defaults is not None and not ignore_defaults:
129
            # Since we only return the iterator of joined (which doesnt contain
130
            # values) it's ok to override values here
131
            joined.update(self.defaults.contents)
132
133
        return iter(joined)
134
135
    def __contains__(self, item, ignore_defaults=False):
136
        try:
137
            self.__getitem__(item, ignore_defaults)
138
139
            return True
140
        except IndexError:
141
            return False
142
143
    def __getitem__(self, item, ignore_defaults=False):
144
        key = self.__prepare_key(item)
145
        if key == "":
146
            raise IndexError("Empty keys are invalid.")
147
148
        res = self.contents.get(key, None)
149
        if res is not None:
150
            return res
151
152
        if self.defaults is None or ignore_defaults:
153
            raise IndexError("Required index is unavailable.")
154
155
        return self.defaults[key]
156
157
    def __str__(self):
158
        value_list = ", ".join(key + " : " + repr(str(self.contents[key]))
159
                               for key in self.contents)
160
        return self.name + " {" + value_list + "}"
161
162
    def get(self, key, default="", ignore_defaults=False):
163
        """
164
        Retrieves the item without raising an exception. If the item is not
165
        available an appropriate Setting will be generated from your provided
166
        default value.
167
168
        :param key:             The key of the setting to return.
169
        :param default:         The default value
170
        :param ignore_defaults: Whether or not to ignore the default section.
171
        :return:                The setting.
172
        """
173
        try:
174
            return self.__getitem__(key, ignore_defaults)
175
        except IndexError:
176
            return Setting(key, str(default))
177
178
    def copy(self):
179
        """
180
        :return: a deep copy of this object
181
        """
182
        result = copy.copy(self)
183
        result.contents = copy.deepcopy(self.contents)
184
        if self.defaults is not None:
185
            result.defaults = self.defaults.copy()
186
187
        return result
188
189
    def update(self, other_section, ignore_defaults=False):
190
        """
191
        Incorporates all keys and values from the other section into this one.
192
        Values from the other section override the ones from this one.
193
194
        Default values from the other section override the default values from
195
        this only.
196
197
        :param other_section:   Another Section
198
        :param ignore_defaults: If set to true, do not take default values from
199
                                other
200
        :return:                self
201
        """
202
        if not isinstance(other_section, Section):
203
            raise TypeError("other_section has to be a Section")
204
205
        self.contents.update(other_section.contents)
206
207
        if not ignore_defaults and other_section.defaults is not None:
208
            if self.defaults is None:
209
                self.defaults = other_section.defaults.copy()
210
            else:
211
                self.defaults.update(other_section.defaults)
212
213
        return self
214
215
    def update_setting(self,
216
                       key,
217
                       new_key=None,
218
                       new_value=None):
219
        """
220
        Updates a setting with new values.
221
        :param key:       The old key string.
222
        :param new_key:   The new key string.
223
        :param new_value: The new value for the setting
224
        """
225
        if new_key is not None:
226
            self.contents[key].key = new_key
227
            self.contents = update_ordered_dict_key(self.contents,
228
                                                    key,
229
                                                    new_key)
230
        if new_value is not None:
231
            if new_key is not None:
232
                self.contents[new_key].value = new_value
233
            else:
234
                self.contents[key].value = new_value
235
236
    def delete_setting(self, key):
237
        """
238
        Delete a setting
239
        :param key: The key of the setting to be deleted
240
        """
241
        del self.contents[key]
242