1
|
|
|
# Copyright 2014 Diamond Light Source Ltd. |
2
|
|
|
# |
3
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
4
|
|
|
# you may not use this file except in compliance with the License. |
5
|
|
|
# You may obtain a copy of the License at |
6
|
|
|
# |
7
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0 |
8
|
|
|
# |
9
|
|
|
# Unless required by applicable law or agreed to in writing, software |
10
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS, |
11
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12
|
|
|
# See the License for the specific language governing permissions and |
13
|
|
|
# limitations under the License. |
14
|
|
|
|
15
|
|
|
""" |
16
|
|
|
.. module:: content |
17
|
|
|
:platform: Unix |
18
|
|
|
:synopsis: Content class for the configurator |
19
|
|
|
|
20
|
|
|
.. moduleauthor:: Nicola Wadeson <[email protected]> |
21
|
|
|
|
22
|
|
|
""" |
23
|
|
|
import re |
24
|
|
|
import os |
25
|
|
|
import copy |
26
|
|
|
import inspect |
27
|
|
|
|
28
|
|
|
from savu.plugins import utils as pu |
29
|
|
|
from savu.data.plugin_list import PluginList |
30
|
|
|
import scripts.config_generator.parameter_utils as param_u |
31
|
|
|
|
32
|
|
|
from . import mutations |
33
|
|
|
|
34
|
|
|
|
35
|
|
|
class Content(object): |
36
|
|
|
def __init__(self, filename=None, level="basic"): |
37
|
|
|
self.disp_level = level |
38
|
|
|
self.plugin_list = PluginList() |
39
|
|
|
self.plugin_mutations = mutations.plugin_mutations |
40
|
|
|
self.param_mutations = mutations.param_mutations |
41
|
|
|
self.filename = filename |
42
|
|
|
self._finished = False |
43
|
|
|
self.failed = {} |
44
|
|
|
self.expand_dim = None |
45
|
|
|
|
46
|
|
|
def set_finished(self, check="y"): |
47
|
|
|
self._finished = True if check.lower() == "y" else False |
48
|
|
|
|
49
|
|
|
def is_finished(self): |
50
|
|
|
return self._finished |
51
|
|
|
|
52
|
|
|
def fopen(self, infile, update=False, skip=False): |
53
|
|
|
if os.path.exists(infile): |
54
|
|
|
self.plugin_list._populate_plugin_list(infile, active_pass=True) |
55
|
|
|
else: |
56
|
|
|
raise Exception("INPUT ERROR: The file does not exist.") |
57
|
|
|
self.filename = infile |
58
|
|
|
if update: |
59
|
|
|
self.plugin_mutations = self.check_mutations( |
60
|
|
|
self.plugin_mutations |
61
|
|
|
) |
62
|
|
|
self.param_mutations = self.check_mutations(self.param_mutations) |
63
|
|
|
self._apply_plugin_updates(skip) |
64
|
|
|
|
65
|
|
|
def check_mutations(self, mut_dict: dict): |
66
|
|
|
plist_version = self._version_to_float(self.plugin_list.version) |
67
|
|
|
# deleting elements while iterating invalidates the iterator |
68
|
|
|
# which raises a RuntimeError in Python 3. |
69
|
|
|
# Instead a copy of the dict is mutated and returned |
70
|
|
|
mut_dict_copy = mut_dict.copy() |
71
|
|
|
for key, subdict in mut_dict.items(): |
72
|
|
|
if "up_to_version" in subdict.keys(): |
73
|
|
|
up_to_version = self._version_to_float( |
74
|
|
|
subdict["up_to_version"] |
75
|
|
|
) |
76
|
|
|
if plist_version >= up_to_version: |
77
|
|
|
del mut_dict_copy[key] |
78
|
|
|
return mut_dict_copy |
79
|
|
|
|
80
|
|
|
def _version_to_float(self, version): |
81
|
|
|
if version is None: |
82
|
|
|
return 0 |
83
|
|
|
if isinstance(version, bytes): |
84
|
|
|
version = version.decode("ascii") |
85
|
|
|
split_vals = version.split(".") |
86
|
|
|
return float(".".join([split_vals[0], "".join(split_vals[1:])])) |
87
|
|
|
|
88
|
|
|
def display(self, formatter, **kwargs): |
89
|
|
|
# Set current level |
90
|
|
|
if "current_level" not in list(kwargs.keys()): |
91
|
|
|
kwargs["current_level"] = self.disp_level |
92
|
|
|
if ( |
93
|
|
|
"disp_level" in list(kwargs.keys()) |
94
|
|
|
and kwargs["disp_level"] is True |
95
|
|
|
): |
96
|
|
|
# Display level |
97
|
|
|
print(f"Level is set at '{kwargs['current_level']}'") |
98
|
|
|
else: |
99
|
|
|
# Display parameter |
100
|
|
|
kwargs["expand_dim"] = self.expand_dim |
101
|
|
|
print("\n" + formatter._get_string(**kwargs) + "\n") |
102
|
|
|
|
103
|
|
|
def check_file(self, filename): |
104
|
|
|
if not filename: |
105
|
|
|
raise Exception( |
106
|
|
|
"INPUT ERROR: Please specify the output filepath." |
107
|
|
|
) |
108
|
|
|
path = os.path.dirname(filename) |
109
|
|
|
path = path if path else "." |
110
|
|
|
if not os.path.exists(path): |
111
|
|
|
file_error = "INPUT_ERROR: Incorrect filepath." |
112
|
|
|
raise Exception(file_error) |
113
|
|
|
|
114
|
|
|
def save(self, filename, check="y", template=False): |
115
|
|
|
self.check_plugin_list_exists() |
116
|
|
|
# Check if a loader and saver are present. |
117
|
|
|
self.plugin_list._check_loaders() |
118
|
|
|
if check.lower() == "y": |
119
|
|
|
print(f"Saving file {filename}") |
120
|
|
|
if template: |
121
|
|
|
self.plugin_list.add_template(create=True) |
122
|
|
|
self.plugin_list._save_plugin_list(filename) |
123
|
|
|
else: |
124
|
|
|
print("The process list has NOT been saved.") |
125
|
|
|
|
126
|
|
|
def clear(self, check="y"): |
127
|
|
|
if check.lower() == "y": |
128
|
|
|
self.expand_dim = None |
129
|
|
|
self.plugin_list.plugin_list = [] |
130
|
|
|
|
131
|
|
|
def check_plugin_list_exists(self): |
132
|
|
|
""" Check if plugin list is populated. """ |
133
|
|
|
pos_list = self.get_positions() |
134
|
|
|
if not pos_list: |
135
|
|
|
print("There are no items to access in your list.") |
136
|
|
|
raise Exception("Please add an item to the process list.") |
137
|
|
|
|
138
|
|
|
def add(self, name, str_pos): |
139
|
|
|
self.check_for_plugin_failure(name) |
140
|
|
|
plugin = pu.plugins[name]() |
141
|
|
|
plugin.get_plugin_tools()._populate_default_parameters() |
142
|
|
|
pos, str_pos = self.convert_pos(str_pos) |
143
|
|
|
self.insert(plugin, pos, str_pos) |
144
|
|
|
|
145
|
|
|
def refresh(self, str_pos, defaults=False, change=False): |
146
|
|
|
pos = self.find_position(str_pos) |
147
|
|
|
plugin_entry = self.plugin_list.plugin_list[pos] |
148
|
|
|
name = change if change else plugin_entry["name"] |
149
|
|
|
active = plugin_entry["active"] |
150
|
|
|
plugin = pu.plugins[name]() |
151
|
|
|
plugin.get_plugin_tools()._populate_default_parameters() |
152
|
|
|
keep = self.get(pos)["data"] if not defaults else None |
153
|
|
|
self.insert(plugin, pos, str_pos, replace=True) |
154
|
|
|
self.plugin_list.plugin_list[pos]["active"] = active |
155
|
|
|
if keep: |
156
|
|
|
self._update_parameters(plugin, name, keep, str_pos) |
157
|
|
|
|
158
|
|
|
def duplicate(self, dupl_pos, new): |
159
|
|
|
""" Duplicate the plugin at position dupl_pos |
160
|
|
|
and insert it at the new position |
161
|
|
|
|
162
|
|
|
:param dupl_pos: Position of the plugin to duplicate |
163
|
|
|
:param new: New plugin position |
164
|
|
|
""" |
165
|
|
|
pos = self.find_position(dupl_pos) |
166
|
|
|
new_pos, new_pos_str = self.convert_pos(new) |
167
|
|
|
plugin_entry = copy.deepcopy(self.plugin_list.plugin_list[pos]) |
168
|
|
|
plugin_entry["pos"] = new_pos_str |
169
|
|
|
self.plugin_list.plugin_list.insert(new_pos, plugin_entry) |
170
|
|
|
|
171
|
|
|
def check_for_plugin_failure(self, name): |
172
|
|
|
"""Check if the plugin failed to load |
173
|
|
|
|
174
|
|
|
:param name: plugin name |
175
|
|
|
""" |
176
|
|
|
if (name not in list(pu.plugins.keys()) |
177
|
|
|
or self.plugin_in_failed_dict(name)): |
178
|
|
|
if self.plugin_in_failed_dict(name): |
179
|
|
|
msg = f"IMPORT ERROR: {name} is unavailable due to" \ |
180
|
|
|
f" the following error:\n\t{self.failed[name]}" |
181
|
|
|
raise Exception(msg) |
182
|
|
|
raise Exception("INPUT ERROR: Unknown plugin %s" % name) |
183
|
|
|
|
184
|
|
|
def plugin_in_failed_dict(self, name): |
185
|
|
|
"""Check if plugin in failed dictionary |
186
|
|
|
|
187
|
|
|
:param name: plugin name |
188
|
|
|
:return: True if plugin name in the list of failed plugins |
189
|
|
|
""" |
190
|
|
|
failed_plugin_list = list(self.failed.keys()) if self.failed else [] |
191
|
|
|
return True if name in failed_plugin_list else False |
192
|
|
|
|
193
|
|
|
def check_preview_param(self, plugin_pos): |
194
|
|
|
""" Check that the plugin position number is valid and it contains |
195
|
|
|
a preview parameter |
196
|
|
|
|
197
|
|
|
:param plugin_pos: |
198
|
|
|
:return: |
199
|
|
|
""" |
200
|
|
|
pos = self.find_position(plugin_pos) |
201
|
|
|
plugin_entry = self.plugin_list.plugin_list[pos] |
202
|
|
|
parameters = plugin_entry["data"] |
203
|
|
|
if "preview" not in parameters: |
204
|
|
|
raise Exception("You can only use this command with " |
205
|
|
|
"plugins containing the preview parameter") |
206
|
|
|
|
207
|
|
|
def set_preview_display(self, expand_off, expand_dim, dim_view, |
208
|
|
|
plugin_pos): |
209
|
|
|
"""Set the dimensions_to_display value to "off" to prevent the |
210
|
|
|
preview parameter being shown in it's expanded form. |
211
|
|
|
|
212
|
|
|
If dimensions_to_display = "all", then all dimension slices are shown. |
213
|
|
|
If a number is provided to dim_view, that dimension is shown. |
214
|
|
|
|
215
|
|
|
:param expand_off: True if expand display should be turned off |
216
|
|
|
:param expand_dim: The dimension number to display, or "all" |
217
|
|
|
:param dim_view: True if only a certain dimension should be shown |
218
|
|
|
:param plugin_pos: Plugin position |
219
|
|
|
""" |
220
|
|
|
if expand_off is True: |
221
|
|
|
self.expand_dim = None |
222
|
|
|
print(f"Expand diplay has been turned off") |
223
|
|
|
else: |
224
|
|
|
self.check_preview_param(plugin_pos) |
225
|
|
|
dims_to_display = expand_dim if dim_view else "all" |
226
|
|
|
self.expand_dim = dims_to_display |
227
|
|
|
|
228
|
|
|
def _update_parameters(self, plugin, name, keep, str_pos): |
229
|
|
|
union_params = set(keep).intersection(set(plugin.parameters)) |
230
|
|
|
# Names of the parameter names present in both lists |
231
|
|
|
for param in union_params: |
232
|
|
|
valid_mod = self.modify(str_pos, param, keep[param], ref=True) |
233
|
|
|
if not valid_mod: |
234
|
|
|
self._print_default_message(plugin, param) |
235
|
|
|
# add any parameter mutations here |
236
|
|
|
classes = [c.__name__ for c in inspect.getmro(plugin.__class__)] |
237
|
|
|
m_dict = self.param_mutations |
238
|
|
|
keys = [k for k in list(m_dict.keys()) if k in classes] |
239
|
|
|
|
240
|
|
|
changes = False |
241
|
|
|
for k in keys: |
242
|
|
|
for entry in m_dict[k]["params"]: |
243
|
|
|
if entry["old"] in list(keep.keys()): |
244
|
|
|
changes = True |
245
|
|
|
val = keep[entry["old"]] |
246
|
|
|
if "eval" in list(entry.keys()): |
247
|
|
|
val = eval(entry["eval"]) |
248
|
|
|
self.modify(str_pos, entry["new"], val, ref=True) |
249
|
|
|
if changes: |
250
|
|
|
mutations.param_change_str(keep, plugin.parameters, name, keys) |
251
|
|
|
|
252
|
|
|
def _print_default_message(self, plugin, param): |
253
|
|
|
"""Print message to alert user that value has not been changed/updated |
254
|
|
|
|
255
|
|
|
:param plugin: plugin object |
256
|
|
|
:param param: parameter name |
257
|
|
|
""" |
258
|
|
|
pdefs = plugin.get_plugin_tools().get_param_definitions() |
259
|
|
|
default = pdefs[param]['default'] |
260
|
|
|
print(f"This has been replaced by the default {param}: " |
261
|
|
|
f"{default}.") |
262
|
|
|
|
263
|
|
|
def _apply_plugin_updates(self, skip=False): |
264
|
|
|
# Update old process lists that start from 0 |
265
|
|
|
the_list = self.plugin_list.plugin_list |
266
|
|
|
if "pos" in list(the_list[0].keys()) and the_list[0]["pos"] == "0": |
267
|
|
|
self.increment_positions() |
268
|
|
|
|
269
|
|
|
missing = [] |
270
|
|
|
pos = len(the_list) - 1 |
271
|
|
|
notices = mutations.plugin_notices |
272
|
|
|
|
273
|
|
|
for plugin in the_list[::-1]: |
274
|
|
|
# update old process lists to include 'active' flag |
275
|
|
|
if "active" not in list(plugin.keys()): |
276
|
|
|
plugin["active"] = True |
277
|
|
|
|
278
|
|
|
while True: |
279
|
|
|
name = the_list[pos]["name"] |
280
|
|
|
if name in notices.keys(): |
281
|
|
|
print(notices[name]["desc"]) |
282
|
|
|
|
283
|
|
|
# if a plugin is missing from all available plugins |
284
|
|
|
# then look for mutations in the plugin name |
285
|
|
|
search = True if name not in pu.plugins.keys() else False |
286
|
|
|
found = self._mutate_plugins(name, pos, search=search) |
287
|
|
|
if search and not found: |
288
|
|
|
str_pos = self.plugin_list.plugin_list[pos]["pos"] |
289
|
|
|
missing.append([name, str_pos]) |
290
|
|
|
self.remove(pos) |
291
|
|
|
pos -= 1 |
292
|
|
|
if name == the_list[pos]["name"]: |
293
|
|
|
break |
294
|
|
|
pos -= 1 |
295
|
|
|
|
296
|
|
|
for name, pos in missing[::-1]: |
297
|
|
|
if skip: |
298
|
|
|
print(f"Skipping plugin {pos}: {name}") |
299
|
|
|
else: |
300
|
|
|
message = ( |
301
|
|
|
f"\nPLUGIN ERROR: The plugin {name} is " |
302
|
|
|
f"unavailable in this version of Savu. \nThe plugin is " |
303
|
|
|
f"missing from the position {pos} in the process list. " |
304
|
|
|
f"\n Type open -s <process_list> to skip the broken " |
305
|
|
|
f"plugin." |
306
|
|
|
) |
307
|
|
|
raise Exception(f"Incompatible process list. {message}") |
308
|
|
|
|
309
|
|
|
def _mutate_plugins(self, name, pos, search=False): |
310
|
|
|
""" Perform plugin mutations. """ |
311
|
|
|
# check for case changes in plugin name |
312
|
|
|
if search: |
313
|
|
|
for key in pu.plugins.keys(): |
314
|
|
|
if name.lower() == key.lower(): |
315
|
|
|
str_pos = self.plugin_list.plugin_list[pos]["pos"] |
316
|
|
|
self.refresh(str_pos, change=key) |
317
|
|
|
return True |
318
|
|
|
|
319
|
|
|
# check mutations dict |
320
|
|
|
m_dict = self.plugin_mutations |
321
|
|
|
if name in m_dict.keys(): |
322
|
|
|
mutate = m_dict[name] |
323
|
|
|
if "replace" in mutate.keys(): |
324
|
|
|
if mutate["replace"] in list(pu.plugins.keys()): |
325
|
|
|
str_pos = self.plugin_list.plugin_list[pos]["pos"] |
326
|
|
|
self.refresh(str_pos, change=mutate["replace"]) |
327
|
|
|
print(mutate["desc"]) |
328
|
|
|
return True |
329
|
|
|
raise Exception( |
330
|
|
|
f"Replacement plugin {mutate['replace']} " |
331
|
|
|
f"unavailable for {name}" |
332
|
|
|
) |
333
|
|
|
elif "remove" in mutate.keys(): |
334
|
|
|
self.remove(pos) |
335
|
|
|
print(mutate["desc"]) |
336
|
|
|
else: |
337
|
|
|
raise Exception("Unknown mutation type.") |
338
|
|
|
return False |
339
|
|
|
|
340
|
|
|
def move(self, old, new): |
341
|
|
|
old_pos = self.find_position(old) |
342
|
|
|
entry = self.plugin_list.plugin_list[old_pos] |
343
|
|
|
self.remove(old_pos) |
344
|
|
|
new_pos, new = self.convert_pos(new) |
345
|
|
|
name = entry["name"] |
346
|
|
|
self.insert(pu.plugins[name](), new_pos, new) |
347
|
|
|
self.plugin_list.plugin_list[new_pos] = entry |
348
|
|
|
self.plugin_list.plugin_list[new_pos]["pos"] = new |
349
|
|
|
|
350
|
|
|
def replace(self, old, new_plugin): |
351
|
|
|
self.check_for_plugin_failure(new_plugin) |
352
|
|
|
old_pos = self.find_position(old) |
353
|
|
|
self.remove(old_pos) |
354
|
|
|
pos, str_pos = self.convert_pos(old) |
355
|
|
|
plugin = pu.plugins[new_plugin]() |
356
|
|
|
plugin.get_plugin_tools()._populate_default_parameters() |
357
|
|
|
self.insert(plugin, pos, str_pos) |
358
|
|
|
#self.plugin_list.plugin_list[pos]["pos"] = str_pos |
359
|
|
|
|
360
|
|
|
def modify(self, pos_str, param_name, value, default=False, ref=False, |
361
|
|
|
dim=False): |
362
|
|
|
"""Modify the plugin at pos_str and the parameter at param_name |
363
|
|
|
The new value will be set if it is valid. |
364
|
|
|
|
365
|
|
|
:param pos_str: The plugin position |
366
|
|
|
:param param_name: The parameter position/name |
367
|
|
|
:param value: The new parameter value |
368
|
|
|
:param default: True if value should be reverted to the default |
369
|
|
|
:param ref: boolean Refresh the plugin |
370
|
|
|
:param dim: The dimension to be modified |
371
|
|
|
|
372
|
|
|
returns: A boolean True if the value is a valid input for the |
373
|
|
|
selected parameter |
374
|
|
|
""" |
375
|
|
|
pos = self.find_position(pos_str) |
376
|
|
|
plugin_entry = self.plugin_list.plugin_list[pos] |
377
|
|
|
tools = plugin_entry["tools"] |
378
|
|
|
parameters = plugin_entry["data"] |
379
|
|
|
params = plugin_entry["param"] |
380
|
|
|
param_name, value = self.setup_modify(params, param_name, value, ref) |
381
|
|
|
default_str = ["-d", "--default"] |
382
|
|
|
if default or value in default_str: |
383
|
|
|
value = tools.get_default_value(param_name) |
384
|
|
|
self._change_value(param_name, value, tools, parameters) |
385
|
|
|
valid_modification = True |
386
|
|
|
else: |
387
|
|
|
value = self._catch_parameter_tuning_syntax(value, param_name) |
388
|
|
|
valid_modification = self.modify_main( |
389
|
|
|
param_name, value, tools, parameters, dim, pos_str |
390
|
|
|
) |
391
|
|
|
return valid_modification |
392
|
|
|
|
393
|
|
|
def _catch_parameter_tuning_syntax(self, value, param_name): |
394
|
|
|
"""Check if the new parameter value seems like it is written |
395
|
|
|
in parameter tuning syntax with colons. If it is, then append |
396
|
|
|
a semi colon onto the end. |
397
|
|
|
|
398
|
|
|
:param value: new parameter value |
399
|
|
|
:param param_name: |
400
|
|
|
:return: modified value with semi colon appended |
401
|
|
|
""" |
402
|
|
|
exempt_parameters = ["preview", "indices"] |
403
|
|
|
if self._is_multi_parameter_syntax(value) \ |
404
|
|
|
and param_name not in exempt_parameters: |
405
|
|
|
# Assume parameter tuning syntax is being used |
406
|
|
|
value = f"{value};" |
407
|
|
|
print("Parameter tuning syntax applied") |
408
|
|
|
return value |
409
|
|
|
|
410
|
|
|
def _is_multi_parameter_syntax(self, value): |
411
|
|
|
"""If the value contains two colons, is not a dictionary, |
412
|
|
|
and doesnt already contain a semi colon, then assume that |
413
|
|
|
it is using parameter tuning syntax |
414
|
|
|
|
415
|
|
|
:param value: new parameter value |
416
|
|
|
:return boolean True if parameter tuning syntax is being used |
417
|
|
|
""" |
418
|
|
|
isdict = re.findall(r"[\{\}]+", str(value)) |
419
|
|
|
return (isinstance(value, str) |
420
|
|
|
and value.count(":") >= 2 |
421
|
|
|
and not isdict |
422
|
|
|
and ";" not in value) |
423
|
|
|
|
424
|
|
|
def setup_modify(self, params, param_name, value, ref): |
425
|
|
|
"""Get the parameter keys in the correct order and find |
426
|
|
|
the parameter name string |
427
|
|
|
|
428
|
|
|
:param params: The plugin parameters |
429
|
|
|
:param param_name: The parameter position/name |
430
|
|
|
:param value: The new parameter value |
431
|
|
|
:param ref: boolean Refresh the plugin |
432
|
|
|
|
433
|
|
|
return: param_name str to avoid discrepancy, value |
434
|
|
|
""" |
435
|
|
|
if ref: |
436
|
|
|
# For a refresh, refresh all keys, including those with |
437
|
|
|
# dependencies (which have the display off) |
438
|
|
|
keys = params.keys() |
439
|
|
|
else: |
440
|
|
|
# Select the correct group and order of parameters according to that |
441
|
|
|
# on display to the user. This ensures correct parameter is modified. |
442
|
|
|
keys = pu.set_order_by_visibility(params) |
443
|
|
|
value = self.value(value) |
444
|
|
|
param_name = pu.param_to_str(param_name, keys) |
445
|
|
|
return param_name, value |
446
|
|
|
|
447
|
|
|
def modify_main(self, param_name, value, tools, parameters, dim, pos_str): |
448
|
|
|
"""Check the parameter is within the current parameter list. |
449
|
|
|
Check the new parameter value is valid, modify the parameter |
450
|
|
|
value, update defaults, check if dependent parameters should |
451
|
|
|
be made visible or hidden. |
452
|
|
|
|
453
|
|
|
:param param_name: The parameter position/name |
454
|
|
|
:param value: The new parameter value |
455
|
|
|
:param tools: The plugin tools |
456
|
|
|
:param parameters: The plugin parameters |
457
|
|
|
:param dim: The dimensions |
458
|
|
|
:param pos_str: The plugin position number |
459
|
|
|
|
460
|
|
|
returns: A boolean True if the value is a valid input for the |
461
|
|
|
selected parameter |
462
|
|
|
""" |
463
|
|
|
parameter_valid = False |
464
|
|
|
current_parameter_details = tools.param.get(param_name) |
465
|
|
|
current_plugin_name = tools.plugin_class.name |
466
|
|
|
|
467
|
|
|
# If dimensions are provided then alter preview param |
468
|
|
|
if self.preview_dimension_to_modify(dim, param_name): |
469
|
|
|
# Filter the dimension, dim1 or dim1.start |
470
|
|
|
dim, _slice = self._separate_dimension_and_slice(dim) |
471
|
|
|
value = self.modify_preview( |
472
|
|
|
parameters, param_name, value, dim, _slice |
473
|
|
|
) |
474
|
|
|
|
475
|
|
|
# If found, then the parameter is within the current parameter list |
476
|
|
|
# displayed to the user |
477
|
|
|
if current_parameter_details: |
478
|
|
|
value_check = pu._dumps(value) |
479
|
|
|
parameter_valid, error_str = param_u.is_valid( |
480
|
|
|
param_name, value_check, current_parameter_details |
481
|
|
|
) |
482
|
|
|
if parameter_valid: |
483
|
|
|
self._change_value(param_name, value, tools, parameters) |
484
|
|
|
else: |
485
|
|
|
print(f"ERROR: The value {value} for " |
486
|
|
|
f"{pos_str}.{param_name} is not correct.") |
487
|
|
|
print(error_str) |
488
|
|
|
else: |
489
|
|
|
print("Not in parameter keys.") |
490
|
|
|
return parameter_valid |
491
|
|
|
|
492
|
|
|
def _change_value(self, param_name, value, tools, parameters): |
493
|
|
|
""" Change the parameter "param_name" value inside the parameters list |
494
|
|
|
Update feedback messages for various dependant parameters |
495
|
|
|
|
496
|
|
|
:param param_name: The parameter position/name |
497
|
|
|
:param value: The new parameter value |
498
|
|
|
:param tools: The plugin tools |
499
|
|
|
:param parameters: The plugin parameters |
500
|
|
|
""" |
501
|
|
|
# Save the value |
502
|
|
|
parameters[param_name] = value |
503
|
|
|
tools.warn_dependents(param_name, value) |
504
|
|
|
# Update the list of parameters to hide those dependent on others |
505
|
|
|
tools.check_dependencies(parameters) |
506
|
|
|
|
507
|
|
|
def check_required_args(self, value, required): |
508
|
|
|
"""Check required argument 'value' is present |
509
|
|
|
|
510
|
|
|
:param value: Argument value |
511
|
|
|
:param required: bool, True if the argument is required |
512
|
|
|
""" |
513
|
|
|
if required and (not value): |
514
|
|
|
raise Exception("Please enter a value") |
515
|
|
|
|
516
|
|
|
if (not required) and value: |
517
|
|
|
raise Exception(f"Unrecognised argument: {value}") |
518
|
|
|
|
519
|
|
|
def preview_dimension_to_modify(self, dim, param_name): |
520
|
|
|
"""Check that the dimension string is only present when the parameter |
521
|
|
|
to modify is the preview parameter |
522
|
|
|
|
523
|
|
|
:param dim: Dimension string |
524
|
|
|
:param param_name: The parameter name (of the parameter to be modified) |
525
|
|
|
:return: True if dimension string is provided and the parameter to modify |
526
|
|
|
the preview parameter |
527
|
|
|
""" |
528
|
|
|
if dim: |
529
|
|
|
if param_name == "preview": |
530
|
|
|
return True |
531
|
|
|
else: |
532
|
|
|
raise Exception( |
533
|
|
|
"Please only use the dimension syntax when " |
534
|
|
|
"modifying the preview parameter." |
535
|
|
|
) |
536
|
|
|
return False |
537
|
|
|
|
538
|
|
|
def modify_dimensions(self, pos_str, dim, check="y"): |
539
|
|
|
"""Modify the plugin preview value. Remove or add dimensions |
540
|
|
|
to the preview parameter until the provided dimension number |
541
|
|
|
is reached. |
542
|
|
|
|
543
|
|
|
:param pos_str: The plugin position |
544
|
|
|
:param dim: The new number of dimensions |
545
|
|
|
:return True if preview is modified |
546
|
|
|
""" |
547
|
|
|
pos = self.find_position(pos_str) |
548
|
|
|
plugin_entry = self.plugin_list.plugin_list[pos] |
549
|
|
|
parameters = plugin_entry["data"] |
550
|
|
|
self.check_param_exists(parameters, "preview") |
551
|
|
|
current_prev_list = pu._dumps(parameters["preview"]) |
552
|
|
|
if not isinstance(current_prev_list, list): |
553
|
|
|
# Temporarily cover dict instance for preview |
554
|
|
|
print("This command is only possible for preview " |
555
|
|
|
"values of the type list") |
556
|
|
|
return False |
557
|
|
|
pu.check_valid_dimension(dim, []) |
558
|
|
|
if check.lower() == "y": |
559
|
|
|
while len(current_prev_list) > dim: |
560
|
|
|
current_prev_list.pop() |
561
|
|
|
while len(current_prev_list) < dim: |
562
|
|
|
current_prev_list.append(":") |
563
|
|
|
parameters["preview"] = current_prev_list |
564
|
|
|
return True |
565
|
|
|
return False |
566
|
|
|
|
567
|
|
|
def check_param_exists(self, parameters, pname): |
568
|
|
|
"""Check the parameter is present in the current parameter list |
569
|
|
|
|
570
|
|
|
:param parameters: Dictionary of parameters |
571
|
|
|
:param pname: Parameter name |
572
|
|
|
:return: |
573
|
|
|
""" |
574
|
|
|
if not parameters.get(pname): |
575
|
|
|
raise Exception( |
576
|
|
|
f"The {pname} parameter is not available" f" for this plugin." |
577
|
|
|
) |
578
|
|
|
|
579
|
|
|
|
580
|
|
|
def plugin_to_num(self, plugin_val, pl_index): |
581
|
|
|
"""Check the plugin is within the process list and |
582
|
|
|
return the number in the list. |
583
|
|
|
|
584
|
|
|
:param plugin_val: The dictionary of parameters |
585
|
|
|
:param pl_index: The plugin index (for use when there are multiple |
586
|
|
|
plugins of same name) |
587
|
|
|
:return: A plugin index number of a certain plugin in the process list |
588
|
|
|
""" |
589
|
|
|
if plugin_val.isdigit(): |
590
|
|
|
return plugin_val |
591
|
|
|
pl_names = [pl["name"] for pl in self.plugin_list.plugin_list] |
592
|
|
|
if plugin_val in pl_names: |
593
|
|
|
# Find the plugin number |
594
|
|
|
pl_indexes = [i for i, p in enumerate(pl_names) if p == plugin_val] |
595
|
|
|
# Subtract one to access correct list index. Add one to access |
596
|
|
|
# correct plugin position |
597
|
|
|
return str(pl_indexes[pl_index-1] +1) |
598
|
|
|
else: |
599
|
|
|
raise Exception("This plugin is not present in this process list.") |
600
|
|
|
|
601
|
|
|
|
602
|
|
|
def value(self, value): |
603
|
|
|
if not value.count(";"): |
604
|
|
|
try: |
605
|
|
|
value = eval(value) |
606
|
|
|
except (NameError, SyntaxError): |
607
|
|
|
try: |
608
|
|
|
value = eval(f"'{value}'") |
609
|
|
|
# if there is one quotation mark there will be an error |
610
|
|
|
except EOFError: |
611
|
|
|
raise EOFError( |
612
|
|
|
"There is an end of line error. Please check your" |
613
|
|
|
' input for the character "\'".' |
614
|
|
|
) |
615
|
|
|
except SyntaxError: |
616
|
|
|
raise SyntaxError( |
617
|
|
|
"There is a syntax error. Please check your input." |
618
|
|
|
) |
619
|
|
|
except: |
620
|
|
|
raise Exception("Please check your input.") |
621
|
|
|
return value |
622
|
|
|
|
623
|
|
|
def convert_to_ascii(self, value): |
624
|
|
|
ascii_list = [] |
625
|
|
|
for v in value: |
626
|
|
|
ascii_list.append(v.encode("ascii", "ignore")) |
627
|
|
|
return ascii_list |
628
|
|
|
|
629
|
|
|
def on_and_off(self, str_pos, index): |
630
|
|
|
print(("switching plugin %s %s" % (str_pos, index))) |
631
|
|
|
status = True if index == "ON" else False |
632
|
|
|
pos = self.find_position(str_pos) |
633
|
|
|
self.plugin_list.plugin_list[pos]["active"] = status |
634
|
|
|
|
635
|
|
|
def convert_pos(self, str_pos): |
636
|
|
|
""" Converts the display position (input) to the equivalent numerical |
637
|
|
|
position and updates the display position if required. |
638
|
|
|
|
639
|
|
|
:param str_pos: the plugin display position (input) string. |
640
|
|
|
:returns: the equivalent numerical position of str_pos and and updated\ |
641
|
|
|
str_pos. |
642
|
|
|
:rtype: (pos, str_pos) |
643
|
|
|
""" |
644
|
|
|
pos_list = self.get_split_positions() |
645
|
|
|
num = re.findall(r"\d+", str_pos)[0] |
646
|
|
|
letter = re.findall("[a-z]", str_pos) |
647
|
|
|
entry = [num, letter[0]] if letter else [num] |
648
|
|
|
|
649
|
|
|
# full value already exists in the list |
650
|
|
|
if entry in pos_list: |
651
|
|
|
index = pos_list.index(entry) |
652
|
|
|
return self.inc_positions(index, pos_list, entry, 1) |
653
|
|
|
|
654
|
|
|
# only the number exists in the list |
655
|
|
|
num_list = [pos_list[i][0] for i in range(len(pos_list))] |
656
|
|
|
if entry[0] in num_list: |
657
|
|
|
start = num_list.index(entry[0]) |
658
|
|
|
if len(entry) == 2: |
659
|
|
|
if len(pos_list[start]) == 2: |
660
|
|
|
idx = int([i for i in range(len(num_list)) if |
661
|
|
|
(num_list[i] == entry[0])][-1]) + 1 |
662
|
|
|
entry = [entry[0], str(chr(ord(pos_list[idx - 1][1]) + 1))] |
663
|
|
|
return idx, ''.join(entry) |
664
|
|
|
if entry[1] == 'a': |
665
|
|
|
self.plugin_list.plugin_list[start]['pos'] = entry[0] + 'b' |
666
|
|
|
return start, ''.join(entry) |
667
|
|
|
else: |
668
|
|
|
self.plugin_list.plugin_list[start]['pos'] = entry[0] + 'a' |
669
|
|
|
return start + 1, entry[0] + 'b' |
670
|
|
|
return self.inc_positions(start, pos_list, entry, 1) |
671
|
|
|
|
672
|
|
|
# number not in list |
673
|
|
|
entry[0] = str(int(num_list[-1]) + 1 if num_list else 1) |
674
|
|
|
if len(entry) == 2: |
675
|
|
|
entry[1] = "a" |
676
|
|
|
return len(self.plugin_list.plugin_list), "".join(entry) |
677
|
|
|
|
678
|
|
|
def increment_positions(self): |
679
|
|
|
"""Update old process lists that start plugin numbering from 0 to |
680
|
|
|
start from 1.""" |
681
|
|
|
for plugin in self.plugin_list.plugin_list: |
682
|
|
|
str_pos = plugin["pos"] |
683
|
|
|
num = str(int(re.findall(r"\d+", str_pos)[0]) + 1) |
684
|
|
|
letter = re.findall("[a-z]", str_pos) |
685
|
|
|
plugin["pos"] = "".join([num, letter[0]] if letter else [num]) |
686
|
|
|
|
687
|
|
|
def get_positions(self): |
688
|
|
|
""" Get a list of all current plugin entry positions. """ |
689
|
|
|
elems = self.plugin_list.plugin_list |
690
|
|
|
pos_list = [] |
691
|
|
|
for e in elems: |
692
|
|
|
pos_list.append(e["pos"]) |
693
|
|
|
return pos_list |
694
|
|
|
|
695
|
|
|
def get_param_arg_str(self, pos_str, subelem): |
696
|
|
|
"""Get the name of the parameter so that the display lists the |
697
|
|
|
correct item when the parameter order has been updated |
698
|
|
|
|
699
|
|
|
:param pos_str: The plugin position |
700
|
|
|
:param subelem: The parameter |
701
|
|
|
:return: The plugin.parameter_name argument |
702
|
|
|
""" |
703
|
|
|
pos = self.find_position(pos_str) |
704
|
|
|
current_parameter_list = self.plugin_list.plugin_list[pos]["param"] |
705
|
|
|
current_parameter_list_ordered = pu.set_order_by_visibility( |
706
|
|
|
current_parameter_list |
707
|
|
|
) |
708
|
|
|
param_name = pu.param_to_str(subelem, current_parameter_list_ordered) |
709
|
|
|
param_argument = pos_str + "." + param_name |
710
|
|
|
return param_argument |
711
|
|
|
|
712
|
|
|
def get_split_positions(self): |
713
|
|
|
""" Separate numbers and letters in positions. """ |
714
|
|
|
positions = self.get_positions() |
715
|
|
|
split_pos = [] |
716
|
|
|
for i in range(len(positions)): |
717
|
|
|
num = re.findall(r"\d+", positions[i])[0] |
718
|
|
|
letter = re.findall("[a-z]", positions[i]) |
719
|
|
|
split_pos.append([num, letter[0]] if letter else [num]) |
720
|
|
|
return split_pos |
721
|
|
|
|
722
|
|
|
def find_position(self, pos): |
723
|
|
|
""" Find the numerical index of a position (a string). """ |
724
|
|
|
pos_list = self.get_positions() |
725
|
|
|
if not pos_list: |
726
|
|
|
print("There are no items to access in your list.") |
727
|
|
|
raise Exception("Please add an item to the process list.") |
728
|
|
|
else: |
729
|
|
|
if pos not in pos_list: |
730
|
|
|
raise ValueError("Incorrect plugin position.") |
731
|
|
|
return pos_list.index(pos) |
732
|
|
|
|
733
|
|
|
def inc_positions(self, start, pos_list, entry, inc): |
734
|
|
|
if len(entry) == 1: |
735
|
|
|
self.inc_numbers(start, pos_list, inc) |
736
|
|
|
else: |
737
|
|
|
idx = [ |
738
|
|
|
i |
739
|
|
|
for i in range(start, len(pos_list)) |
740
|
|
|
if pos_list[i][0] == entry[0] |
741
|
|
|
] |
742
|
|
|
self.inc_letters(idx, pos_list, inc) |
743
|
|
|
return start, "".join(entry) |
744
|
|
|
|
745
|
|
|
def inc_numbers(self, start, pos_list, inc): |
746
|
|
|
for i in range(start, len(pos_list)): |
747
|
|
|
pos_list[i][0] = str(int(pos_list[i][0]) + inc) |
748
|
|
|
self.plugin_list.plugin_list[i]["pos"] = "".join(pos_list[i]) |
749
|
|
|
|
750
|
|
|
def inc_letters(self, idx, pos_list, inc): |
751
|
|
|
for i in idx: |
752
|
|
|
pos_list[i][1] = str(chr(ord(pos_list[i][1]) + inc)) |
753
|
|
|
self.plugin_list.plugin_list[i]["pos"] = "".join(pos_list[i]) |
754
|
|
|
|
755
|
|
|
def split_plugin_string(self, start, stop, subelem_view=False): |
756
|
|
|
"""Find the start and stop number for the plugin range selected. |
757
|
|
|
|
758
|
|
|
:param start: Plugin starting index (including a subelem value |
759
|
|
|
if permitted) |
760
|
|
|
:param stop: Plugin stopping index |
761
|
|
|
:param subelem_view: False if subelem value not permitted |
762
|
|
|
:return: range_dict containing start stop (and possible subelem) |
763
|
|
|
""" |
764
|
|
|
range_dict = {} |
765
|
|
|
if start: |
766
|
|
|
if subelem_view and "." in start: |
767
|
|
|
start, stop, subelem = self._split_subelem(start) |
768
|
|
|
range_dict["subelem"] = subelem |
769
|
|
|
else: |
770
|
|
|
start, stop = self._get_start_stop(start, stop) |
771
|
|
|
range_dict["start"] = start |
772
|
|
|
range_dict["stop"] = stop |
773
|
|
|
return range_dict |
774
|
|
|
|
775
|
|
|
def _get_start_stop(self, start, stop): |
776
|
|
|
"""Find the start and stop number for the plugin range selected """ |
777
|
|
|
start = self.find_position(start) |
778
|
|
|
stop = self.find_position(stop) + 1 if stop else start + 1 |
779
|
|
|
return start, stop |
780
|
|
|
|
781
|
|
|
def _split_subelem(self, start, config_disp=True): |
782
|
|
|
"""Separate the start string containing the plugin number, |
783
|
|
|
parameter(subelement), dimension and command |
784
|
|
|
|
785
|
|
|
:param start: The plugin to start at |
786
|
|
|
:param config_disp: True if command and dimension arguments |
787
|
|
|
are not permitted |
788
|
|
|
:return: start plugin, range_dict containing a subelem |
789
|
|
|
if a parameter is specified |
790
|
|
|
""" |
791
|
|
|
start, subelem, dim, command = self.separate_plugin_subelem( |
792
|
|
|
start, config_disp |
793
|
|
|
) |
794
|
|
|
start, stop = self._get_start_stop(start, "") |
795
|
|
|
return start, stop, subelem |
796
|
|
|
|
797
|
|
|
def _check_command_valid(self, plugin_param, config_disp): |
798
|
|
|
"""Check the plugin_param string length |
799
|
|
|
|
800
|
|
|
:param plugin_param: The string containing plugin number, parameter, |
801
|
|
|
and command |
802
|
|
|
:param config_disp: bool, True if command and dimension arguments are |
803
|
|
|
not permitted |
804
|
|
|
""" |
805
|
|
|
if config_disp: |
806
|
|
|
if not 1 < len(plugin_param) < 3: |
807
|
|
|
raise ValueError( |
808
|
|
|
"Use either 'plugin_pos.param_name' or" |
809
|
|
|
" 'plugin_pos.param_no'" |
810
|
|
|
) |
811
|
|
|
else: |
812
|
|
|
# The modify command is being used |
813
|
|
|
if len(plugin_param) <= 1: |
814
|
|
|
raise ValueError( |
815
|
|
|
"Please enter the plugin parameter to modify" |
816
|
|
|
". Either 'plugin_pos.param_name' or" |
817
|
|
|
" 'plugin_pos.param_no'" |
818
|
|
|
) |
819
|
|
|
if not 1 < len(plugin_param) < 5: |
820
|
|
|
raise ValueError( |
821
|
|
|
"Enter 'plugin_pos.param_no.dimension'. " |
822
|
|
|
"Following the dimension, use start/stop/step" |
823
|
|
|
" eg. '1.1.dim1.start' " |
824
|
|
|
) |
825
|
|
|
|
826
|
|
|
def separate_plugin_subelem(self, plugin_param, config_disp): |
827
|
|
|
"""Separate the plugin number,parameter (subelement) number |
828
|
|
|
and additional command if present. |
829
|
|
|
|
830
|
|
|
:param plugin_param: A string supplied by the user input which |
831
|
|
|
contains the plugin element to edit/display. eg "1.1.dim.command" |
832
|
|
|
:param config_disp: bool, True if command and dimension arguments are |
833
|
|
|
not permitted |
834
|
|
|
|
835
|
|
|
:returns plugin: The number of the plugin element |
836
|
|
|
subelem: The number of the parameter |
837
|
|
|
dim: The dimension |
838
|
|
|
command: The supplied command, eg expand or a dimension |
839
|
|
|
string |
840
|
|
|
""" |
841
|
|
|
plugin_param = plugin_param.split(".") |
842
|
|
|
plugin = plugin_param[0] |
843
|
|
|
# change str plugin name to a number |
844
|
|
|
start = self.find_position(plugin) |
845
|
|
|
self._check_command_valid(plugin_param, config_disp) |
846
|
|
|
subelem = plugin_param[1] |
847
|
|
|
if len(plugin_param) > 2: |
848
|
|
|
dim = self.dim_str_to_int(plugin_param[2]) |
849
|
|
|
command = str(dim) |
850
|
|
|
if len(plugin_param) == 4: |
851
|
|
|
self._check_command_str(plugin_param[3]) |
852
|
|
|
command += "." + plugin_param[3] |
853
|
|
|
else: |
854
|
|
|
dim, command = "", "" |
855
|
|
|
return plugin, subelem, dim, command |
856
|
|
|
|
857
|
|
|
def _check_command_str(self, command_str): |
858
|
|
|
"""Check the additional 1.1.dim.command for slice or 'expand' |
859
|
|
|
keywords |
860
|
|
|
""" |
861
|
|
|
command_list = ["expand", "start", "stop", "step", "chunk"] |
862
|
|
|
if command_str not in command_list: |
863
|
|
|
raise ValueError( |
864
|
|
|
"Following the dimension, use start/stop/step eg. " |
865
|
|
|
"'1.1.dim1.start' " |
866
|
|
|
) |
867
|
|
|
return command_str |
868
|
|
|
|
869
|
|
|
def insert(self, plugin, pos, str_pos, replace=False): |
870
|
|
|
plugin_dict = self.create_plugin_dict(plugin) |
871
|
|
|
plugin_dict["pos"] = str_pos |
872
|
|
|
if replace: |
873
|
|
|
self.plugin_list.plugin_list[pos] = plugin_dict |
874
|
|
|
else: |
875
|
|
|
self.plugin_list.plugin_list.insert(pos, plugin_dict) |
876
|
|
|
|
877
|
|
|
def create_plugin_dict(self, plugin): |
878
|
|
|
tools = plugin.get_plugin_tools() |
879
|
|
|
plugin_dict = {} |
880
|
|
|
plugin_dict["name"] = plugin.name |
881
|
|
|
plugin_dict["id"] = plugin.__module__ |
882
|
|
|
plugin_dict["data"] = plugin.parameters |
883
|
|
|
plugin_dict["active"] = True |
884
|
|
|
plugin_dict["tools"] = tools |
885
|
|
|
plugin_dict["param"] = tools.get_param_definitions() |
886
|
|
|
plugin_dict["doc"] = tools.docstring_info |
887
|
|
|
return plugin_dict |
888
|
|
|
|
889
|
|
|
def get(self, pos): |
890
|
|
|
return self.plugin_list.plugin_list[pos] |
891
|
|
|
|
892
|
|
|
def _separate_dimension_and_slice(self, command_str): |
893
|
|
|
"""Check the start stop step command |
894
|
|
|
|
895
|
|
|
param command_str: a string '1.1' containing the dimension |
896
|
|
|
and slice number seperated by a full stop |
897
|
|
|
|
898
|
|
|
:returns dim, slice |
899
|
|
|
""" |
900
|
|
|
if isinstance(command_str, str) and "." in command_str: |
901
|
|
|
# If the slice value is included |
902
|
|
|
slice_dict = {"start": 0, "stop": 1, "step": 2, "chunk": 3} |
903
|
|
|
_slice = slice_dict[command_str.split(".")[1]] |
904
|
|
|
dim = int(command_str.split(".")[0]) |
905
|
|
|
else: |
906
|
|
|
dim = int(command_str) |
907
|
|
|
_slice = "" |
908
|
|
|
return dim, _slice |
909
|
|
|
|
910
|
|
|
def dim_str_to_int(self, dim_str): |
911
|
|
|
"""Check the additional 1.1.dim keyword |
912
|
|
|
|
913
|
|
|
:param dim: A string 'dim1' specifying the dimension |
914
|
|
|
|
915
|
|
|
:return: dim - An integer dimension value |
916
|
|
|
""" |
917
|
|
|
number = "".join(l for l in dim_str if l.isdigit()) |
918
|
|
|
letters = "".join(l for l in dim_str if l.isalpha()) |
919
|
|
|
|
920
|
|
|
if letters == "dim" and number.strip(): |
921
|
|
|
dim = int(number) |
922
|
|
|
else: |
923
|
|
|
raise ValueError( |
924
|
|
|
"Following the second decimal place, please " |
925
|
|
|
"specify a dimension 1.1.dim1 or 1.preview.dim1" |
926
|
|
|
) |
927
|
|
|
return dim |
928
|
|
|
|
929
|
|
|
def modify_preview(self, parameters, param_name, value, dim, _slice): |
930
|
|
|
""" Check the entered value is valid and edit preview""" |
931
|
|
|
slice_list = [0, 1, 2, 3] |
932
|
|
|
type_check_value = pu._dumps(value) |
933
|
|
|
current_preview_value = pu._dumps(parameters[param_name]) |
934
|
|
|
pu.check_valid_dimension(dim, current_preview_value) |
935
|
|
|
if _slice in slice_list: |
936
|
|
|
# Modify this dimension and slice only |
937
|
|
|
if param_u._preview_dimension_singular(type_check_value): |
938
|
|
|
value = self._modify_preview_dimension_slice( |
939
|
|
|
value, current_preview_value, dim, _slice |
940
|
|
|
) |
941
|
|
|
else: |
942
|
|
|
raise ValueError( |
943
|
|
|
"Invalid preview dimension slice value. Please " |
944
|
|
|
"enter a float, an integer or a string including " |
945
|
|
|
"only start, mid and end keywords." |
946
|
|
|
) |
947
|
|
|
else: |
948
|
|
|
# If the entered value is a valid dimension value |
949
|
|
|
if param_u._preview_dimension(type_check_value): |
950
|
|
|
# Modify the whole dimension |
951
|
|
|
value = self._modify_preview_dimension( |
952
|
|
|
value, current_preview_value, dim |
953
|
|
|
) |
954
|
|
|
else: |
955
|
|
|
raise ValueError( |
956
|
|
|
"Invalid preview dimension value. Please " |
957
|
|
|
"enter a float, an integer or slice notation." |
958
|
|
|
) |
959
|
|
|
return value |
960
|
|
|
|
961
|
|
|
def _modify_preview_dimension_slice(self, value, current_val, dim, _slice): |
962
|
|
|
"""Modify the preview dimension slice value at the dimension (dim) |
963
|
|
|
provided |
964
|
|
|
|
965
|
|
|
:param value: The new value |
966
|
|
|
:param current_value: The current preview parameter value |
967
|
|
|
:param dim: The dimension to modify |
968
|
|
|
:param _slice: The slice value to modify |
969
|
|
|
:return: The modified value |
970
|
|
|
""" |
971
|
|
|
if not current_val: |
972
|
|
|
current_val = self._set_empty_list( |
973
|
|
|
dim, self._set_empty_dimension_slice(value, _slice) |
974
|
|
|
) |
975
|
|
|
else: |
976
|
|
|
current_val[dim - 1] = self._modified_slice_notation( |
977
|
|
|
current_val[dim - 1], value, _slice |
978
|
|
|
) |
979
|
|
|
return current_val |
980
|
|
|
|
981
|
|
|
def _modified_slice_notation(self, old_value, value, _slice): |
982
|
|
|
"""Change the current value at the provided slice |
983
|
|
|
|
984
|
|
|
:param old_value: Previous slice notation |
985
|
|
|
:param value: New value to set |
986
|
|
|
:param _slice: Slice to modify |
987
|
|
|
:return: Changed value (str/int) |
988
|
|
|
""" |
989
|
|
|
old_value = self._set_incomplete_slices(str(old_value), _slice) |
990
|
|
|
if pu.is_slice_notation(old_value): |
991
|
|
|
start_stop_split = old_value.split(":") |
992
|
|
|
return self._get_modified_slice(start_stop_split, value, _slice) |
993
|
|
|
elif _slice == 0: |
994
|
|
|
# If there is no slice notation, only allow first slice to |
995
|
|
|
# be modified |
996
|
|
|
return value |
997
|
|
|
else: |
998
|
|
|
raise Exception( |
999
|
|
|
"There is no existing slice notation to modify." |
1000
|
|
|
) |
1001
|
|
|
|
1002
|
|
|
def _get_modified_slice(self, start_stop_split, value, _slice): |
1003
|
|
|
if all(v == "" for v in start_stop_split): |
1004
|
|
|
return self._set_empty_dimension_slice(value, _slice) |
1005
|
|
|
else: |
1006
|
|
|
start_stop_split[_slice] = str(value) |
1007
|
|
|
start_stop_split = ":".join(start_stop_split) |
1008
|
|
|
return start_stop_split |
1009
|
|
|
|
1010
|
|
|
def _modify_preview_dimension(self, value, current_preview, dim): |
1011
|
|
|
"""Modify the preview list value at the dimension provided (dim) |
1012
|
|
|
|
1013
|
|
|
:param value: The new value |
1014
|
|
|
:param current_value: The current preview parameter list value |
1015
|
|
|
:param dim: The dimension to modify |
1016
|
|
|
:return: The modified value |
1017
|
|
|
""" |
1018
|
|
|
if not current_preview: |
1019
|
|
|
return self._set_empty_list(dim, value) |
1020
|
|
|
current_preview[dim - 1] = value |
1021
|
|
|
# Save the altered preview value |
1022
|
|
|
return current_preview |
1023
|
|
|
|
1024
|
|
|
def _set_empty_dimension_slice(self, value, _slice): |
1025
|
|
|
"""Set the empty dimension and insert colons to indicate |
1026
|
|
|
the correct slice notation. |
1027
|
|
|
|
1028
|
|
|
:param value: New value to set |
1029
|
|
|
:param _slice: start/stop/step/chunk value |
1030
|
|
|
:return: String for the new value |
1031
|
|
|
""" |
1032
|
|
|
return _slice * ":" + str(value) |
1033
|
|
|
|
1034
|
|
|
def _set_incomplete_slices(self, old_value, _slice): |
1035
|
|
|
"""Append default slice values.to the current string value, in order |
1036
|
|
|
to allow later slice values to be set |
1037
|
|
|
|
1038
|
|
|
:param old_value: Current string value with slice notation |
1039
|
|
|
:param _slice: slice notation index to be edited |
1040
|
|
|
:return: String with default slice notation entries set |
1041
|
|
|
""" |
1042
|
|
|
while old_value.count(":") < _slice: |
1043
|
|
|
old_value += ":" |
1044
|
|
|
return old_value |
1045
|
|
|
|
1046
|
|
|
def _set_empty_list(self, dim, value): |
1047
|
|
|
"""If the dimension is 1 then allow the whole empty list |
1048
|
|
|
to be set. |
1049
|
|
|
|
1050
|
|
|
:param dim: Dimension to be altered |
1051
|
|
|
:param value: New value |
1052
|
|
|
:return: List containing new value |
1053
|
|
|
""" |
1054
|
|
|
if dim == 1: |
1055
|
|
|
return [value] |
1056
|
|
|
else: |
1057
|
|
|
raise ValueError("You have not set earlier dimensions") |
1058
|
|
|
|
1059
|
|
|
def level(self, level): |
1060
|
|
|
""" Set the visibility level of parameters """ |
1061
|
|
|
if level: |
1062
|
|
|
self.disp_level = level |
1063
|
|
|
print(f"Level set to '{level}'") |
1064
|
|
|
else: |
1065
|
|
|
print(f"Level is set at '{self.disp_level}'") |
1066
|
|
|
|
1067
|
|
|
def remove(self, pos): |
1068
|
|
|
if pos >= self.size: |
1069
|
|
|
raise Exception( |
1070
|
|
|
"Cannot remove plugin %s as it does not exist." |
1071
|
|
|
% self.plugin_list.plugin_list[pos]["name"] |
1072
|
|
|
) |
1073
|
|
|
pos_str = self.plugin_list.plugin_list[pos]["pos"] |
1074
|
|
|
self.plugin_list.plugin_list.pop(pos) |
1075
|
|
|
pos_list = self.get_split_positions() |
1076
|
|
|
self.inc_positions(pos, pos_list, pos_str, -1) |
1077
|
|
|
|
1078
|
|
|
@property |
1079
|
|
|
def size(self): |
1080
|
|
|
return len(self.plugin_list.plugin_list) |
1081
|
|
|
|