Completed
Pull Request — master (#1250)
by Lasse
01:52
created

coalib.settings.Section.__setitem__()   A

Complexity

Conditions 2

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 2
dl 0
loc 19
rs 9.4285
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 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
        Creates a Setting object from the given value if needed and assigns the
116
        setting to the key:
117
118
        >>> section = Section('section_name')
119
        >>> section['key'] = 'value'
120
        >>> section['key'].value
121
        'value'
122
123
        :param key:   Argument whose value is to be set
124
        :param value: The value of the given key
125
        :return:      Returns nothing.
126
        """
127
        if isinstance(value, Setting):
128
            self.append(value, custom_key=key)
129
        else:  # It must be a string since signature is enforced
130
            self.append(Setting(key, value))
131
132
    def __iter__(self, ignore_defaults=False):
133
        joined = self.contents.copy()
134
        if self.defaults is not None and not ignore_defaults:
135
            # Since we only return the iterator of joined (which doesnt contain
136
            # values) it's ok to override values here
137
            joined.update(self.defaults.contents)
138
139
        return iter(joined)
140
141
    def __contains__(self, item, ignore_defaults=False):
142
        try:
143
            self.__getitem__(item, ignore_defaults)
144
145
            return True
146
        except IndexError:
147
            return False
148
149
    def __getitem__(self, item, ignore_defaults=False):
150
        key = self.__prepare_key(item)
151
        if key == "":
152
            raise IndexError("Empty keys are invalid.")
153
154
        res = self.contents.get(key, None)
155
        if res is not None:
156
            return res
157
158
        if self.defaults is None or ignore_defaults:
159
            raise IndexError("Required index is unavailable.")
160
161
        return self.defaults[key]
162
163
    def __str__(self):
164
        value_list = ", ".join(key + " : " + repr(str(self.contents[key]))
165
                               for key in self.contents)
166
        return self.name + " {" + value_list + "}"
167
168
    def get(self, key, default="", ignore_defaults=False):
169
        """
170
        Retrieves the item without raising an exception. If the item is not
171
        available an appropriate Setting will be generated from your provided
172
        default value.
173
174
        :param key:             The key of the setting to return.
175
        :param default:         The default value
176
        :param ignore_defaults: Whether or not to ignore the default section.
177
        :return:                The setting.
178
        """
179
        try:
180
            return self.__getitem__(key, ignore_defaults)
181
        except IndexError:
182
            return Setting(key, str(default))
183
184
    def copy(self):
185
        """
186
        :return: a deep copy of this object
187
        """
188
        result = copy.copy(self)
189
        result.contents = copy.deepcopy(self.contents)
190
        if self.defaults is not None:
191
            result.defaults = self.defaults.copy()
192
193
        return result
194
195
    def update(self, other_section, ignore_defaults=False):
196
        """
197
        Incorporates all keys and values from the other section into this one.
198
        Values from the other section override the ones from this one.
199
200
        Default values from the other section override the default values from
201
        this only.
202
203
        :param other_section:   Another Section
204
        :param ignore_defaults: If set to true, do not take default values from
205
                                other
206
        :return:                self
207
        """
208
        if not isinstance(other_section, Section):
209
            raise TypeError("other_section has to be a Section")
210
211
        self.contents.update(other_section.contents)
212
213
        if not ignore_defaults and other_section.defaults is not None:
214
            if self.defaults is None:
215
                self.defaults = other_section.defaults.copy()
216
            else:
217
                self.defaults.update(other_section.defaults)
218
219
        return self
220
221
    def update_setting(self,
222
                       key,
223
                       new_key=None,
224
                       new_value=None):
225
        """
226
        Updates a setting with new values.
227
        :param key:       The old key string.
228
        :param new_key:   The new key string.
229
        :param new_value: The new value for the setting
230
        """
231
        if new_key is not None:
232
            self.contents[key].key = new_key
233
            self.contents = update_ordered_dict_key(self.contents,
234
                                                    key,
235
                                                    new_key)
236
        if new_value is not None:
237
            if new_key is not None:
238
                self.contents[new_key].value = new_value
239
            else:
240
                self.contents[key].value = new_value
241
242
    def delete_setting(self, key):
243
        """
244
        Delete a setting
245
        :param key: The key of the setting to be deleted
246
        """
247
        del self.contents[key]
248