comparison toolfactory/galaxyxml/tool/parameters/__init__.py @ 92:6ce360759c28 draft

Uploaded
author fubar
date Thu, 19 Nov 2020 23:59:50 +0000
parents
children
comparison
equal deleted inserted replaced
91:7176af503cdd 92:6ce360759c28
1 from builtins import object
2 from builtins import str
3
4 from galaxyxml import Util
5
6 from lxml import etree
7
8
9
10 class XMLParam(object):
11 name = "node"
12
13 def __init__(self, *args, **kwargs):
14 # http://stackoverflow.com/a/12118700
15 self.children = []
16 kwargs = {k: v for k, v in list(kwargs.items()) if v is not None}
17 kwargs = Util.coerce(kwargs, kill_lists=True)
18 kwargs = Util.clean_kwargs(kwargs, final=True)
19 self.node = etree.Element(self.name, **kwargs)
20
21 def append(self, sub_node):
22 if self.acceptable_child(sub_node):
23 # If one of ours, they aren't etree nodes, they're custom objects
24 if issubclass(type(sub_node), XMLParam):
25 self.node.append(sub_node.node)
26 self.children.append(sub_node)
27 else:
28 raise Exception(
29 "Child was unacceptable to parent (%s is not appropriate for %s)" % (type(self), type(sub_node))
30 )
31 else:
32 raise Exception(
33 "Child was unacceptable to parent (%s is not appropriate for %s)" % (type(self), type(sub_node))
34 )
35
36 def validate(self):
37 # Very few need validation, but some nodes we may want to have
38 # validation routines on. Should only be called when DONE.
39 for child in self.children:
40 # If any child fails to validate return false.
41 if not child.validate():
42 return False
43 return True
44
45 def cli(self):
46 lines = []
47 for child in self.children:
48 lines.append(child.command_line())
49 # lines += child.command_line()
50 return "\n".join(lines)
51
52 def command_line(self):
53 return None
54
55
56 class RequestParamTranslation(XMLParam):
57 name = "request_param_translation"
58
59 def __init__(self, **kwargs):
60 self.node = etree.Element(self.name)
61
62 def acceptable_child(self, child):
63 return isinstance(child, RequestParamTranslation)
64
65
66 class RequestParam(XMLParam):
67 name = "request_param"
68
69 def __init__(self, galaxy_name, remote_name, missing, **kwargs):
70 # TODO: bulk copy locals into self.attr?
71 self.galaxy_name = galaxy_name
72 # http://stackoverflow.com/a/1408860
73 params = Util.clean_kwargs(locals().copy())
74 super(RequestParam, self).__init__(**params)
75
76 def acceptable_child(self, child):
77 return isinstance(child, AppendParam) and self.galaxy_name == "URL"
78
79
80 class AppendParam(XMLParam):
81 name = "append_param"
82
83 def __init__(self, separator="&", first_separator="?", join="=", **kwargs):
84 params = Util.clean_kwargs(locals().copy())
85 super(AppendParam, self).__init__(**params)
86
87 def acceptable_child(self, child):
88 return isinstance(child, AppendParamValue)
89
90
91 class AppendParamValue(XMLParam):
92 name = "value"
93
94 def __init__(self, name="_export", missing="1", **kwargs):
95 params = Util.clean_kwargs(locals().copy())
96 super(AppendParamValue, self).__init__(**params)
97
98 def acceptable_child(self, child):
99 return False
100
101
102 class EdamOperations(XMLParam):
103 name = "edam_operations"
104
105 def acceptable_child(self, child):
106 return issubclass(type(child), EdamOperation)
107
108 def has_operation(self, edam_operation):
109 """
110 Check the presence of a given edam_operation.
111
112 :type edam_operation: STRING
113 """
114 for operation in self.children:
115 if operation.node.text == edam_operation:
116 return True
117 return False
118
119
120 class EdamOperation(XMLParam):
121 name = "edam_operation"
122
123 def __init__(self, value):
124 super(EdamOperation, self).__init__()
125 self.node.text = str(value)
126
127
128 class EdamTopics(XMLParam):
129 name = "edam_topics"
130
131 def acceptable_child(self, child):
132 return issubclass(type(child), EdamTopic)
133
134 def has_topic(self, edam_topic):
135 """
136 Check the presence of a given edam_topic.
137
138 :type edam_topic: STRING
139 """
140 for topic in self.children:
141 if topic.node.text == edam_topic:
142 return True
143 return False
144
145
146 class EdamTopic(XMLParam):
147 name = "edam_topic"
148
149 def __init__(self, value):
150 super(EdamTopic, self).__init__()
151 self.node.text = str(value)
152
153
154 class Requirements(XMLParam):
155 name = "requirements"
156 # This bodes to be an issue -__-
157
158 def acceptable_child(self, child):
159 return issubclass(type(child), Requirement) or issubclass(type(child), Container)
160
161
162 class Requirement(XMLParam):
163 name = "requirement"
164
165 def __init__(self, type, value, version=None, **kwargs):
166 params = Util.clean_kwargs(locals().copy())
167 passed_kwargs = {}
168 passed_kwargs["version"] = params["version"]
169 passed_kwargs["type"] = params["type"]
170 super(Requirement, self).__init__(**passed_kwargs)
171 self.node.text = str(value)
172
173
174 class Container(XMLParam):
175 name = "container"
176
177 def __init__(self, type, value, **kwargs):
178 params = Util.clean_kwargs(locals().copy())
179 passed_kwargs = {}
180 passed_kwargs["type"] = params["type"]
181 super(Container, self).__init__(**passed_kwargs)
182 self.node.text = str(value)
183
184
185 class Configfiles(XMLParam):
186 name = "configfiles"
187
188 def acceptable_child(self, child):
189 return issubclass(type(child), Configfile) or issubclass(type(child), ConfigfileDefaultInputs)
190
191
192 class Configfile(XMLParam):
193 name = "configfile"
194
195 def __init__(self, name, text, **kwargs):
196 params = Util.clean_kwargs(locals().copy())
197 passed_kwargs = {}
198 passed_kwargs["name"] = params["name"]
199 super(Configfile, self).__init__(**passed_kwargs)
200 self.node.text = etree.CDATA(str(text))
201
202
203 class ConfigfileDefaultInputs(XMLParam):
204 name = "inputs"
205
206 def __init__(self, name, **kwargs):
207 params = Util.clean_kwargs(locals().copy())
208 passed_kwargs = {}
209 passed_kwargs["name"] = params["name"]
210 super(ConfigfileDefaultInputs, self).__init__(**passed_kwargs)
211
212
213 class Inputs(XMLParam):
214 name = "inputs"
215 # This bodes to be an issue -__-
216
217 def __init__(self, action=None, check_value=None, method=None, target=None, nginx_upload=None, **kwargs):
218 params = Util.clean_kwargs(locals().copy())
219 super(Inputs, self).__init__(**params)
220
221 def acceptable_child(self, child):
222 return issubclass(type(child), InputParameter)
223
224
225 class InputParameter(XMLParam):
226 def __init__(self, name, **kwargs):
227 # TODO: look at
228 self.mako_identifier = name
229 # We use kwargs instead of the usual locals(), so manually copy the
230 # name to kwargs
231 if name is not None:
232 kwargs["name"] = name
233
234 # Handle positional parameters
235 if "positional" in kwargs and kwargs["positional"]:
236 self.positional = True
237 else:
238 self.positional = False
239
240 if "num_dashes" in kwargs:
241 self.num_dashes = kwargs["num_dashes"]
242 del kwargs["num_dashes"]
243 else:
244 self.num_dashes = 0
245
246 self.space_between_arg = " "
247
248 # Not sure about this :(
249 # https://wiki.galaxyproject.org/Tools/BestPractices#Parameter_help
250 if "label" in kwargs:
251 # TODO: replace with positional attribute
252 if len(self.flag()) > 0:
253 if kwargs["label"] is None:
254 kwargs["label"] = "Author did not provide help for this parameter... "
255 if not self.positional:
256 kwargs["argument"] = self.flag()
257
258 super(InputParameter, self).__init__(**kwargs)
259
260 def command_line(self):
261 before = self.command_line_before()
262 cli = self.command_line_actual()
263 after = self.command_line_after()
264
265 complete = [x for x in (before, cli, after) if x is not None]
266 return "\n".join(complete)
267
268 def command_line_before(self):
269 try:
270 return self.command_line_before_override
271 except Exception:
272 return None
273
274 def command_line_after(self):
275 try:
276 return self.command_line_after_override
277 except Exception:
278 return None
279
280 def command_line_actual(self):
281 try:
282 return self.command_line_override
283 except Exception:
284 if self.positional:
285 return self.mako_name()
286 else:
287 return "%s%s%s" % (self.flag(), self.space_between_arg, self.mako_name())
288
289 def mako_name(self):
290 # TODO: enhance logic to check up parents for things like
291 # repeat>condotion>param
292 return "$" + self.mako_identifier
293
294 def flag(self):
295 flag = "-" * self.num_dashes
296 return flag + self.mako_identifier
297
298
299 class Section(InputParameter):
300 name = "section"
301
302 def __init__(self, name, title, expanded=None, help=None, **kwargs):
303 params = Util.clean_kwargs(locals().copy())
304 super(Section, self).__init__(**params)
305
306 def acceptable_child(self, child):
307 return issubclass(type(child), InputParameter)
308
309
310 class Repeat(InputParameter):
311 name = "repeat"
312
313 def __init__(self, name, title, min=None, max=None, default=None, **kwargs):
314 params = Util.clean_kwargs(locals().copy())
315 # Allow overriding
316 self.command_line_before_override = "#for $i in $%s:" % name
317 self.command_line_after_override = "#end for"
318 # self.command_line_override
319 super(Repeat, self).__init__(**params)
320
321 def acceptable_child(self, child):
322 return issubclass(type(child), InputParameter)
323
324 def command_line_actual(self):
325 if hasattr(self, "command_line_override"):
326 return self.command_line_override
327 else:
328 return "%s" % self.mako_name()
329
330
331 class Conditional(InputParameter):
332 name = "conditional"
333
334 def __init__(self, name, **kwargs):
335 params = Util.clean_kwargs(locals().copy())
336 super(Conditional, self).__init__(**params)
337
338 def acceptable_child(self, child):
339 return issubclass(type(child), InputParameter) and not isinstance(child, Conditional)
340
341 def validate(self):
342 # Find a way to check if one of the kids is a WHEN
343 pass
344
345
346 class When(InputParameter):
347 name = "when"
348
349 def __init__(self, value):
350 params = Util.clean_kwargs(locals().copy())
351 super(When, self).__init__(None, **params)
352
353 def acceptable_child(self, child):
354 return issubclass(type(child), InputParameter)
355
356
357 class Param(InputParameter):
358 name = "param"
359
360 # This...isn't really valid as-is, and shouldn't be used.
361 def __init__(self, name, optional=None, label=None, help=None, **kwargs):
362 params = Util.clean_kwargs(locals().copy())
363 params["type"] = self.type
364 super(Param, self).__init__(**params)
365
366 if type(self) == Param:
367 raise Exception("Param class is not an actual parameter type, use a subclass of Param")
368
369 def acceptable_child(self, child):
370 return issubclass(type(child, InputParameter) or isinstance(child), ValidatorParam)
371
372
373 class TextParam(Param):
374 type = "text"
375
376 def __init__(self, name, optional=None, label=None, help=None, value=None, **kwargs):
377 params = Util.clean_kwargs(locals().copy())
378 super(TextParam, self).__init__(**params)
379
380 def command_line_actual(self):
381 try:
382 return self.command_line_override
383 except Exception:
384 if self.positional:
385 return self.mako_name()
386 else:
387 return f"{self.flag}{self.space_between_arg}'{self.mako_name()}'"
388
389
390 class _NumericParam(Param):
391 def __init__(self, name, value, optional=None, label=None, help=None, min=None, max=None, **kwargs):
392 params = Util.clean_kwargs(locals().copy())
393 super(_NumericParam, self).__init__(**params)
394
395
396 class IntegerParam(_NumericParam):
397 type = "integer"
398
399
400 class FloatParam(_NumericParam):
401 type = "float"
402
403
404 class BooleanParam(Param):
405 type = "boolean"
406
407 def __init__(
408 self, name, optional=None, label=None, help=None, checked=False, truevalue=None, falsevalue=None, **kwargs
409 ):
410 params = Util.clean_kwargs(locals().copy())
411
412 super(BooleanParam, self).__init__(**params)
413 if truevalue is None:
414 # If truevalue and falsevalue are None, then we use "auto", the IUC
415 # recommended default.
416 #
417 # truevalue is set to the parameter's value, and falsevalue is not.
418 #
419 # Unfortunately, mako_identifier is set as a result of the super
420 # call, which we shouldn't call TWICE, so we'll just hack around this :(
421 # params['truevalue'] = '%s%s' % (self.)
422 self.node.attrib["truevalue"] = self.flag()
423
424 if falsevalue is None:
425 self.node.attrib["falsevalue"] = ""
426
427 def command_line_actual(self):
428 if hasattr(self, "command_line_override"):
429 return self.command_line_override
430 else:
431 return "%s" % self.mako_name()
432
433
434 class DataParam(Param):
435 type = "data"
436
437 def __init__(self, name, optional=None, label=None, help=None, format=None, multiple=None, **kwargs):
438 params = Util.clean_kwargs(locals().copy())
439 super(DataParam, self).__init__(**params)
440
441
442 class SelectParam(Param):
443 type = "select"
444
445 def __init__(
446 self,
447 name,
448 optional=None,
449 label=None,
450 help=None,
451 data_ref=None,
452 display=None,
453 multiple=None,
454 options=None,
455 default=None,
456 **kwargs
457 ):
458 params = Util.clean_kwargs(locals().copy())
459 del params["options"]
460 del params["default"]
461
462 super(SelectParam, self).__init__(**params)
463
464 if options is not None and default is not None:
465 if default not in options:
466 raise Exception("Specified a default that isn't in options")
467
468 if options:
469 for k, v in list(sorted(options.items())):
470 selected = k == default
471 self.append(SelectOption(k, v, selected=selected))
472
473 def acceptable_child(self, child):
474 return issubclass(type(child), SelectOption) or issubclass(type(child), Options)
475
476
477 class SelectOption(InputParameter):
478 name = "option"
479
480 def __init__(self, value, text, selected=False, **kwargs):
481 params = Util.clean_kwargs(locals().copy())
482
483 passed_kwargs = {}
484 if selected:
485 passed_kwargs["selected"] = "true"
486 passed_kwargs["value"] = params["value"]
487
488 super(SelectOption, self).__init__(None, **passed_kwargs)
489 self.node.text = str(text)
490
491
492 class Options(InputParameter):
493 name = "options"
494
495 def __init__(self, from_dataset=None, from_file=None, from_data_table=None, from_parameter=None, **kwargs):
496 params = Util.clean_kwargs(locals().copy())
497 super(Options, self).__init__(None, **params)
498
499 def acceptable_child(self, child):
500 return issubclass(type(child), Column) or issubclass(type(child), Filter)
501
502
503 class Column(InputParameter):
504 name = "column"
505
506 def __init__(self, name, index, **kwargs):
507 params = Util.clean_kwargs(locals().copy())
508 super(Column, self).__init__(**params)
509
510
511 class Filter(InputParameter):
512 name = "filter"
513
514 def __init__(
515 self,
516 type,
517 column=None,
518 name=None,
519 ref=None,
520 key=None,
521 multiple=None,
522 separator=None,
523 keep=None,
524 value=None,
525 ref_attribute=None,
526 index=None,
527 **kwargs
528 ):
529 params = Util.clean_kwargs(locals().copy())
530 super(Filter, self).__init__(**params)
531
532
533 class ValidatorParam(InputParameter):
534 name = "validator"
535
536 def __init__(
537 self,
538 type,
539 message=None,
540 filename=None,
541 metadata_name=None,
542 metadata_column=None,
543 line_startswith=None,
544 min=None,
545 max=None,
546 **kwargs
547 ):
548 params = Util.clean_kwargs(locals().copy())
549 super(ValidatorParam, self).__init__(**params)
550
551
552 class Outputs(XMLParam):
553 name = "outputs"
554
555 def acceptable_child(self, child):
556 return isinstance(child, OutputData) or isinstance(child, OutputCollection)
557
558
559 class OutputData(XMLParam):
560 """Copypasta of InputParameter, needs work
561 """
562
563 name = "data"
564
565 def __init__(
566 self,
567 name,
568 format,
569 format_source=None,
570 metadata_source=None,
571 label=None,
572 from_work_dir=None,
573 hidden=False,
574 **kwargs
575 ):
576 # TODO: validate format_source&metadata_source against something in the
577 # XMLParam children tree.
578 self.mako_identifier = name
579 if "num_dashes" in kwargs:
580 self.num_dashes = kwargs["num_dashes"]
581 del kwargs["num_dashes"]
582 else:
583 self.num_dashes = 0
584 self.space_between_arg = " "
585 params = Util.clean_kwargs(locals().copy())
586
587 super(OutputData, self).__init__(**params)
588
589 def command_line(self):
590 if hasattr(self, "command_line_override"):
591 return self.command_line_override
592 else:
593 return "%s%s%s" % (self.flag(), self.space_between_arg, self.mako_name())
594
595 def mako_name(self):
596 return "$" + self.mako_identifier
597
598 def flag(self):
599 flag = "-" * self.num_dashes
600 return flag + self.mako_identifier
601
602 def acceptable_child(self, child):
603 return isinstance(child, OutputFilter) or isinstance(child, ChangeFormat) or isinstance(child, DiscoverDatasets)
604
605
606 class OutputFilter(XMLParam):
607 name = "filter"
608
609 def __init__(self, text, **kwargs):
610 params = Util.clean_kwargs(locals().copy())
611 del params["text"]
612 super(OutputFilter, self).__init__(**params)
613 self.node.text = text
614
615 def acceptable_child(self, child):
616 return False
617
618
619 class ChangeFormat(XMLParam):
620 name = "change_format"
621
622 def __init__(self, **kwargs):
623 params = Util.clean_kwargs(locals().copy())
624 super(ChangeFormat, self).__init__(**params)
625
626 def acceptable_child(self, child):
627 return isinstance(child, ChangeFormatWhen)
628
629
630 class ChangeFormatWhen(XMLParam):
631 name = "when"
632
633 def __init__(self, input, format, value, **kwargs):
634 params = Util.clean_kwargs(locals().copy())
635 super(ChangeFormatWhen, self).__init__(**params)
636
637 def acceptable_child(self, child):
638 return False
639
640
641 class OutputCollection(XMLParam):
642 name = "collection"
643
644 def __init__(
645 self,
646 name,
647 type=None,
648 label=None,
649 format_source=None,
650 type_source=None,
651 structured_like=None,
652 inherit_format=None,
653 **kwargs
654 ):
655 params = Util.clean_kwargs(locals().copy())
656 super(OutputCollection, self).__init__(**params)
657
658 def acceptable_child(self, child):
659 return isinstance(child, OutputData) or isinstance(child, OutputFilter) or isinstance(child, DiscoverDatasets)
660
661
662 class DiscoverDatasets(XMLParam):
663 name = "discover_datasets"
664
665 def __init__(self, pattern, directory=None, format=None, ext=None, visible=None, **kwargs):
666 params = Util.clean_kwargs(locals().copy())
667 super(DiscoverDatasets, self).__init__(**params)
668
669
670 class Tests(XMLParam):
671 name = "tests"
672
673 def acceptable_child(self, child):
674 return issubclass(type(child), Test)
675
676
677 class Test(XMLParam):
678 name = "test"
679
680 def acceptable_child(self, child):
681 return isinstance(child, TestParam) or isinstance(child, TestOutput)
682
683
684 class TestParam(XMLParam):
685 name = "param"
686
687 def __init__(self, name, value=None, ftype=None, dbkey=None, **kwargs):
688 params = Util.clean_kwargs(locals().copy())
689 super(TestParam, self).__init__(**params)
690
691
692 class TestOutput(XMLParam):
693 name = "output"
694
695 def __init__(
696 self,
697 name=None,
698 file=None,
699 ftype=None,
700 sort=None,
701 value=None,
702 md5=None,
703 checksum=None,
704 compare=None,
705 lines_diff=None,
706 delta=None,
707 **kwargs
708 ):
709 params = Util.clean_kwargs(locals().copy())
710 super(TestOutput, self).__init__(**params)
711
712
713 class Citations(XMLParam):
714 name = "citations"
715
716 def acceptable_child(self, child):
717 return issubclass(type(child), Citation)
718
719 def has_citation(self, type, value):
720 """
721 Check the presence of a given citation.
722
723 :type type: STRING
724 :type value: STRING
725 """
726 for citation in self.children:
727 if citation.node.attrib["type"] == type and citation.node.text == value:
728 return True
729 return False
730
731
732 class Citation(XMLParam):
733 name = "citation"
734
735 def __init__(self, type, value):
736 passed_kwargs = {}
737 passed_kwargs["type"] = type
738 super(Citation, self).__init__(**passed_kwargs)
739 self.node.text = str(value)