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