FunVIP 0.3.20__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- FunVIP-0.3.20.dist-info/LICENSE +674 -0
- FunVIP-0.3.20.dist-info/METADATA +32 -0
- FunVIP-0.3.20.dist-info/RECORD +36 -0
- FunVIP-0.3.20.dist-info/WHEEL +5 -0
- FunVIP-0.3.20.dist-info/entry_points.txt +3 -0
- FunVIP-0.3.20.dist-info/top_level.txt +3 -0
- data/__init__.py +0 -0
- external/BLAST_Windows/bin/cleanup-blastdb-volumes.py +162 -0
- external/__init__.py +0 -0
- src/__init__.py +0 -0
- src/align.py +124 -0
- src/cluster.py +510 -0
- src/command.py +360 -0
- src/concatenate.py +356 -0
- src/dataset.py +716 -0
- src/ext.py +448 -0
- src/hasher.py +98 -0
- src/initialize.py +335 -0
- src/logger.py +69 -0
- src/logics.py +104 -0
- src/modeltest.py +443 -0
- src/ncbi.py +160 -0
- src/opt_generator.py +72 -0
- src/patch.py +261 -0
- src/reporter.py +875 -0
- src/save.py +181 -0
- src/search.py +440 -0
- src/tool.py +309 -0
- src/tree.py +222 -0
- src/tree_interpretation.py +1379 -0
- src/tree_interpretation_pipe.py +679 -0
- src/trim.py +118 -0
- src/validate_input.py +846 -0
- src/validate_option.py +1609 -0
- src/validation.py +38 -0
- src/version.py +337 -0
src/validate_option.py
ADDED
|
@@ -0,0 +1,1609 @@
|
|
|
1
|
+
# Validate option parsed from CommandParser in command.py
|
|
2
|
+
import copy
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
import yaml
|
|
6
|
+
import builtins
|
|
7
|
+
import datetime
|
|
8
|
+
import re
|
|
9
|
+
import psutil
|
|
10
|
+
from funvip.src.logics import isvalidcolor
|
|
11
|
+
from funvip.src.tool import check_avx
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# FunVIP Option class definition
|
|
15
|
+
class Option:
|
|
16
|
+
# Method option
|
|
17
|
+
class Method_Option:
|
|
18
|
+
def __init__(self):
|
|
19
|
+
self.search = "blast"
|
|
20
|
+
self.alignment = "mafft"
|
|
21
|
+
self.trim = "trimal"
|
|
22
|
+
self.modeltest = "none"
|
|
23
|
+
self.tree = "fasttree"
|
|
24
|
+
|
|
25
|
+
# Visualize option
|
|
26
|
+
class Visualize_Option:
|
|
27
|
+
def __init__(self):
|
|
28
|
+
self.bscutoff = 70
|
|
29
|
+
self.highlight = "#aa0000"
|
|
30
|
+
self.heightmultiplier = 6
|
|
31
|
+
self.maxwordlength = 48
|
|
32
|
+
self.backgroundcolor = ["#ffe0e0", "#ffefef"]
|
|
33
|
+
self.outgroupcolor = "#999999"
|
|
34
|
+
self.ftype = "Arial"
|
|
35
|
+
self.fsize = 10
|
|
36
|
+
self.fsize_bootstrap = 9
|
|
37
|
+
|
|
38
|
+
# Cluster option
|
|
39
|
+
class Cluster_Option:
|
|
40
|
+
def __init__(self):
|
|
41
|
+
self.cutoff = 0.95
|
|
42
|
+
self.evalue = 10
|
|
43
|
+
self.wordsize = 7
|
|
44
|
+
self.outgroupoffset = 20
|
|
45
|
+
|
|
46
|
+
# MAFFT option
|
|
47
|
+
class MAFFT_Option:
|
|
48
|
+
def __init__(self):
|
|
49
|
+
self.algorithm = "auto"
|
|
50
|
+
self.op = 1.3
|
|
51
|
+
self.ep = 0.1
|
|
52
|
+
|
|
53
|
+
# TrimAl option
|
|
54
|
+
class TrimAl_Option:
|
|
55
|
+
def __init__(self):
|
|
56
|
+
self.algorithm = "gt"
|
|
57
|
+
self.gt = 0.2 # Should be found
|
|
58
|
+
|
|
59
|
+
# Option will be generated by file, and iteratively
|
|
60
|
+
def __init__(self):
|
|
61
|
+
# Running options
|
|
62
|
+
self.query = []
|
|
63
|
+
self.db = []
|
|
64
|
+
self.gene = []
|
|
65
|
+
self.email = ""
|
|
66
|
+
self.api = ""
|
|
67
|
+
self.test = None
|
|
68
|
+
self.thread = "auto"
|
|
69
|
+
self.memory = f"{int(psutil.virtual_memory().total / (1024 ** 3))}G"
|
|
70
|
+
self.outdir = None
|
|
71
|
+
self.runname = None
|
|
72
|
+
self.mode = "identification"
|
|
73
|
+
self.continue_from_previous = False
|
|
74
|
+
self.criterion = "BIC"
|
|
75
|
+
self.allow_innertrimming = False
|
|
76
|
+
self.step = ""
|
|
77
|
+
self.level = "genus"
|
|
78
|
+
self.queryonly = True
|
|
79
|
+
self.confident = True
|
|
80
|
+
self.verbose = 2
|
|
81
|
+
self.maxoutgroup = 3
|
|
82
|
+
self.collapsedistcutoff = 0.01
|
|
83
|
+
self.collapsebscutoff = 101
|
|
84
|
+
self.bootstrap = 100
|
|
85
|
+
self.solveflat = True
|
|
86
|
+
self.regex = None
|
|
87
|
+
self.avx = True
|
|
88
|
+
self.cachedb = True
|
|
89
|
+
self.usecache = True
|
|
90
|
+
self.tableformat = "csv"
|
|
91
|
+
self.nosearchresult = False
|
|
92
|
+
|
|
93
|
+
# Method options
|
|
94
|
+
self.method = self.Method_Option()
|
|
95
|
+
|
|
96
|
+
# Visualization options
|
|
97
|
+
self.visualize = self.Visualize_Option()
|
|
98
|
+
|
|
99
|
+
# Cluster options
|
|
100
|
+
self.cluster = self.Cluster_Option()
|
|
101
|
+
|
|
102
|
+
# MAFFT options
|
|
103
|
+
self.mafft = self.MAFFT_Option()
|
|
104
|
+
|
|
105
|
+
# TrimAl options
|
|
106
|
+
self.trimal = self.TrimAl_Option()
|
|
107
|
+
|
|
108
|
+
# update values from given preset
|
|
109
|
+
def update_from_preset(self, preset_file):
|
|
110
|
+
# Try to parser preset file
|
|
111
|
+
with open(preset_file) as f:
|
|
112
|
+
try:
|
|
113
|
+
parser_dict = yaml.safe_load(f)
|
|
114
|
+
except:
|
|
115
|
+
print(f"{preset_file} is not a valid preset yaml file")
|
|
116
|
+
raise Exception
|
|
117
|
+
|
|
118
|
+
# Update loaded preset
|
|
119
|
+
for key in parser_dict:
|
|
120
|
+
# Basic options
|
|
121
|
+
if key.lower() in ("query"):
|
|
122
|
+
self.query = parser_dict[key]
|
|
123
|
+
elif key.lower() in ("db"):
|
|
124
|
+
self.db = parser_dict[key]
|
|
125
|
+
elif key.lower() in ("gene"):
|
|
126
|
+
self.gene = parser_dict[key]
|
|
127
|
+
elif key.lower() in ("email"):
|
|
128
|
+
self.email = parser_dict[key]
|
|
129
|
+
elif key.lower() in ("api"):
|
|
130
|
+
self.api = parser_dict[key]
|
|
131
|
+
elif key.lower() in ("thread"):
|
|
132
|
+
self.thread = parser_dict[key]
|
|
133
|
+
elif key.lower() in ("memory"):
|
|
134
|
+
self.memory = parser_dict[key]
|
|
135
|
+
elif key.lower() in ("outdir"):
|
|
136
|
+
self.outdir = parser_dict[key]
|
|
137
|
+
elif key.lower() in ("runname"):
|
|
138
|
+
self.runname = parser_dict[key]
|
|
139
|
+
elif key.lower() in ("mode"):
|
|
140
|
+
self.mode = parser_dict[key]
|
|
141
|
+
elif key.lower() in ("continue"):
|
|
142
|
+
self.continue_from_previous = parser_dict[key]
|
|
143
|
+
elif key.lower() in ("step"):
|
|
144
|
+
self.step = parser_dict[key]
|
|
145
|
+
elif key.lower() in ("level"):
|
|
146
|
+
self.level = parser_dict[key]
|
|
147
|
+
elif key.lower() in ("queryonly", "all"):
|
|
148
|
+
if key.lower() == "queryonly":
|
|
149
|
+
self.queryonly = parser_dict[key]
|
|
150
|
+
elif key.lower() == "all":
|
|
151
|
+
self.queryonly = ~parser_dicy[key]
|
|
152
|
+
elif key.lower() in ("verbose"):
|
|
153
|
+
self.verbose = parser_dict[key]
|
|
154
|
+
elif key.lower() in ("maxoutgroup"):
|
|
155
|
+
self.maxoutgroup = parser_dict[key]
|
|
156
|
+
elif key.lower() in ("collapsedistcutoff"):
|
|
157
|
+
self.collapsedistcutoff = parser_dict[key]
|
|
158
|
+
elif key.lower() in ("collapsebscutoff"):
|
|
159
|
+
self.collapsebscutoff = parser_dict[key]
|
|
160
|
+
elif key.lower() in ("bootstrap"):
|
|
161
|
+
self.bootstrap = parser_dict[key]
|
|
162
|
+
elif key.lower() in ("solveflat"):
|
|
163
|
+
self.solveflat = parser_dict[key]
|
|
164
|
+
elif key.lower() in ("regex"):
|
|
165
|
+
self.regex = parser_dict[key]
|
|
166
|
+
elif key.lower() in ("avx"):
|
|
167
|
+
self.avx = parser_dict[key]
|
|
168
|
+
elif key.lower() in ("allow-innertrimming"):
|
|
169
|
+
self.allow_innertrimming = parser_dict[key]
|
|
170
|
+
elif key.lower() in ("criterion"):
|
|
171
|
+
self.criterion = parser_dict[key]
|
|
172
|
+
elif key.lower() in ("cachedb"):
|
|
173
|
+
self.cachedb = parser_dict[key]
|
|
174
|
+
elif key.lower() in ("usecache"):
|
|
175
|
+
self.usecache = parser_dict[key]
|
|
176
|
+
elif key.lower() in ("tableformat"):
|
|
177
|
+
self.tableformat = parser_dict[key]
|
|
178
|
+
elif key.lower() in ("nosearchresult"):
|
|
179
|
+
self.nosearchresult = parser_dict[key]
|
|
180
|
+
elif key.lower() in ("confident"):
|
|
181
|
+
self.confident = parser_dict[key]
|
|
182
|
+
|
|
183
|
+
# Method options
|
|
184
|
+
elif key.lower() in ("search"):
|
|
185
|
+
self.method.search = parser_dict[key]
|
|
186
|
+
elif key.lower() in ("alignment"):
|
|
187
|
+
self.method.alignment = parser_dict[key]
|
|
188
|
+
elif key.lower() in ("trim"):
|
|
189
|
+
self.method.trim = parser_dict[key]
|
|
190
|
+
elif key.lower() in ("modeltest"):
|
|
191
|
+
self.method.modeltest = parser_dict[key]
|
|
192
|
+
elif key.lower() in ("tree"):
|
|
193
|
+
self.method.tree = parser_dict[key]
|
|
194
|
+
|
|
195
|
+
# Visualize options
|
|
196
|
+
elif key.lower() in ("bscutoff"):
|
|
197
|
+
self.visualize.bscutoff = parser_dict[key]
|
|
198
|
+
elif key.lower() in ("bootstrapcutoff"):
|
|
199
|
+
self.visualize.bscutoff = parser_dict[key]
|
|
200
|
+
elif key.lower() in ("highlight"):
|
|
201
|
+
self.visualize.highlight = parser_dict[key]
|
|
202
|
+
elif key.lower() in ("heightmultiplier"):
|
|
203
|
+
self.visualize.heightmultiplier = parser_dict[key]
|
|
204
|
+
elif key.lower() in ("maxwordlength"):
|
|
205
|
+
self.visualize.maxwordlength = parser_dict[key]
|
|
206
|
+
elif key.lower() in ("backgroundcolor"):
|
|
207
|
+
self.visualize.backgroundcolor = parser_dict[key]
|
|
208
|
+
elif key.lower() in ("outgroupcolor"):
|
|
209
|
+
self.visualize.outgroupcolor = parser_dict[key]
|
|
210
|
+
elif key.lower() in ("ftype"):
|
|
211
|
+
self.visualize.ftype = parser_dict[key]
|
|
212
|
+
elif key.lower() in ("fsize"):
|
|
213
|
+
self.visualize.fsize = parser_dict[key]
|
|
214
|
+
elif key.lower() in ("fsize_bootstrap"):
|
|
215
|
+
self.visualize.fsize_bootstrap = parser_dict[key]
|
|
216
|
+
|
|
217
|
+
# Cluster options
|
|
218
|
+
elif key.lower() in ("cluster-cutoff"):
|
|
219
|
+
self.cluster.evalue = parser_dict[key]
|
|
220
|
+
elif key.lower() in ("evalue", "cluster-evalue"):
|
|
221
|
+
self.cluster.evalue = parser_dict[key]
|
|
222
|
+
elif key.lower() in ("wordsize"):
|
|
223
|
+
self.cluster.wordsize = parser_dict[key]
|
|
224
|
+
elif key.lower() in ("outgroupoffset"):
|
|
225
|
+
self.cluster.wordsize = parser_dict[key]
|
|
226
|
+
|
|
227
|
+
# MAFFT options
|
|
228
|
+
elif key.lower() in ("mafft-algorithm"):
|
|
229
|
+
self.mafft.algorithm = parser_dict[key]
|
|
230
|
+
elif key.lower() in ("mafft-op"):
|
|
231
|
+
self.mafft.op = parser_dict[key]
|
|
232
|
+
elif key.lower() in ("mafft-ep"):
|
|
233
|
+
self.mafft.ep = parser_dict[key]
|
|
234
|
+
|
|
235
|
+
# TrimAl options
|
|
236
|
+
elif key.lower() in ("trimal-algorithm"):
|
|
237
|
+
self.trimal.algorithm = parser_dict[key]
|
|
238
|
+
elif key.lower() in ("trimal-gt"):
|
|
239
|
+
self.trimal.gt = parser_dict[key]
|
|
240
|
+
else:
|
|
241
|
+
print(f"cannot recoginze {key} in preset file as valid variable")
|
|
242
|
+
|
|
243
|
+
# update values from parser object
|
|
244
|
+
def update_from_parser(self, parser):
|
|
245
|
+
# Parsed terms will have higher priority from preset file
|
|
246
|
+
# test should not be parsed here (should be parsed in initialize option)
|
|
247
|
+
|
|
248
|
+
try:
|
|
249
|
+
if not parser.query is None:
|
|
250
|
+
self.query = parser.query
|
|
251
|
+
except:
|
|
252
|
+
pass
|
|
253
|
+
|
|
254
|
+
try:
|
|
255
|
+
if not parser.db is None:
|
|
256
|
+
self.db = parser.db
|
|
257
|
+
except:
|
|
258
|
+
pass
|
|
259
|
+
|
|
260
|
+
try:
|
|
261
|
+
if not parser.gene is None:
|
|
262
|
+
self.gene = parser.gene
|
|
263
|
+
except:
|
|
264
|
+
pass
|
|
265
|
+
|
|
266
|
+
try:
|
|
267
|
+
if not parser.email is None:
|
|
268
|
+
self.email = parser.email
|
|
269
|
+
except:
|
|
270
|
+
pass
|
|
271
|
+
|
|
272
|
+
try:
|
|
273
|
+
if not parser.api is None:
|
|
274
|
+
self.api = parser.api
|
|
275
|
+
except:
|
|
276
|
+
pass
|
|
277
|
+
|
|
278
|
+
try:
|
|
279
|
+
if not parser.thread is None:
|
|
280
|
+
self.thread = parser.thread
|
|
281
|
+
except:
|
|
282
|
+
pass
|
|
283
|
+
|
|
284
|
+
try:
|
|
285
|
+
if not parser.memory is None:
|
|
286
|
+
self.memory = parser.memory
|
|
287
|
+
except:
|
|
288
|
+
pass
|
|
289
|
+
|
|
290
|
+
try:
|
|
291
|
+
if not parser.runname is None:
|
|
292
|
+
self.runname = parser.runname
|
|
293
|
+
except:
|
|
294
|
+
pass
|
|
295
|
+
|
|
296
|
+
# Create runname directory in outdir location
|
|
297
|
+
try:
|
|
298
|
+
if not parser.outdir is None:
|
|
299
|
+
self.outdir = parser.outdir
|
|
300
|
+
except:
|
|
301
|
+
pass
|
|
302
|
+
|
|
303
|
+
try:
|
|
304
|
+
if not parser.mode is None:
|
|
305
|
+
self.mode = parser.mode
|
|
306
|
+
except:
|
|
307
|
+
pass
|
|
308
|
+
|
|
309
|
+
try:
|
|
310
|
+
if not parser.continue_from_previous is None:
|
|
311
|
+
self.continue_from_previous = parser.continue_from_previous
|
|
312
|
+
except:
|
|
313
|
+
pass
|
|
314
|
+
|
|
315
|
+
try:
|
|
316
|
+
if not parser.step is None:
|
|
317
|
+
self.step = parser.step
|
|
318
|
+
except:
|
|
319
|
+
pass
|
|
320
|
+
|
|
321
|
+
try:
|
|
322
|
+
if not parser.level is None:
|
|
323
|
+
self.level = parser.level
|
|
324
|
+
except:
|
|
325
|
+
pass
|
|
326
|
+
|
|
327
|
+
try:
|
|
328
|
+
if parser.all is True:
|
|
329
|
+
self.queryonly = not (parser.all)
|
|
330
|
+
except:
|
|
331
|
+
pass
|
|
332
|
+
|
|
333
|
+
try:
|
|
334
|
+
if not parser.confident is None:
|
|
335
|
+
self.confident = parser.confident
|
|
336
|
+
except:
|
|
337
|
+
pass
|
|
338
|
+
|
|
339
|
+
try:
|
|
340
|
+
if not parser.search is None:
|
|
341
|
+
self.method.search = parser.search
|
|
342
|
+
except:
|
|
343
|
+
pass
|
|
344
|
+
|
|
345
|
+
try:
|
|
346
|
+
if not parser.alignment is None:
|
|
347
|
+
self.method.alignment = parser.alignment
|
|
348
|
+
except:
|
|
349
|
+
pass
|
|
350
|
+
|
|
351
|
+
try:
|
|
352
|
+
if not parser.trim is None:
|
|
353
|
+
self.method.trim = parser.trim
|
|
354
|
+
except:
|
|
355
|
+
pass
|
|
356
|
+
|
|
357
|
+
try:
|
|
358
|
+
if not parser.modeltest is None:
|
|
359
|
+
self.method.modeltest = parser.modeltest
|
|
360
|
+
except:
|
|
361
|
+
pass
|
|
362
|
+
|
|
363
|
+
try:
|
|
364
|
+
if not parser.tree is None:
|
|
365
|
+
self.method.tree = parser.tree
|
|
366
|
+
except:
|
|
367
|
+
pass
|
|
368
|
+
|
|
369
|
+
try:
|
|
370
|
+
if not parser.bscutoff is None:
|
|
371
|
+
self.visualize.bscutoff = parser.bscutoff
|
|
372
|
+
except:
|
|
373
|
+
pass
|
|
374
|
+
|
|
375
|
+
try:
|
|
376
|
+
if not parser.highlight is None:
|
|
377
|
+
self.visualize.highlight = parser.highlight
|
|
378
|
+
except:
|
|
379
|
+
pass
|
|
380
|
+
|
|
381
|
+
try:
|
|
382
|
+
if not parser.heightmultiplier is None:
|
|
383
|
+
self.visualize.heightmultiplier = parser.heightmultiplier
|
|
384
|
+
except:
|
|
385
|
+
pass
|
|
386
|
+
|
|
387
|
+
try:
|
|
388
|
+
if not parser.maxwordlength is None:
|
|
389
|
+
self.visualize.maxwordlength = parser.maxwordlength
|
|
390
|
+
except:
|
|
391
|
+
pass
|
|
392
|
+
|
|
393
|
+
try:
|
|
394
|
+
if not parser.backgroundcolor is None:
|
|
395
|
+
self.visualize.backgroundcolor = parser.backgroundcolor
|
|
396
|
+
except:
|
|
397
|
+
pass
|
|
398
|
+
|
|
399
|
+
try:
|
|
400
|
+
if not parser.outgroupcolor is None:
|
|
401
|
+
self.visualize.outgroupcolor = parser.outgroupcolor
|
|
402
|
+
except:
|
|
403
|
+
pass
|
|
404
|
+
|
|
405
|
+
try:
|
|
406
|
+
if not parser.ftype is None:
|
|
407
|
+
self.visualize.ftype = parser.ftype
|
|
408
|
+
except:
|
|
409
|
+
pass
|
|
410
|
+
|
|
411
|
+
try:
|
|
412
|
+
if not parser.fsize is None:
|
|
413
|
+
self.visualize.fsize = parser.fsize
|
|
414
|
+
except:
|
|
415
|
+
pass
|
|
416
|
+
|
|
417
|
+
try:
|
|
418
|
+
if not parser.fsize_bootstrap is None:
|
|
419
|
+
self.visualize.fsize_bootstrap = parser.fsize_bootstrap
|
|
420
|
+
except:
|
|
421
|
+
pass
|
|
422
|
+
|
|
423
|
+
try:
|
|
424
|
+
if not parser.verbose is None:
|
|
425
|
+
self.verbose = parser.verbose
|
|
426
|
+
except:
|
|
427
|
+
pass
|
|
428
|
+
|
|
429
|
+
try:
|
|
430
|
+
if not parser.maxoutgroup is None:
|
|
431
|
+
self.maxoutgroup = parser.maxoutgroup
|
|
432
|
+
except:
|
|
433
|
+
pass
|
|
434
|
+
|
|
435
|
+
try:
|
|
436
|
+
if not parser.collapsedistcutoff is None:
|
|
437
|
+
self.collapsedistcutoff = parser.collapsedistcutoff
|
|
438
|
+
except:
|
|
439
|
+
pass
|
|
440
|
+
|
|
441
|
+
try:
|
|
442
|
+
if not parser.collapsebscutoff is None:
|
|
443
|
+
self.collapsebscutoff = parser.collapsebscutoff
|
|
444
|
+
except:
|
|
445
|
+
pass
|
|
446
|
+
|
|
447
|
+
try:
|
|
448
|
+
if not parser.bootstrap is None:
|
|
449
|
+
self.bootstrap = parser.bootstrap
|
|
450
|
+
except:
|
|
451
|
+
pass
|
|
452
|
+
|
|
453
|
+
try:
|
|
454
|
+
if parser.solveflat is True:
|
|
455
|
+
self.solveflat = parser.solveflat
|
|
456
|
+
except:
|
|
457
|
+
pass
|
|
458
|
+
|
|
459
|
+
try:
|
|
460
|
+
if not parser.regex is None:
|
|
461
|
+
self.regex = parser.regex
|
|
462
|
+
except:
|
|
463
|
+
pass
|
|
464
|
+
|
|
465
|
+
try:
|
|
466
|
+
if not parser.cluster_cutoff is None:
|
|
467
|
+
self.cluster.cutoff = parser.cluster_cutoff
|
|
468
|
+
except:
|
|
469
|
+
pass
|
|
470
|
+
|
|
471
|
+
try:
|
|
472
|
+
if not parser.cluster_evalue is None:
|
|
473
|
+
self.cluster.evalue = parser.cluster_evalue
|
|
474
|
+
except:
|
|
475
|
+
pass
|
|
476
|
+
|
|
477
|
+
try:
|
|
478
|
+
if not parser.cluster_wordsize is None:
|
|
479
|
+
self.cluster.wordsize = parser.cluster_wordsize
|
|
480
|
+
except:
|
|
481
|
+
pass
|
|
482
|
+
|
|
483
|
+
try:
|
|
484
|
+
if not parser.cluster_outgroupoffset is None:
|
|
485
|
+
self.cluster.outgroupoffset = parser.cluster_outgroupoffset
|
|
486
|
+
except:
|
|
487
|
+
pass
|
|
488
|
+
|
|
489
|
+
try:
|
|
490
|
+
if not parser.mafft_algorithm is None:
|
|
491
|
+
self.mafft.algorithm = parser.mafft_algorithm
|
|
492
|
+
except:
|
|
493
|
+
pass
|
|
494
|
+
|
|
495
|
+
try:
|
|
496
|
+
if not parser.mafft_op is None:
|
|
497
|
+
self.mafft.op = parser.mafft_op
|
|
498
|
+
except:
|
|
499
|
+
pass
|
|
500
|
+
|
|
501
|
+
try:
|
|
502
|
+
if not parser.mafft_ep is None:
|
|
503
|
+
self.mafft.ep = parser.mafft_ep
|
|
504
|
+
except:
|
|
505
|
+
pass
|
|
506
|
+
|
|
507
|
+
try:
|
|
508
|
+
if not parser.trimal_algorithm is None:
|
|
509
|
+
self.trimal.algorithm = parser.trimal_algorithm
|
|
510
|
+
except:
|
|
511
|
+
pass
|
|
512
|
+
|
|
513
|
+
try:
|
|
514
|
+
if not parser.trimal_gt is None:
|
|
515
|
+
self.trimal.gt = parser.trimal_gt
|
|
516
|
+
except:
|
|
517
|
+
pass
|
|
518
|
+
|
|
519
|
+
try:
|
|
520
|
+
if parser.noavx is True:
|
|
521
|
+
self.avx = False
|
|
522
|
+
except:
|
|
523
|
+
pass
|
|
524
|
+
|
|
525
|
+
try:
|
|
526
|
+
if not parser.criterion is None:
|
|
527
|
+
self.criterion = parser.criterion
|
|
528
|
+
except:
|
|
529
|
+
pass
|
|
530
|
+
|
|
531
|
+
try:
|
|
532
|
+
if not parser.allow_innertrimming is None:
|
|
533
|
+
self.allow_innertrimming = parser.allow_innertrimming
|
|
534
|
+
except:
|
|
535
|
+
pass
|
|
536
|
+
|
|
537
|
+
try:
|
|
538
|
+
if parser.cachedb is True:
|
|
539
|
+
self.cachedb = parser.cachedb
|
|
540
|
+
except:
|
|
541
|
+
pass
|
|
542
|
+
|
|
543
|
+
try:
|
|
544
|
+
if parser.usecache is True:
|
|
545
|
+
self.usecache = parser.usecache
|
|
546
|
+
except:
|
|
547
|
+
pass
|
|
548
|
+
|
|
549
|
+
try:
|
|
550
|
+
if not parser.tableformat is None:
|
|
551
|
+
self.tableformat = parser.tableformat
|
|
552
|
+
except:
|
|
553
|
+
pass
|
|
554
|
+
|
|
555
|
+
try:
|
|
556
|
+
if parser.nosearchresult is True:
|
|
557
|
+
self.nosearchresult = parser.nosearchresult
|
|
558
|
+
except:
|
|
559
|
+
pass
|
|
560
|
+
|
|
561
|
+
# Valiate current status preset
|
|
562
|
+
def validate(self):
|
|
563
|
+
list_info = []
|
|
564
|
+
list_error = []
|
|
565
|
+
list_warning = []
|
|
566
|
+
|
|
567
|
+
# query
|
|
568
|
+
# Check if query files are in valid directories
|
|
569
|
+
if not (type(self.query) is list):
|
|
570
|
+
list_error.append(f"Type for query should be list format")
|
|
571
|
+
else:
|
|
572
|
+
flag_query = 0
|
|
573
|
+
for query in self.query:
|
|
574
|
+
if not (type(query) is str):
|
|
575
|
+
list_error.append(f"query {query} is not a valid string format")
|
|
576
|
+
flag_query = 1
|
|
577
|
+
|
|
578
|
+
if flag_query == 0:
|
|
579
|
+
# Adjust query location if query is in test dataset
|
|
580
|
+
if not (self.test is None):
|
|
581
|
+
path_query = os.path.abspath(
|
|
582
|
+
f"{os.path.dirname(__file__)}/../test_dataset/{self.test}/Query"
|
|
583
|
+
)
|
|
584
|
+
|
|
585
|
+
self.query = [f"{path_query}/{query}" for query in self.query]
|
|
586
|
+
|
|
587
|
+
for query in self.query:
|
|
588
|
+
# Check if query location is valid
|
|
589
|
+
try:
|
|
590
|
+
if not (os.path.exists(f"{query}")):
|
|
591
|
+
list_error.append(f"{query} is not a valid query path")
|
|
592
|
+
except:
|
|
593
|
+
pass
|
|
594
|
+
|
|
595
|
+
# db
|
|
596
|
+
# Check if db files are in valid
|
|
597
|
+
if not (type(self.db) is list):
|
|
598
|
+
list_error.append(f"Type for db should be list format")
|
|
599
|
+
else:
|
|
600
|
+
flag_db = 0
|
|
601
|
+
for db in self.db:
|
|
602
|
+
if not (type(db) is str):
|
|
603
|
+
list_error.append(f"db {db} is not a valid string format")
|
|
604
|
+
flag_db = 1
|
|
605
|
+
|
|
606
|
+
if flag_db == 0:
|
|
607
|
+
# Adjust db location if db is in test dataset
|
|
608
|
+
if not (self.test is None):
|
|
609
|
+
path_db = os.path.abspath(
|
|
610
|
+
f"{os.path.dirname(__file__)}/../test_dataset/{self.test}/DB"
|
|
611
|
+
)
|
|
612
|
+
self.db = [f"{path_db}/{db}" for db in self.db]
|
|
613
|
+
|
|
614
|
+
for db in self.db:
|
|
615
|
+
# Check if DB location is valid
|
|
616
|
+
try:
|
|
617
|
+
if not (os.path.exists(f"{db}")):
|
|
618
|
+
list_error.append(f"{db} is not a valid db path")
|
|
619
|
+
except:
|
|
620
|
+
pass
|
|
621
|
+
|
|
622
|
+
# Change all db path into linux style
|
|
623
|
+
|
|
624
|
+
# gene
|
|
625
|
+
# Check if gene names are valid strings (comparing with db will be performed in parsing)
|
|
626
|
+
if not (type(self.gene) is list):
|
|
627
|
+
list_error.append(f"Type for gene should be list format")
|
|
628
|
+
elif len(self.gene) < 1:
|
|
629
|
+
list_error.append(f"At least one gene should be designated")
|
|
630
|
+
else:
|
|
631
|
+
self.gene = [g.strip() for g in self.gene]
|
|
632
|
+
for gene in self.gene:
|
|
633
|
+
if not (type(gene) is str):
|
|
634
|
+
list_error.append(f"gene {gene} is not a valid string format")
|
|
635
|
+
else:
|
|
636
|
+
if sys.platform == "win32" and " " in gene:
|
|
637
|
+
list_error.append(
|
|
638
|
+
f"You cannot use space for genename in windows platform : {gene}"
|
|
639
|
+
)
|
|
640
|
+
|
|
641
|
+
# email
|
|
642
|
+
# Check if email is in valid format
|
|
643
|
+
if self.email is None:
|
|
644
|
+
pass
|
|
645
|
+
else:
|
|
646
|
+
if not (type(self.email) is str):
|
|
647
|
+
list_error.append(f"Type for email should be string")
|
|
648
|
+
email_pattern = r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$"
|
|
649
|
+
if not (re.match(email_pattern, self.email)):
|
|
650
|
+
if self.email == "":
|
|
651
|
+
list_warning.append(
|
|
652
|
+
f"Email not provided. If your database includes GenBank accession, please provide email"
|
|
653
|
+
)
|
|
654
|
+
else:
|
|
655
|
+
list_error.append(f"Email {self.email} is not a valid email")
|
|
656
|
+
|
|
657
|
+
# api
|
|
658
|
+
# Check if api number is in valid format
|
|
659
|
+
# Connect to entrez once to check api is valid
|
|
660
|
+
if self.api is None:
|
|
661
|
+
pass
|
|
662
|
+
else:
|
|
663
|
+
if not (type(self.api) is str):
|
|
664
|
+
list_error.append(f"Type for api should be string")
|
|
665
|
+
|
|
666
|
+
# Check either email or api exists
|
|
667
|
+
if self.email is None and self.api is None:
|
|
668
|
+
list_warning.append(
|
|
669
|
+
f"Email and API both were not given. May cause error when downloading sequence"
|
|
670
|
+
)
|
|
671
|
+
|
|
672
|
+
# thread
|
|
673
|
+
# Check if thread is valid int
|
|
674
|
+
# If thread is over system thread, 0, or negative, adjust it to maximum
|
|
675
|
+
if not (type(self.thread) is int):
|
|
676
|
+
if not (type(self.thread) is str):
|
|
677
|
+
list_warning.append(
|
|
678
|
+
f"Type for thread should be int but {self.thread} was given. Using {os.cpu_count()} for default"
|
|
679
|
+
)
|
|
680
|
+
else:
|
|
681
|
+
if not (self.thread.lower() == "auto"):
|
|
682
|
+
list_warning.append(
|
|
683
|
+
f"Type for thread should be int but {self.thread} was given. Using {os.cpu_count()} for default"
|
|
684
|
+
)
|
|
685
|
+
|
|
686
|
+
self.thread = os.cpu_count()
|
|
687
|
+
elif self.thread <= 0:
|
|
688
|
+
list_info.append(f"thread adjusted to {os.cpu_count()}")
|
|
689
|
+
self.thread = os.cpu_count()
|
|
690
|
+
elif self.thread >= os.cpu_count():
|
|
691
|
+
list_info.append(
|
|
692
|
+
f"thread exceeded system maximum. Adjusting to {os.cpu_count()}"
|
|
693
|
+
)
|
|
694
|
+
self.thread = os.cpu_count()
|
|
695
|
+
|
|
696
|
+
# memory
|
|
697
|
+
# Check if memory is in valid format
|
|
698
|
+
# memory should be in XXG format like '16G'
|
|
699
|
+
# If memory is over system memory adjust it to maximum
|
|
700
|
+
# If memory is less than 4G, adjust it to 4G
|
|
701
|
+
if type(self.memory) is int or type(self.memory) is float:
|
|
702
|
+
list_warning.append(
|
|
703
|
+
f"Type for memory should be in format of 'nG' such as '16G', but {self.memory} was given. Considering {self.memory} as gigabytes"
|
|
704
|
+
)
|
|
705
|
+
self.memory = f"{int(self.memory)}G"
|
|
706
|
+
|
|
707
|
+
elif not type(self.memory) is str:
|
|
708
|
+
list_warning.append(
|
|
709
|
+
f"Type for memory should be in format of 'nG' such as '16G', but {self.memory} was given. Using maximum system memory"
|
|
710
|
+
)
|
|
711
|
+
self.memory = f"{int(psutil.virtual_memory().total / (1024 ** 3))}G"
|
|
712
|
+
elif not self.memory.endswith("G"):
|
|
713
|
+
list_warning.append(
|
|
714
|
+
f"Type for memory should be in format of 'nG' such as '16G', but {self.memory} was given. Using maximum system memory"
|
|
715
|
+
)
|
|
716
|
+
self.memory = f"{int(psutil.virtual_memory().total / (1024 ** 3))}G"
|
|
717
|
+
else:
|
|
718
|
+
try:
|
|
719
|
+
float(self.memory[:-1])
|
|
720
|
+
except:
|
|
721
|
+
list_warning.append(
|
|
722
|
+
f"Type for memory should be in format of 'nG' such as '16G', but {self.memory} was given. Using maximum system memory"
|
|
723
|
+
)
|
|
724
|
+
self.memory = f"{int(psutil.virtual_memory().total / (1024 ** 3))}G"
|
|
725
|
+
|
|
726
|
+
if float(self.memory[:-1]) < 4:
|
|
727
|
+
list_warning.append(
|
|
728
|
+
f"At least 4G of memory required for FunVIP. Try using 4G"
|
|
729
|
+
)
|
|
730
|
+
if psutil.virtual_memory().total / (1024**3) < 4:
|
|
731
|
+
list_error.append(f"Less than 4G of memory (RAM) detected ! Aborted")
|
|
732
|
+
else:
|
|
733
|
+
self.memory = "4G"
|
|
734
|
+
|
|
735
|
+
# outdir
|
|
736
|
+
# Check if outdirectory is valid path
|
|
737
|
+
# If outdir does not exists, try making directory
|
|
738
|
+
if self.outdir:
|
|
739
|
+
if not (os.path.exists(self.outdir)):
|
|
740
|
+
list_warning.append(
|
|
741
|
+
f"Out directory location {self.outdir} does not exists try making it"
|
|
742
|
+
)
|
|
743
|
+
try:
|
|
744
|
+
os.makedirs(self.outdir, mode=0o755, exist_ok=True)
|
|
745
|
+
except:
|
|
746
|
+
list_error.append(
|
|
747
|
+
f"Failed making outdir location {self.outdir}. Try checking directory or permissions"
|
|
748
|
+
)
|
|
749
|
+
|
|
750
|
+
# Change outdir to absolute path
|
|
751
|
+
self.outdir = str(os.path.abspath(self.outdir))
|
|
752
|
+
else:
|
|
753
|
+
self.outdir = os.getcwd()
|
|
754
|
+
|
|
755
|
+
# continue - continue should be validated before runname designated
|
|
756
|
+
# If continue is not None, give True, else, give False
|
|
757
|
+
# If continue is true, check if runname directory is valid
|
|
758
|
+
# If outdir is not distinctively selected, warn that it will overwrite previous run
|
|
759
|
+
if self.continue_from_previous is False or self.continue_from_previous is None:
|
|
760
|
+
self.continue_from_previous = False
|
|
761
|
+
else:
|
|
762
|
+
self.continue_from_previous = True
|
|
763
|
+
|
|
764
|
+
# runname
|
|
765
|
+
# Check if runname is valid string
|
|
766
|
+
# Check for existing runname
|
|
767
|
+
invalid_char = r'[\\/:*?"<>|]|\.|\s$'
|
|
768
|
+
|
|
769
|
+
# Use current time stamp if no runname given
|
|
770
|
+
if self.runname is None:
|
|
771
|
+
now = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
|
|
772
|
+
self.runname = now
|
|
773
|
+
|
|
774
|
+
if not (type(self.runname) is str):
|
|
775
|
+
list_error.append(f"runname should be string")
|
|
776
|
+
elif re.search(invalid_char, self.runname.strip()):
|
|
777
|
+
list_error.append(f"invalid characters in runname")
|
|
778
|
+
elif " " in self.runname.strip() and sys.platform == "win32":
|
|
779
|
+
list_error.append(
|
|
780
|
+
f"You should not include space for runname in windows platform"
|
|
781
|
+
)
|
|
782
|
+
else: # if valid runname
|
|
783
|
+
if self.continue_from_previous is True:
|
|
784
|
+
# Check if continue available
|
|
785
|
+
if not (os.path.exists(f"{self.outdir}/{self.runname}")):
|
|
786
|
+
list_error.append(
|
|
787
|
+
f"continue option selected, but previous run directory {self.runname} not found in {self.outdir}"
|
|
788
|
+
)
|
|
789
|
+
else:
|
|
790
|
+
# If already previous path exists
|
|
791
|
+
if os.path.exists(f"{self.outdir}/{self.runname}"):
|
|
792
|
+
# memo user designated runname
|
|
793
|
+
ori_runname = self.runname
|
|
794
|
+
# if same name exists, try to add numbers at the end to discriminate
|
|
795
|
+
i = 1
|
|
796
|
+
while 1:
|
|
797
|
+
if os.path.exists(f"{self.outdir}/{ori_runname}_{i}"):
|
|
798
|
+
i += 1
|
|
799
|
+
else:
|
|
800
|
+
self.runname = f"{ori_runname}_{i}"
|
|
801
|
+
break
|
|
802
|
+
|
|
803
|
+
# step
|
|
804
|
+
# Check if continue is True. If False, warn that step will be ignored
|
|
805
|
+
# Check if step is valid :
|
|
806
|
+
step = [
|
|
807
|
+
"setup",
|
|
808
|
+
"search",
|
|
809
|
+
"cluster",
|
|
810
|
+
"align",
|
|
811
|
+
"trim",
|
|
812
|
+
"concatenate",
|
|
813
|
+
"modeltest",
|
|
814
|
+
"tree",
|
|
815
|
+
"visualize",
|
|
816
|
+
"report",
|
|
817
|
+
]
|
|
818
|
+
|
|
819
|
+
if self.continue_from_previous is True:
|
|
820
|
+
if not (type(self.step) is str):
|
|
821
|
+
list_error.append(f"step should be string")
|
|
822
|
+
elif not (self.step in step):
|
|
823
|
+
list_error.append(f"step should be one of {str(step)}")
|
|
824
|
+
else:
|
|
825
|
+
if not self.step is None:
|
|
826
|
+
list_warning.append(
|
|
827
|
+
f"--continue is not designated, --step will be ignored"
|
|
828
|
+
)
|
|
829
|
+
|
|
830
|
+
# level
|
|
831
|
+
"""
|
|
832
|
+
# Check for valid level : subseries, series, subsection, section, subtribe,
|
|
833
|
+
tribe, subfamily, family, suborder, order, subclass, class, subdivision,
|
|
834
|
+
division, subphylum, phylum, subkingdom, kingdom
|
|
835
|
+
"""
|
|
836
|
+
level = [
|
|
837
|
+
"subseries",
|
|
838
|
+
"series",
|
|
839
|
+
"subsection",
|
|
840
|
+
"section",
|
|
841
|
+
"genus",
|
|
842
|
+
"subtribe",
|
|
843
|
+
"tribe",
|
|
844
|
+
"subfamily",
|
|
845
|
+
"family",
|
|
846
|
+
"suborder",
|
|
847
|
+
"order",
|
|
848
|
+
"subclass",
|
|
849
|
+
"class",
|
|
850
|
+
"subdivision",
|
|
851
|
+
"division",
|
|
852
|
+
"subphylum",
|
|
853
|
+
"phylum",
|
|
854
|
+
"subkingdom",
|
|
855
|
+
"kingdom",
|
|
856
|
+
]
|
|
857
|
+
|
|
858
|
+
if not (type(self.level) is str):
|
|
859
|
+
list_error.append(f"--level should be string")
|
|
860
|
+
elif not (self.level in level):
|
|
861
|
+
list_error.append(
|
|
862
|
+
f"--level should be one of {str(level)}, not {self.level}"
|
|
863
|
+
)
|
|
864
|
+
|
|
865
|
+
# mode
|
|
866
|
+
# Check for valid mode : identificaion or validation
|
|
867
|
+
mode = ["identification", "validation"]
|
|
868
|
+
if not (type(self.mode) is str):
|
|
869
|
+
list_error.append(f"--mode should be string")
|
|
870
|
+
elif not (self.mode in mode):
|
|
871
|
+
list_error.append(f"--mode should be one of {str(mode)}")
|
|
872
|
+
|
|
873
|
+
# queryonly
|
|
874
|
+
# If queryonly is not None, give True, else, give False
|
|
875
|
+
# If no query is empty, raise Exception
|
|
876
|
+
if not (self.queryonly is None or self.queryonly is False):
|
|
877
|
+
self.queryonly = True
|
|
878
|
+
else:
|
|
879
|
+
self.queryonly = False
|
|
880
|
+
|
|
881
|
+
if self.query:
|
|
882
|
+
if len(self.query) == 0:
|
|
883
|
+
list_warning.append(f"No query detected, activating --all")
|
|
884
|
+
self.queryonly = False
|
|
885
|
+
else:
|
|
886
|
+
list_warning.append(f"No query detected, activating --all")
|
|
887
|
+
self.queryonly = False
|
|
888
|
+
|
|
889
|
+
# confident
|
|
890
|
+
# If confident is not None, give True, else, give False
|
|
891
|
+
# "confident" option can be only used when queryonly is True
|
|
892
|
+
if not (self.confident is None or self.confident is False):
|
|
893
|
+
if self.queryonly is True:
|
|
894
|
+
self.confident = True
|
|
895
|
+
else:
|
|
896
|
+
list_warning.append(
|
|
897
|
+
f"Option --confident can be only used without --all. Ignoring it"
|
|
898
|
+
)
|
|
899
|
+
self.confident = False
|
|
900
|
+
else:
|
|
901
|
+
self.confident = False
|
|
902
|
+
|
|
903
|
+
# search
|
|
904
|
+
# Check if search method is one of default, blast, mmseqs
|
|
905
|
+
# Adjust misspellings
|
|
906
|
+
# If given value is default, change it to mmseqs
|
|
907
|
+
# If does not met to any of above, raise Exception
|
|
908
|
+
search = ["blast", "mmseqs"]
|
|
909
|
+
search_adjust = {
|
|
910
|
+
"default": "blast",
|
|
911
|
+
"blast": "blast",
|
|
912
|
+
"blastn": "blast",
|
|
913
|
+
"mmseq": "mmseqs",
|
|
914
|
+
"mmseqs": "mmseqs",
|
|
915
|
+
"mmseq2": "mmseqs",
|
|
916
|
+
"mmseqs2": "mmseqs",
|
|
917
|
+
}
|
|
918
|
+
if not (type(self.method.search) is str):
|
|
919
|
+
list_error.append(f"search method should be string")
|
|
920
|
+
else:
|
|
921
|
+
self.method.search = search_adjust[self.method.search.lower()]
|
|
922
|
+
if not (self.method.search in search):
|
|
923
|
+
list_error.append(f"search method should be one of {str(search)}")
|
|
924
|
+
|
|
925
|
+
# alignment
|
|
926
|
+
# Check if alignment method is one of default, mafft
|
|
927
|
+
# Adjust misspellings
|
|
928
|
+
# If given value is default, change it to mafft
|
|
929
|
+
# If does not met to any of above, raise Exception
|
|
930
|
+
alignment = ["mafft"]
|
|
931
|
+
alignment_adjust = {
|
|
932
|
+
"default": "mafft",
|
|
933
|
+
"mafft": "mafft",
|
|
934
|
+
}
|
|
935
|
+
if not (type(self.method.alignment) is str):
|
|
936
|
+
list_error.append(f"align method should be string")
|
|
937
|
+
else:
|
|
938
|
+
self.method.alignment = alignment_adjust[self.method.alignment.lower()]
|
|
939
|
+
if not (self.method.alignment in alignment):
|
|
940
|
+
list_error.append(f"align method should be one of {str(alignment)}")
|
|
941
|
+
|
|
942
|
+
# trim
|
|
943
|
+
# Check if trimming method is one of default, none, trimal, gblocks
|
|
944
|
+
# Adjust misspellings
|
|
945
|
+
# If given value is default, change it to none
|
|
946
|
+
# If does not met to any of above, raise Exception
|
|
947
|
+
trim = ["none", "trimal", "gblocks"]
|
|
948
|
+
trim_adjust = {
|
|
949
|
+
"default": "none",
|
|
950
|
+
"trimal": "trimal",
|
|
951
|
+
"trimai": "trimal",
|
|
952
|
+
"gblocks": "gblocks",
|
|
953
|
+
"gblock": "gblocks",
|
|
954
|
+
"none": "none",
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
if self.method.trim is None:
|
|
958
|
+
self.method.trim = "none"
|
|
959
|
+
|
|
960
|
+
if not (type(self.method.trim) is str):
|
|
961
|
+
list_error.append(f"trim method should be string")
|
|
962
|
+
else:
|
|
963
|
+
self.method.trim = trim_adjust[self.method.trim.lower()]
|
|
964
|
+
if not (self.method.trim in trim):
|
|
965
|
+
list_error.append(
|
|
966
|
+
f"trim method should be one of {str(trim_adjust.keys())}"
|
|
967
|
+
)
|
|
968
|
+
|
|
969
|
+
# model
|
|
970
|
+
# Check if search method is one of default, none, modeltest-ng, iqtree
|
|
971
|
+
# Adjust misspellings
|
|
972
|
+
# If given value is default, change it to none
|
|
973
|
+
# If does not met to any of above, raise Exception
|
|
974
|
+
modeltest = ["none", "modeltest-ng", "iqtree"]
|
|
975
|
+
modeltest_adjust = {
|
|
976
|
+
"default": "none",
|
|
977
|
+
"modeltest": "modeltest-ng",
|
|
978
|
+
"modeltestng": "modeltest-ng",
|
|
979
|
+
"modeltest-ng": "modeltest-ng",
|
|
980
|
+
"jmodeltest": "modeltest-ng",
|
|
981
|
+
"iqtree": "iqtree",
|
|
982
|
+
"modelfinder": "iqtree",
|
|
983
|
+
"none": "none",
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
if self.method.modeltest is None:
|
|
987
|
+
self.method.modeltest = "none"
|
|
988
|
+
|
|
989
|
+
if not (type(self.method.modeltest) is str):
|
|
990
|
+
list_error.append(f"modeltest method should be string")
|
|
991
|
+
|
|
992
|
+
else:
|
|
993
|
+
if self.method.modeltest.lower() == "jmodeltest":
|
|
994
|
+
list_warning.append(
|
|
995
|
+
f"option jmodeltest will be substituted to modeltest-ng"
|
|
996
|
+
)
|
|
997
|
+
self.method.modeltest = modeltest_adjust[self.method.modeltest.lower()]
|
|
998
|
+
if not (self.method.modeltest in modeltest):
|
|
999
|
+
list_error.append(f"modeltest method should be one of {str(modeltest)}")
|
|
1000
|
+
if self.method.modeltest == "modeltest-ng" and sys.platform == "win32":
|
|
1001
|
+
list_error.append(
|
|
1002
|
+
f"Modeltest-ng is currently not available in windows platform. Please select other modeltest methods or use linux platform"
|
|
1003
|
+
)
|
|
1004
|
+
|
|
1005
|
+
# tree
|
|
1006
|
+
# Check if search method is one of default, fasttree, raxml, iqtree
|
|
1007
|
+
# Adjust misspellings
|
|
1008
|
+
# If given value is default, change it to fasttree
|
|
1009
|
+
# If does not met to any of above, raise Exception
|
|
1010
|
+
tree = ["fasttree", "iqtree", "raxml"]
|
|
1011
|
+
tree_adjust = {
|
|
1012
|
+
"default": "fasttree",
|
|
1013
|
+
"fasttree": "fasttree",
|
|
1014
|
+
"iqtree": "iqtree",
|
|
1015
|
+
"raxml": "raxml",
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
if not (type(self.method.tree) is str):
|
|
1019
|
+
list_error.append(f"tree method should be string")
|
|
1020
|
+
else:
|
|
1021
|
+
self.method.tree = tree_adjust[self.method.tree.lower()]
|
|
1022
|
+
if not (self.method.tree in tree):
|
|
1023
|
+
list_error.append(f"tree method should be one of {str(tree)}")
|
|
1024
|
+
|
|
1025
|
+
# bscutoff
|
|
1026
|
+
# Check if bootstrap cutoff is in optimal range 0~
|
|
1027
|
+
# If lower than 0, set to 0
|
|
1028
|
+
# If upper than 100, warn that bootstrap will not be shown
|
|
1029
|
+
# If between 0 and 1, multiply 100 and warn
|
|
1030
|
+
if not (type(self.visualize.bscutoff) is int):
|
|
1031
|
+
try:
|
|
1032
|
+
if self.visualize.bscutoff > 0 and self.visualize.bscutoff < 1:
|
|
1033
|
+
list_warning.append(
|
|
1034
|
+
f"bscutoff should be in integer range, but given one seems to between 0 and 1. Automatically multiplying 100"
|
|
1035
|
+
)
|
|
1036
|
+
self.visualize.bscutoff = int(self.visualize.bscutoff * 100)
|
|
1037
|
+
# If failed solving
|
|
1038
|
+
if self.visualize.bscutoff > 0 and self.visualize.bscutoff < 1:
|
|
1039
|
+
list_error.append(f"Failed to solve bscutoff range")
|
|
1040
|
+
|
|
1041
|
+
else:
|
|
1042
|
+
self.visualize.bscutoff = int(self.visualize.bscutoff)
|
|
1043
|
+
|
|
1044
|
+
if self.visualize.bscutoff < 0:
|
|
1045
|
+
self.visualize.bscutoff = 0
|
|
1046
|
+
if self.visualize.bscutoff > 100:
|
|
1047
|
+
list_warning.append(
|
|
1048
|
+
f"bscutoff is over 100, all bootstrap will not seen"
|
|
1049
|
+
)
|
|
1050
|
+
|
|
1051
|
+
except:
|
|
1052
|
+
list_error.append(f"--bscutoff should be integer")
|
|
1053
|
+
|
|
1054
|
+
# highlight
|
|
1055
|
+
# highlight should be availabe svg colors or unicode
|
|
1056
|
+
if not (type(self.visualize.highlight) is str):
|
|
1057
|
+
list_error.append(f"--highlight should be string")
|
|
1058
|
+
else:
|
|
1059
|
+
if not (isvalidcolor(self.visualize.highlight)):
|
|
1060
|
+
list_error.append(
|
|
1061
|
+
f"in --highlight, color {color} does not seems to be valid svg color nor hex code"
|
|
1062
|
+
)
|
|
1063
|
+
else:
|
|
1064
|
+
self.visualize.highlight = self.visualize.highlight.lower()
|
|
1065
|
+
|
|
1066
|
+
# heightmultiplier
|
|
1067
|
+
# heightmultiplier should be positive float
|
|
1068
|
+
try:
|
|
1069
|
+
self.visualize.heightmultiplier = float(self.visualize.heightmultiplier)
|
|
1070
|
+
if self.visualize.heightmultiplier <= 0:
|
|
1071
|
+
list_warning.append(
|
|
1072
|
+
"--heightmultiplier should be positive, setting to default value, 6"
|
|
1073
|
+
)
|
|
1074
|
+
self.visualize.heightmultiplier = 6
|
|
1075
|
+
except:
|
|
1076
|
+
list_error.append(
|
|
1077
|
+
"--heightmultiplier should be positive floating point number"
|
|
1078
|
+
)
|
|
1079
|
+
|
|
1080
|
+
# maxwordlength
|
|
1081
|
+
# maxwordlength should be positive int
|
|
1082
|
+
try:
|
|
1083
|
+
self.visualize.maxwordlength = int(self.visualize.maxwordlength)
|
|
1084
|
+
if self.visualize.maxwordlength <= 0:
|
|
1085
|
+
list_warning.append(
|
|
1086
|
+
"--maxwordlength should be positive int, setting to default value, 48"
|
|
1087
|
+
)
|
|
1088
|
+
self.visualize.maxwordlength = 48
|
|
1089
|
+
except:
|
|
1090
|
+
list_error.append(
|
|
1091
|
+
"--maxwordlength should be positive floating point number"
|
|
1092
|
+
)
|
|
1093
|
+
|
|
1094
|
+
# backgroundcolor
|
|
1095
|
+
# backgroundcolor should be list of colors
|
|
1096
|
+
flag_backgroundcolor = 0
|
|
1097
|
+
if not (type(self.visualize.backgroundcolor) is list):
|
|
1098
|
+
list_error.append(f"--backgroundcolor should be list")
|
|
1099
|
+
flag_backgroundcolor += 1
|
|
1100
|
+
elif len(self.visualize.backgroundcolor) < 1:
|
|
1101
|
+
list_error.append(
|
|
1102
|
+
f"At least one color should be designated for --backgroundcolor"
|
|
1103
|
+
)
|
|
1104
|
+
flag_backgroundcolor += 1
|
|
1105
|
+
else:
|
|
1106
|
+
for color in self.visualize.backgroundcolor:
|
|
1107
|
+
if not isvalidcolor(color):
|
|
1108
|
+
list_error.append(
|
|
1109
|
+
f"color {color} does not seems to be valid svg color nor hex code"
|
|
1110
|
+
)
|
|
1111
|
+
flag_backgroundcolor += 1
|
|
1112
|
+
if flag_backgroundcolor == 0:
|
|
1113
|
+
self.visualize.backgroundcolor = [
|
|
1114
|
+
x.lower() for x in self.visualize.backgroundcolor
|
|
1115
|
+
]
|
|
1116
|
+
|
|
1117
|
+
# outgroupcolor
|
|
1118
|
+
# outgroupcolor should be availabe svg colors or unicode
|
|
1119
|
+
if not (type(self.visualize.outgroupcolor) is str):
|
|
1120
|
+
list_error.append(f"--outgroupcolor should be string")
|
|
1121
|
+
else:
|
|
1122
|
+
if not (isvalidcolor(self.visualize.outgroupcolor)):
|
|
1123
|
+
list_error.append(
|
|
1124
|
+
f"in --outgroupcolor, color {color} does not seems to be valid svg color nor hex code"
|
|
1125
|
+
)
|
|
1126
|
+
else:
|
|
1127
|
+
self.visualize.outgroupcolor = self.visualize.outgroupcolor.lower()
|
|
1128
|
+
|
|
1129
|
+
# ftype
|
|
1130
|
+
if not (type(self.visualize.ftype) is str):
|
|
1131
|
+
list_error.append(f"--ftype should be valid font name (string)")
|
|
1132
|
+
else:
|
|
1133
|
+
# Fix this when enough data has been collected
|
|
1134
|
+
pass
|
|
1135
|
+
|
|
1136
|
+
# fsize
|
|
1137
|
+
try:
|
|
1138
|
+
float(self.visualize.fsize)
|
|
1139
|
+
if self.visualize.fsize < 0:
|
|
1140
|
+
list_warning.append(
|
|
1141
|
+
f"--fsize should be positive float. Setting to default, 10"
|
|
1142
|
+
)
|
|
1143
|
+
self.visualize.fsize = 10
|
|
1144
|
+
except:
|
|
1145
|
+
list_error.append(f"--fsize should be positive float")
|
|
1146
|
+
|
|
1147
|
+
# fsize_bootstrap
|
|
1148
|
+
try:
|
|
1149
|
+
float(self.visualize.fsize_bootstrap)
|
|
1150
|
+
if self.visualize.fsize_bootstrap < 0:
|
|
1151
|
+
list_warning.append(
|
|
1152
|
+
f"--fsize_bootstrap should be positive float. Setting to default, 10"
|
|
1153
|
+
)
|
|
1154
|
+
self.visualize.fsize_bootstrap = 9
|
|
1155
|
+
except:
|
|
1156
|
+
list_error.append(f"--fsize_bootstrap should be positive float")
|
|
1157
|
+
|
|
1158
|
+
# verbose
|
|
1159
|
+
# If not 0,1,2,3 raise error with warning
|
|
1160
|
+
# 0: quiet, 1: info, 2: warning, 3: debug, default : 2
|
|
1161
|
+
try:
|
|
1162
|
+
self.verbose = int(self.verbose)
|
|
1163
|
+
if not self.verbose in (0, 1, 2, 3):
|
|
1164
|
+
list_error.append(
|
|
1165
|
+
f"verbose should be one of 0,1,2,3 - 0: only error, 1: warning, 2: info, 3: debug"
|
|
1166
|
+
)
|
|
1167
|
+
except:
|
|
1168
|
+
list_error.append(
|
|
1169
|
+
f"verbose should be one of 0,1,2,3 - 0: only error, 1: warning, 2: info, 3: debug"
|
|
1170
|
+
)
|
|
1171
|
+
|
|
1172
|
+
# maxoutgroup
|
|
1173
|
+
# Check if maxoutgroup is in optimal range 0~
|
|
1174
|
+
# if lower than 1, change into 1 and warn
|
|
1175
|
+
try:
|
|
1176
|
+
self.maxoutgroup = int(self.maxoutgroup)
|
|
1177
|
+
if self.maxoutgroup < 1:
|
|
1178
|
+
list_warning.append(f"invalid maxoutgroup, automatically selecting 1")
|
|
1179
|
+
except:
|
|
1180
|
+
list_warning.append(f"invalid maxoutgroup, automatically selecting 1")
|
|
1181
|
+
self.maxoutgroup = 1
|
|
1182
|
+
|
|
1183
|
+
# collapsedistcutoff
|
|
1184
|
+
# Check if collapse distance cutoff is in optimal range 0~
|
|
1185
|
+
# if lower than 0, change into 0 and warn
|
|
1186
|
+
try:
|
|
1187
|
+
self.collapsedistcutoff = float(self.collapsedistcutoff)
|
|
1188
|
+
except:
|
|
1189
|
+
list_warning.append(f"invalid collapsedistcutoff, change into 0")
|
|
1190
|
+
self.collapsedistcutoff = 0
|
|
1191
|
+
|
|
1192
|
+
# collapsebscutoff
|
|
1193
|
+
# Check if collapse bootstrap cutoff is in optimal range 0~
|
|
1194
|
+
# If higher than 101, change into 100 and warn
|
|
1195
|
+
# If lower than 0, change into 0 and warn
|
|
1196
|
+
if not (type(self.collapsebscutoff) is int):
|
|
1197
|
+
try:
|
|
1198
|
+
if self.collapsebscutoff > 0 and self.collapsebscutoff < 1:
|
|
1199
|
+
list_warning.append(
|
|
1200
|
+
f"collapsebscutoff should be in integer range, but given one seems to between 0 and 1. Automatically multiplying 100"
|
|
1201
|
+
)
|
|
1202
|
+
self.collapsebscutoff = int(self.collapsebscutoff * 100)
|
|
1203
|
+
# If failed solving
|
|
1204
|
+
if self.collapsebscutoff > 0 and self.collapsebscutoff < 1:
|
|
1205
|
+
list_error.append(f"Failed to solve collapse bscutoff range")
|
|
1206
|
+
|
|
1207
|
+
else:
|
|
1208
|
+
self.collapsebscutoff = int(self.collapsebscutoff)
|
|
1209
|
+
|
|
1210
|
+
if self.collapsebscutoff < 0:
|
|
1211
|
+
self.collapsebscutoff = 0
|
|
1212
|
+
if self.collapsebscutoff > 100:
|
|
1213
|
+
list_warning.append(
|
|
1214
|
+
f"collapsebscutoff is over 100, all bootstrap will not seen"
|
|
1215
|
+
)
|
|
1216
|
+
|
|
1217
|
+
except:
|
|
1218
|
+
list_error.append(f"bscutoff should be integer")
|
|
1219
|
+
|
|
1220
|
+
# bootstrap
|
|
1221
|
+
# bootstrap number should be int
|
|
1222
|
+
# If IQTREE selected and bootstrap number under 1000, change to 1000
|
|
1223
|
+
if self.method.tree == "fasttree":
|
|
1224
|
+
list_warning.append(
|
|
1225
|
+
f"Fasttree does not supports bootstrap. --bootstrap will be ignored"
|
|
1226
|
+
)
|
|
1227
|
+
self.bootstrap = None
|
|
1228
|
+
else:
|
|
1229
|
+
try:
|
|
1230
|
+
self.bootstrap = int(self.bootstrap)
|
|
1231
|
+
if self.method.tree == "iqtree" and self.bootstrap < 1000:
|
|
1232
|
+
list_warning.append(
|
|
1233
|
+
"iqtree requires at least 1000 bootstrap. adjusting to 1000"
|
|
1234
|
+
)
|
|
1235
|
+
self.bootstrap = 1000
|
|
1236
|
+
elif self.method.tree == "raxml" and self.bootstrap < 0:
|
|
1237
|
+
list_warning.append(
|
|
1238
|
+
"bootstrap should not be negative. adjusting to 1"
|
|
1239
|
+
)
|
|
1240
|
+
self.bootstrap = 1
|
|
1241
|
+
|
|
1242
|
+
except:
|
|
1243
|
+
list_error.append(
|
|
1244
|
+
f"bootstrap should be integer when iqtree or raxml are selected"
|
|
1245
|
+
)
|
|
1246
|
+
|
|
1247
|
+
# solveflat
|
|
1248
|
+
# If solveflat is not None, give True, else, give False
|
|
1249
|
+
if self.solveflat is False or self.solveflat is None:
|
|
1250
|
+
self.solveflat = False
|
|
1251
|
+
else:
|
|
1252
|
+
self.solveflat = True
|
|
1253
|
+
|
|
1254
|
+
# regex
|
|
1255
|
+
# Regex list for queries
|
|
1256
|
+
# Validate if regex are valid regex
|
|
1257
|
+
if self.regex is None:
|
|
1258
|
+
pass
|
|
1259
|
+
elif not (type(self.regex)) is list:
|
|
1260
|
+
list_error.append("regex should be given in list of pattern")
|
|
1261
|
+
else:
|
|
1262
|
+
for regex in self.regex:
|
|
1263
|
+
try:
|
|
1264
|
+
re.compile(regex)
|
|
1265
|
+
except:
|
|
1266
|
+
list_error.append(f"regex {regex} is not a valid python regex")
|
|
1267
|
+
|
|
1268
|
+
# cluster-evalue
|
|
1269
|
+
# E-value cutoff for clustering - should be positive
|
|
1270
|
+
try:
|
|
1271
|
+
self.cluster.evalue = float(self.cluster.evalue)
|
|
1272
|
+
if self.cluster.evalue < 0:
|
|
1273
|
+
list_warning.append("evalue should be positive, setting to 1")
|
|
1274
|
+
self.cluster.evalue = 1
|
|
1275
|
+
except:
|
|
1276
|
+
list_error.append("evalue should be positive floating point number")
|
|
1277
|
+
|
|
1278
|
+
# cluster-wordsize
|
|
1279
|
+
# Wordsize option for clustering - should be int and not less than 7
|
|
1280
|
+
try:
|
|
1281
|
+
self.cluster.wordsize = int(self.cluster.wordsize)
|
|
1282
|
+
if self.cluster.wordsize < 7:
|
|
1283
|
+
list_warning.append(
|
|
1284
|
+
"wordsize should be int not less than 7. Changing to 7"
|
|
1285
|
+
)
|
|
1286
|
+
self.cluster.wordsize = 7
|
|
1287
|
+
except:
|
|
1288
|
+
list_error.append("wordsize should be int not less than 7. Changing to 7")
|
|
1289
|
+
|
|
1290
|
+
# cluster-outgroupoffset
|
|
1291
|
+
# outgroupoffset for clustering - should be 0 or positive
|
|
1292
|
+
try:
|
|
1293
|
+
self.cluster.outgroupoffset = int(self.cluster.outgroupoffset)
|
|
1294
|
+
if self.cluster.outgroupoffset < 0:
|
|
1295
|
+
list_warning.append(
|
|
1296
|
+
"outgroupoffset should be 0 or positive, setting to 0"
|
|
1297
|
+
)
|
|
1298
|
+
self.cluster.outgroupoffset = 0
|
|
1299
|
+
except:
|
|
1300
|
+
list_error.append("outgroupoffset should be 0 or positive integer")
|
|
1301
|
+
|
|
1302
|
+
# mafft-algorithm
|
|
1303
|
+
# mafft-algorithm - auto, l-ins-i
|
|
1304
|
+
# mafft algorithm commands should be revised
|
|
1305
|
+
if self.method.alignment == "mafft":
|
|
1306
|
+
try:
|
|
1307
|
+
self.mafft.algorithm = str(self.mafft.algorithm)
|
|
1308
|
+
if not (
|
|
1309
|
+
self.mafft.algorithm.lower()
|
|
1310
|
+
in (
|
|
1311
|
+
"auto",
|
|
1312
|
+
"l-ins-i",
|
|
1313
|
+
"linsi",
|
|
1314
|
+
"localpair",
|
|
1315
|
+
"g-ins-i",
|
|
1316
|
+
"ginsi",
|
|
1317
|
+
"globalpair",
|
|
1318
|
+
)
|
|
1319
|
+
):
|
|
1320
|
+
list_error.append(
|
|
1321
|
+
f"Invalid mafft algorithm {self.mafft.algorithm}. Currently available algorithms are auto and l-ins-i"
|
|
1322
|
+
)
|
|
1323
|
+
elif self.mafft.algorithm.lower() in ("l-ins-i", "linsi", "localpair"):
|
|
1324
|
+
self.mafft.algorithm = "localpair"
|
|
1325
|
+
elif self.mafft.algorithm.lower() in ("g-ins-i", "ginsi", "globalpair"):
|
|
1326
|
+
self.mafft.algorithm = "globalpair"
|
|
1327
|
+
|
|
1328
|
+
except:
|
|
1329
|
+
list_error.append(
|
|
1330
|
+
f"Invalid mafft algorithm {self.mafft.algorithm}. Currently available algorithms are auto and l-ins-i"
|
|
1331
|
+
)
|
|
1332
|
+
|
|
1333
|
+
# mafft-op
|
|
1334
|
+
# mafft gap opening penalty should be 0 or positive
|
|
1335
|
+
if self.method.alignment == "mafft":
|
|
1336
|
+
try:
|
|
1337
|
+
self.mafft.op = float(self.mafft.op)
|
|
1338
|
+
if self.mafft.op < 0:
|
|
1339
|
+
list_warning.append(
|
|
1340
|
+
"mafft op value should be positive, setting to 1.2"
|
|
1341
|
+
)
|
|
1342
|
+
self.mafft.op = 1.2
|
|
1343
|
+
except:
|
|
1344
|
+
list_error.append("mafft op value should be 0 or positive")
|
|
1345
|
+
|
|
1346
|
+
# mafft-ep
|
|
1347
|
+
# mafft gap extension penalty should be 0 or positive
|
|
1348
|
+
if self.method.alignment == "mafft":
|
|
1349
|
+
try:
|
|
1350
|
+
self.mafft.ep = float(self.mafft.ep)
|
|
1351
|
+
if self.mafft.ep < 0:
|
|
1352
|
+
list_warning.append(
|
|
1353
|
+
"mafft ep value should be positive, setting to 1.2"
|
|
1354
|
+
)
|
|
1355
|
+
self.mafft.ep = 0.1
|
|
1356
|
+
except:
|
|
1357
|
+
list_error.append("mafft ep value should be 0 or positive")
|
|
1358
|
+
|
|
1359
|
+
# trimal-algorithm
|
|
1360
|
+
# trimal algorithm, should be either gt
|
|
1361
|
+
# if auto, set gt
|
|
1362
|
+
if self.method.trim.lower() == "trimal":
|
|
1363
|
+
try:
|
|
1364
|
+
self.trimal.algorithm = str(self.trimal.algorithm)
|
|
1365
|
+
if not (self.trimal.algorithm.lower() in ("auto", "gt")):
|
|
1366
|
+
list_warning(
|
|
1367
|
+
f"Invalid trimal algorithm {self.trimal.algorithm}. Chaniging to gt"
|
|
1368
|
+
)
|
|
1369
|
+
self.trimal.algorithm = "gt"
|
|
1370
|
+
except:
|
|
1371
|
+
list_error.append(
|
|
1372
|
+
f"Invalid trimal algorithm {self.trimal.algorithm}. Currently avilable algorithms are auto and gt"
|
|
1373
|
+
)
|
|
1374
|
+
|
|
1375
|
+
# trimal-gt
|
|
1376
|
+
# trimal gt value, should be between 0 and 1
|
|
1377
|
+
# If trimming method is not trimal or trimal-algorithm is not 0, warn
|
|
1378
|
+
# Change to default value
|
|
1379
|
+
if self.method.trim.lower() == "trimal":
|
|
1380
|
+
try:
|
|
1381
|
+
self.trimal.gt = float(self.trimal.gt)
|
|
1382
|
+
if self.trimal.gt < 0 and self.trimal.gt >= 1:
|
|
1383
|
+
list_warning.append(
|
|
1384
|
+
f"trimal gt value should be between 1 and 0, setting to 0.2"
|
|
1385
|
+
)
|
|
1386
|
+
self.trimal.gt = 0.2
|
|
1387
|
+
except:
|
|
1388
|
+
list_error.append(
|
|
1389
|
+
f"Invalid trimal gt value {self.trimal.gt}. gt should be between 1 and 0"
|
|
1390
|
+
)
|
|
1391
|
+
|
|
1392
|
+
# noavx
|
|
1393
|
+
# default : False
|
|
1394
|
+
# if used, set True
|
|
1395
|
+
# if avx is not available command, set True
|
|
1396
|
+
# Negative boolean and save as avx
|
|
1397
|
+
if check_avx() is False and self.avx is True:
|
|
1398
|
+
list_warning.append(f"AVX is not available. Changing --noavx to True")
|
|
1399
|
+
self.avx = False
|
|
1400
|
+
|
|
1401
|
+
# criterion
|
|
1402
|
+
# default : BIC
|
|
1403
|
+
# Should be one of AIC, AICc, BIC
|
|
1404
|
+
try:
|
|
1405
|
+
self.criterion = str(self.criterion)
|
|
1406
|
+
if not (self.criterion.lower() in ("aic", "aicc", "bic")):
|
|
1407
|
+
list_error.append(
|
|
1408
|
+
"Modeltest criterion should be one of AIC, AICc and BIC"
|
|
1409
|
+
)
|
|
1410
|
+
else:
|
|
1411
|
+
# For prevent capital errors
|
|
1412
|
+
if self.criterion.lower() == "aic":
|
|
1413
|
+
self.criterion = "AIC"
|
|
1414
|
+
elif self.criterion.lower() == "aicc":
|
|
1415
|
+
self.criterion = "AICc"
|
|
1416
|
+
elif self.criterion.lower() == "bic":
|
|
1417
|
+
self.criterion = "BIC"
|
|
1418
|
+
else:
|
|
1419
|
+
list_error.append(
|
|
1420
|
+
f"Somewhat error in parsing criterion, {self.criterion}"
|
|
1421
|
+
)
|
|
1422
|
+
|
|
1423
|
+
except:
|
|
1424
|
+
list_error.append("Modeltest criterion should be one of AIC, AICc and BIC")
|
|
1425
|
+
|
|
1426
|
+
# cachedb
|
|
1427
|
+
# If cachedb is not None, give True, else, give False
|
|
1428
|
+
if self.cachedb is False or self.cachedb is None:
|
|
1429
|
+
self.cachedb = False
|
|
1430
|
+
else:
|
|
1431
|
+
self.cachedb = True
|
|
1432
|
+
|
|
1433
|
+
# usecache
|
|
1434
|
+
# If usecache is not None, give True, else, give False
|
|
1435
|
+
if self.usecache is False or self.usecache is None:
|
|
1436
|
+
self.usecache = False
|
|
1437
|
+
else:
|
|
1438
|
+
self.usecache = True
|
|
1439
|
+
|
|
1440
|
+
# tableformat
|
|
1441
|
+
# should be either [csv, xlsx, parquet, feather]
|
|
1442
|
+
# if ftr, change it to feather
|
|
1443
|
+
# if excel, change it to xlsx
|
|
1444
|
+
try:
|
|
1445
|
+
self.tableformat = str(self.tableformat)
|
|
1446
|
+
if not (
|
|
1447
|
+
self.tableformat.lower()
|
|
1448
|
+
in ("csv", "tsv", "xlsx", "parquet", "ftr", "feather")
|
|
1449
|
+
):
|
|
1450
|
+
list_error.append(
|
|
1451
|
+
"tableformat should be one of csv, tsv, xlsx, parquet, ftr, or feather"
|
|
1452
|
+
)
|
|
1453
|
+
|
|
1454
|
+
except:
|
|
1455
|
+
list_error.append(
|
|
1456
|
+
"tableformat should be one of csv, tsv, xlsx, parquet, ftr, or feather"
|
|
1457
|
+
)
|
|
1458
|
+
|
|
1459
|
+
# nosearchresult
|
|
1460
|
+
# If nosearchresult is not None, give True, else, give False
|
|
1461
|
+
if self.nosearchresult is True:
|
|
1462
|
+
self.nosearchresult = True
|
|
1463
|
+
else:
|
|
1464
|
+
self.nosearchresult = False
|
|
1465
|
+
|
|
1466
|
+
# Printing logs while parsing validate options
|
|
1467
|
+
# Written in print functions, because logging can be loaded after option parsing
|
|
1468
|
+
print("--INFO--")
|
|
1469
|
+
if len(list_info) > 0:
|
|
1470
|
+
for info in list_info:
|
|
1471
|
+
print(f"[INFO] {info}")
|
|
1472
|
+
else:
|
|
1473
|
+
print(f"[INFO] No information to declare during input validation")
|
|
1474
|
+
|
|
1475
|
+
print("\n")
|
|
1476
|
+
print("--WARNING--")
|
|
1477
|
+
if len(list_warning) > 0:
|
|
1478
|
+
for warning in list_warning:
|
|
1479
|
+
print(f"[WARNING] {warning}")
|
|
1480
|
+
else:
|
|
1481
|
+
print(f"[INFO] No warnings to declare during input validation")
|
|
1482
|
+
|
|
1483
|
+
print("\n")
|
|
1484
|
+
print("--ERROR--")
|
|
1485
|
+
if len(list_error) > 0:
|
|
1486
|
+
for error in list_error:
|
|
1487
|
+
print(f"[ERROR] {error}")
|
|
1488
|
+
else:
|
|
1489
|
+
print(f"[INFO] No errors to declare during input validation")
|
|
1490
|
+
|
|
1491
|
+
print("\n\n")
|
|
1492
|
+
|
|
1493
|
+
if len(list_error) > 0:
|
|
1494
|
+
raise Exception
|
|
1495
|
+
|
|
1496
|
+
# Returning option parsing logs
|
|
1497
|
+
return list_info, list_warning, list_error
|
|
1498
|
+
|
|
1499
|
+
|
|
1500
|
+
### Main function in validate_option.py
|
|
1501
|
+
def initialize_option(parser, path_run):
|
|
1502
|
+
#### Before start
|
|
1503
|
+
# Backup original parser
|
|
1504
|
+
ori_parser = copy.deepcopy(parser)
|
|
1505
|
+
|
|
1506
|
+
### Initialize option
|
|
1507
|
+
opt = Option()
|
|
1508
|
+
|
|
1509
|
+
### test
|
|
1510
|
+
# 1. Check if test name is valid (Avaliable list : Penicillium)
|
|
1511
|
+
# 2. Change preset to test
|
|
1512
|
+
|
|
1513
|
+
path_test = f"{os.path.dirname(__file__)}/../test_dataset"
|
|
1514
|
+
path_preset = f"{os.path.dirname(__file__)}/../preset"
|
|
1515
|
+
|
|
1516
|
+
overwrite_preset = None
|
|
1517
|
+
# *1 - if test option selected
|
|
1518
|
+
if not (parser.test is None):
|
|
1519
|
+
# If preset should be overwrited, save it
|
|
1520
|
+
if not (parser.preset is None):
|
|
1521
|
+
overwrite_preset = copy.deepcopy(parser.preset)
|
|
1522
|
+
|
|
1523
|
+
# *1 - if test value is valid dataset
|
|
1524
|
+
if parser.test.lower() in os.listdir(path_test):
|
|
1525
|
+
if os.path.exists(f"{path_test}/{parser.test.lower()}/preset.yaml"):
|
|
1526
|
+
parser.preset = f"{path_test}/{parser.test.lower()}/preset.yaml"
|
|
1527
|
+
print(f"test dataset {parser.preset} selected")
|
|
1528
|
+
else:
|
|
1529
|
+
print("Something wrong with test dataset option")
|
|
1530
|
+
raise Exception
|
|
1531
|
+
|
|
1532
|
+
# Set runname to current time
|
|
1533
|
+
now = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
|
|
1534
|
+
|
|
1535
|
+
# Give default locations if no outdir and runname given
|
|
1536
|
+
if parser.outdir is None:
|
|
1537
|
+
opt.outdir = f"{path_run}"
|
|
1538
|
+
if parser.runname is None:
|
|
1539
|
+
f"{parser.test.lower()}_{now}"
|
|
1540
|
+
|
|
1541
|
+
opt.test = parser.test.lower()
|
|
1542
|
+
|
|
1543
|
+
else:
|
|
1544
|
+
print("Invalid test dataset. Please --test option")
|
|
1545
|
+
raise Exception
|
|
1546
|
+
|
|
1547
|
+
### preset
|
|
1548
|
+
# 1. Check if lower case is fast or accurate
|
|
1549
|
+
# 2. Else, check if preset is parsable YAML file
|
|
1550
|
+
# 3. If parsable json file, parse it and update parser
|
|
1551
|
+
if not (parser.preset is None):
|
|
1552
|
+
if str(parser.preset).lower() == "fast": # *1 - fast mode
|
|
1553
|
+
parser.preset = f"{path_preset}/fast.yaml" # - connect to fast.yaml
|
|
1554
|
+
print("Using fast preset as default option")
|
|
1555
|
+
opt.update_from_preset(parser.preset)
|
|
1556
|
+
elif str(parser.preset).lower() == "accurate": # *1 - accurate mode
|
|
1557
|
+
parser.preset = f"{path_preset}/accurate.yaml" # - connect to accurate.yaml
|
|
1558
|
+
print("Using accurate preset as default option")
|
|
1559
|
+
opt.update_from_preset(parser.preset)
|
|
1560
|
+
else:
|
|
1561
|
+
if os.path.exists(parser.preset):
|
|
1562
|
+
print(f"[DEBUG] {parser.preset}")
|
|
1563
|
+
opt.update_from_preset(parser.preset)
|
|
1564
|
+
else:
|
|
1565
|
+
print(f"Cannot find preset file : {parser.preset}")
|
|
1566
|
+
raise Exception
|
|
1567
|
+
|
|
1568
|
+
# Overwrite test preset if needed
|
|
1569
|
+
if not (overwrite_preset is None):
|
|
1570
|
+
if str(overwrite_preset).lower() == "fast": # *1 - fast mode
|
|
1571
|
+
overwrite_preset = f"{path_preset}/fast.yaml" # - connect to fast.yaml
|
|
1572
|
+
print("Using fast preset as default option")
|
|
1573
|
+
opt.update_from_preset(overwrite_preset)
|
|
1574
|
+
elif str(overwrite_preset).lower() == "accurate": # *1 - accurate mode
|
|
1575
|
+
overwrite_preset = (
|
|
1576
|
+
f"{path_preset}/accurate.yaml" # - connect to accurate.yaml
|
|
1577
|
+
)
|
|
1578
|
+
print("Using accurate preset as default option")
|
|
1579
|
+
opt.update_from_preset(overwrite_preset)
|
|
1580
|
+
else:
|
|
1581
|
+
if os.path.exists(overwrite_preset):
|
|
1582
|
+
print(f"[DEBUG] {overwrite_preset}")
|
|
1583
|
+
opt.update_from_preset(overwrite_preset)
|
|
1584
|
+
else:
|
|
1585
|
+
print(f"Cannot find preset file : {overwrite_preset}")
|
|
1586
|
+
raise Exception
|
|
1587
|
+
|
|
1588
|
+
### Then, update other options in parser
|
|
1589
|
+
opt.update_from_parser(ori_parser)
|
|
1590
|
+
|
|
1591
|
+
### validate
|
|
1592
|
+
list_info, list_warning, list_error = opt.validate()
|
|
1593
|
+
|
|
1594
|
+
### stdout input options
|
|
1595
|
+
# print("[OPTIONS INPUT]")
|
|
1596
|
+
|
|
1597
|
+
## Print and log output options
|
|
1598
|
+
for attr, value in opt.__dict__.items():
|
|
1599
|
+
if isinstance(value, (str, float, bool, int, list, type(None))):
|
|
1600
|
+
list_info.append(f"Option {attr} : {value}")
|
|
1601
|
+
# print(f"Option {attr} : {value}")
|
|
1602
|
+
else:
|
|
1603
|
+
for attr_, value_ in value.__dict__.items():
|
|
1604
|
+
list_info.append(f"Option {attr}-{attr_}: {value_}")
|
|
1605
|
+
# print(f"Option {attr}-{attr_}: {value_}")
|
|
1606
|
+
|
|
1607
|
+
print("------------------------------------")
|
|
1608
|
+
|
|
1609
|
+
return opt, list_info, list_warning, list_error
|