Mercurial > repos > fubar > tool_factory_2
changeset 35:5d38cb3d9be8 draft
added patched galaxyxml code temporarily until PR accepted
author | fubar |
---|---|
date | Sat, 08 Aug 2020 19:55:55 -0400 |
parents | 5052ac89c036 |
children | ce2b1f8ea68d |
files | toolfactory/__init__.py toolfactory/galaxyxml/__init__.py toolfactory/galaxyxml/tool/__init__.py toolfactory/galaxyxml/tool/import_xml.py toolfactory/galaxyxml/tool/parameters/__init__.py toolfactory/sample_toolfactory_tools.ga |
diffstat | 5 files changed, 2029 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toolfactory/galaxyxml/__init__.py Sat Aug 08 19:55:55 2020 -0400 @@ -0,0 +1,66 @@ +from builtins import str +from builtins import object +from lxml import etree + + +class GalaxyXML(object): + + def __init__(self): + self.root = etree.Element('root') + + def export(self): + return etree.tostring(self.root, pretty_print=True, encoding='unicode') + + +class Util(object): + + @classmethod + def coerce(cls, data, kill_lists=False): + """Recursive data sanitisation + """ + if isinstance(data, dict): + return {k: cls.coerce(v, kill_lists=kill_lists) for k, v in + list(data.items()) if v is not None} + elif isinstance(data, list): + if kill_lists: + return cls.coerce(data[0]) + else: + return [cls.coerce(v, kill_lists=kill_lists) for v in data] + else: + return cls.coerce_value(data) + + @classmethod + def coerce_value(cls, obj): + """Make everything a string! + """ + if isinstance(obj, bool): + if obj: + return "true" + else: + return "false" + elif isinstance(obj, str): + return obj + else: + return str(obj) + + @classmethod + def clean_kwargs(cls, params, final=False): + if 'kwargs' in params: + kwargs = params['kwargs'] + for k in kwargs: + params[k] = kwargs[k] + del params['kwargs'] + if 'self' in params: + del params['self'] + + if '__class__' in params: + del params['__class__'] + + # There will be more params, it would be NICE to use a whitelist + # instead of a blacklist, but until we have more data let's just + # blacklist stuff we see commonly. + if final: + for blacklist in ('positional',): + if blacklist in params: + del params[blacklist] + return params
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toolfactory/galaxyxml/tool/__init__.py Sat Aug 08 19:55:55 2020 -0400 @@ -0,0 +1,172 @@ +import copy +import logging +from lxml import etree +from galaxyxml import Util, GalaxyXML +from galaxyxml.tool.parameters import XMLParam + +VALID_TOOL_TYPES = ('data_source', 'data_source_async') +VALID_URL_METHODS = ('get', 'post') + +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + + +class Tool(GalaxyXML): + + def __init__(self, name, id, version, description, executable, hidden=False, + tool_type=None, URL_method=None, workflow_compatible=True, + interpreter=None, version_command='interpreter filename.exe --version', + command_line_override=None): + + self.executable = executable + self.interpreter = interpreter + self.command_line_override = command_line_override + kwargs = { + 'name': name, + 'id': id, + 'version': version, + 'hidden': hidden, + 'workflow_compatible': workflow_compatible, + } + self.version_command = version_command + + # Remove some of the default values to make tools look a bit nicer + if not hidden: + del kwargs['hidden'] + if workflow_compatible: + del kwargs['workflow_compatible'] + + kwargs = Util.coerce(kwargs) + self.root = etree.Element('tool', **kwargs) + + if tool_type is not None: + if tool_type not in VALID_TOOL_TYPES: + raise Exception("Tool type must be one of %s" % + ','.join(VALID_TOOL_TYPES)) + else: + kwargs['tool_type'] = tool_type + + if URL_method is not None: + if URL_method in VALID_URL_METHODS: + kwargs['URL_method'] = URL_method + else: + raise Exception("URL_method must be one of %s" % + ','.join(VALID_URL_METHODS)) + + description_node = etree.SubElement(self.root, 'description') + description_node.text = description + + def add_comment(self, comment_txt): + comment = etree.Comment(comment_txt) + self.root.insert(0, comment) + + def append_version_command(self): + version_command = etree.SubElement(self.root, 'version_command') + try: + version_command.text = etree.CDATA(self.version_command) + except Exception: + pass + + def append(self, sub_node): + if issubclass(type(sub_node), XMLParam): + self.root.append(sub_node.node) + else: + self.root.append(sub_node) + + def clean_command_string(self, command_line): + clean = [] + for x in command_line: + if x is not [] and x is not ['']: + clean.append(x) + + return '\n'.join(clean) + + def export(self, keep_old_command=False): # noqa + + export_xml = copy.deepcopy(self) + + try: + export_xml.append(export_xml.edam_operations) + except Exception: + pass + + try: + export_xml.append(export_xml.edam_topics) + except Exception: + pass + + try: + export_xml.append(export_xml.requirements) + except Exception: + pass + + try: + export_xml.append(export_xml.configfiles) + except Exception: + pass + + if self.command_line_override != None: + command_line = self.command_line_override + else: + command_line = [] + try: + command_line.append(export_xml.inputs.cli()) + except Exception as e: + logger.warning(str(e)) + + try: + command_line.append(export_xml.outputs.cli()) + except Exception: + pass + + # Add stdio section + stdio = etree.SubElement(export_xml.root, 'stdio') + etree.SubElement(stdio, 'exit_code', range='1:', level='fatal') + + # Append version command + export_xml.append_version_command() + + # Steal interpreter from kwargs + command_kwargs = {} + if export_xml.interpreter is not None: + command_kwargs['interpreter'] = export_xml.interpreter + + # Add command section + command_node = etree.SubElement(export_xml.root, 'command', **command_kwargs) + + if keep_old_command: + if getattr(self, 'command', None): + command_node.text = etree.CDATA(export_xml.command) + else: + logger.warning('The tool does not have any old command stored. ' + + 'Only the command line is written.') + command_node.text = export_xml.executable + else: + actual_cli = "%s %s" % ( + export_xml.executable, export_xml.clean_command_string(command_line)) + command_node.text = etree.CDATA(actual_cli.strip()) + + try: + export_xml.append(export_xml.inputs) + except Exception: + pass + + try: + export_xml.append(export_xml.outputs) + except Exception: + pass + + try: + export_xml.append(export_xml.tests) + except Exception: + pass + + help_element = etree.SubElement(export_xml.root, 'help') + help_element.text = etree.CDATA(export_xml.help) + + try: + export_xml.append(export_xml.citations) + except Exception: + pass + + return super(Tool, export_xml).export()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toolfactory/galaxyxml/tool/import_xml.py Sat Aug 08 19:55:55 2020 -0400 @@ -0,0 +1,660 @@ +import logging +import xml.etree.ElementTree as ET +import galaxyxml.tool as gxt +import galaxyxml.tool.parameters as gxtp + +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + + +class GalaxyXmlParser(object): + """ + Class to import content from an existing Galaxy XML wrapper. + """ + + def _init_tool(self, xml_root): + """ + Init tool from existing xml tool. + + :param xml_root: root of the galaxy xml file. + :type xml_root: :class:`xml.etree._Element` + """ + version_cmd = None + description = None + for child in xml_root: + if child.tag == 'description': + description = child.text + elif child.tag == 'command': + executable = child.text.split()[0] + command = child.text + elif child.tag == 'version_command': + version_cmd = child.text + + tool = gxt.Tool(xml_root.attrib['name'], + xml_root.attrib['id'], + xml_root.attrib.get('version', None), + description, + executable, + hidden=xml_root.attrib.get('hidden', False), + tool_type=xml_root.attrib.get('tool_type', None), + URL_method=xml_root.attrib.get('URL_method', None), + workflow_compatible=xml_root.attrib.get('workflow_compatible', True), + version_command=version_cmd) + tool.command = command + return tool + + def _load_description(self, tool, desc_root): + """ + <description> is already loaded during initiation. + + :param tool: Tool object from galaxyxml. + :type tool: :class:`galaxyxml.tool.Tool` + :param desc_root: root of <description> tag. + :type desc_root: :class:`xml.etree._Element` + """ + logger.info("<description> is loaded during initiation of the object.") + + def _load_version_command(self, tool, vers_root): + """ + <version_command> is already loaded during initiation. + + :param tool: Tool object from galaxyxml. + :type tool: :class:`galaxyxml.tool.Tool` + :param vers_root: root of <version_command> tag. + :type vers_root: :class:`xml.etree._Element` + """ + logger.info("<version_command> is loaded during initiation of the object.") + + def _load_stdio(self, tool, stdio_root): + """ + So far, <stdio> is automatically generated by galaxyxml. + + :param tool: Tool object from galaxyxml. + :type tool: :class:`galaxyxml.tool.Tool` + :param desc_root: root of <stdio> tag. + :type desc_root: :class:`xml.etree._Element` + """ + logger.info("<stdio> is not loaded but automatically generated by galaxyxml.") + + def _load_command(self, tool, desc_root): + """ + <command> is already loaded during initiation. + + :param tool: Tool object from galaxyxml. + :type tool: :class:`galaxyxml.tool.Tool` + :param desc_root: root of <command> tag. + :type desc_root: :class:`xml.etree._Element` + """ + logger.info("<command> is loaded during initiation of the object.") + + def _load_help(self, tool, help_root): + """ + Load the content of the <help> into the tool. + + :param tool: Tool object from galaxyxml. + :type tool: :class:`galaxyxml.tool.Tool` + :param requirements_root: root of <help> tag. + :type requirements_root: :class:`xml.etree._Element` + """ + tool.help = help_root.text + + def _load_requirements(self, tool, requirements_root): + """ + Add <requirements> to the tool. + + :param tool: Tool object from galaxyxml. + :type tool: :class:`galaxyxml.tool.Tool` + :param requirements_root: root of <requirements> tag. + :type requirements_root: :class:`xml.etree._Element` + """ + tool.requirements = gxtp.Requirements() + for req in requirements_root: + req_type = req.attrib['type'] + value = req.text + if req.tag == 'requirement': + version = req.attrib.get('version', None) + tool.requirements.append(gxtp.Requirement(req_type, value, version=version)) + elif req.tag == 'container': + tool.requirements.append(gxtp.Container(req_type, value)) + else: + logger.warning(req.tag + ' is not a valid tag for requirements child') + + def _load_edam_topics(self, tool, topics_root): + """ + Add <edam_topics> to the tool. + + :param tool: Tool object from galaxyxml. + :type tool: :class:`galaxyxml.tool.Tool` + :param topics_root: root of <edam_topics> tag. + :type topics_root: :class:`xml.etree._Element` + """ + tool.edam_topics = gxtp.EdamTopics() + for edam_topic in topics_root: + tool.edam_topics.append(gxtp.EdamTopic(edam_topic.text)) + + def _load_edam_operations(self, tool, operations_root): + """ + Add <edam_operations> to the tool. + + :param tool: Tool object from galaxyxml. + :type tool: :class:`galaxyxml.tool.Tool` + :param operations_root: root of <edam_operations> tag. + :type operations_root: :class:`xml.etree._Element` + """ + tool.edam_operations = gxtp.EdamOperations() + for edam_op in operations_root: + tool.edam_operations.append(gxtp.EdamOperation(edam_op.text)) + + def _load_configfiles(self, tool, configfiles_root): + """ + Add <configfiles> to the tool. + + :param tool: Tool object from galaxyxml. + :type tool: :class:`galaxyxml.tool.Tool` + :param configfiles_root: root of <configfiles> tag. + :type configfiles_root: :class:`xml.etree._Element` + """ + tool.configfiles = gxtp.Configfiles() + for conf in configfiles_root: + name = conf.attrib['name'] + value = conf.text + tool.configfiles.append(gxtp.Configfile(name, value)) + + def _load_citations(self, tool, citations_root): + """ + Add <citations> to the tool. + + :param tool: Tool object from galaxyxml. + :type tool: :class:`galaxyxml.tool.Tool` + :param citations_root: root of <citations> tag. + :type citations_root: :class:`xml.etree._Element` + """ + tool.citations = gxtp.Citations() + for cit in citations_root: + cit_type = cit.attrib['type'] + value = cit.text + tool.citations.append(gxtp.Citation(cit_type, value)) + + def _load_inputs(self, tool, inputs_root): + """ + Add <inputs> to the tool using the :class:`galaxyxml.tool.import_xml.InputsParser` object. + + :param tool: Tool object from galaxyxml. + :type tool: :class:`galaxyxml.tool.Tool` + :param inputs_root: root of <inputs> tag. + :type inputs_root: :class:`xml.etree._Element` + """ + tool.inputs = gxtp.Inputs() + inp_parser = InputsParser() + inp_parser.load_inputs(tool.inputs, inputs_root) + + def _load_outputs(self, tool, outputs_root): + """ + Add <outputs> to the tool using the :class:`galaxyxml.tool.import_xml.OutputsParser` object. + + :param tool: Tool object from galaxyxml. + :type tool: :class:`galaxyxml.tool.Tool` + :param outputs_root: root of <outputs> tag. + :type outputs_root: :class:`xml.etree._Element` + """ + tool.outputs = gxtp.Outputs() + out_parser = OutputsParser() + out_parser.load_outputs(tool.outputs, outputs_root) + + def _load_tests(self, tool, tests_root): + """ + Add <tests> to the tool using the :class:`galaxyxml.tool.import_xml.TestsParser` object. + + :param tool: Tool object from galaxyxml. + :type tool: :class:`galaxyxml.tool.Tool` + :param tests_root: root of <tests> tag. + :type tests_root: :class:`xml.etree._Element` + """ + tool.tests = gxtp.Tests() + tests_parser = TestsParser() + tests_parser.load_tests(tool.tests, tests_root) + + def import_xml(self, xml_path): + """ + Load existing xml into the :class:`galaxyxml.tool.Tool` object. + + :param xml_path: Path of the XML to be loaded. + :type xml_path: STRING + :return: XML content in the galaxyxml model. + :rtype: :class:`galaxyxml.tool.Tool` + """ + xml_root = ET.parse(xml_path).getroot() + tool = self._init_tool(xml_root) + # Now we import each tag's field + for child in xml_root: + try: + getattr(self, '_load_{}'.format(child.tag))(tool, child) + except AttributeError: + logger.warning(child.tag + " tag is not processed.") + return tool + + +class InputsParser(object): + """ + Class to parse content of the <inputs> tag from a Galaxy XML wrapper. + """ + + def _load_text_param(self, root, text_param): + """ + Add <param type="text" /> to the root. + + :param root: root to append the param to. + :param text_param: root of <param> tag. + :type text_param: :class:`xml.etree._Element` + """ + root.append(gxtp.TextParam(text_param.attrib['name'], + optional=text_param.get('optional', None), + label=text_param.get('label', None), + help=text_param.get('help', None), + value=text_param.get('value', None))) + + def _load_data_param(self, root, data_param): + """ + Add <param type="data" /> to the root. + + :param root: root to append the param to. + :param data_param: root of <param> tag. + :type data_param: :class:`xml.etree._Element` + """ + root.append(gxtp.DataParam(data_param.attrib['name'], + optional=data_param.attrib.get('optional', None), + label=data_param.attrib.get('label', None), + help=data_param.attrib.get('help', None), + format=data_param.attrib.get('format', None), + multiple=data_param.attrib.get('multiple', None))) + + def _load_boolean_param(self, root, bool_param): + """ + Add <param type="boolean" /> to the root. + + :param root: root to append the param to. + :param bool_param: root of <param> tag. + :type bool_param: :class:`xml.etree._Element` + """ + root.append(gxtp.BooleanParam(bool_param.attrib['name'], + optional=bool_param.attrib.get('optional', None), + label=bool_param.attrib.get('label', None), + help=bool_param.attrib.get('help', None), + checked=bool_param.attrib.get('checked', False), + truevalue=bool_param.attrib.get('truevalue', None), + falsevalue=bool_param.attrib.get('falsevalue', None))) + + def _load_integer_param(self, root, int_param): + """ + Add <param type="integer" /> to the root. + + :param root: root to append the param to. + :param int_param: root of <param> tag. + :type int_param: :class:`xml.etree._Element` + """ + root.append(gxtp.IntegerParam(int_param.attrib['name'], + int_param.attrib.get('value', None), + optional=int_param.attrib.get('optional', None), + label=int_param.attrib.get('label', None), + help=int_param.attrib.get('help', None), + min=int_param.attrib.get('min', None), + max=int_param.attrib.get('max', None))) + + def _load_float_param(self, root, float_param): + """ + Add <param type="float" /> to the root. + + :param root: root to append the param to. + :param float_param: root of <param> tag. + :type float_param: :class:`xml.etree._Element` + """ + root.append(gxtp.FloatParam(float_param.attrib['name'], + float_param.attrib.get('value', None), + optional=float_param.attrib.get('optional', None), + label=float_param.attrib.get('label', None), + help=float_param.attrib.get('help', None), + min=float_param.attrib.get('min', None), + max=float_param.attrib.get('max', None))) + + def _load_option_select(self, root, option): + """ + Add <option> to the root (usually <param type="select" />). + + :param root: root to append the param to. + :param option: root of <option> tag. + :type float_param: :class:`xml.etree._Element` + """ + root.append(gxtp.SelectOption(option.attrib.get('value', None), + option.text, + selected=option.attrib.get('selected', False))) + + def _load_column_options(self, root, column): + """ + Add <column> to the root (usually <options>). + + :param root: root to append the param to. + :param option: root of <column> tag. + :type float_param: :class:`xml.etree._Element` + """ + root.append(gxtp.Column(column.attrib['name'], column.attrib['index'])) + + def _load_filter_options(self, root, filter): + """ + Add <filter> to the root (usually <options>). + + :param root: root to append the param to. + :param option: root of <filter> tag. + :type float_param: :class:`xml.etree._Element` + """ + root.append(gxtp.Filter(filter.attrib['type'], + column=filter.attrib.get('column', None), + name=filter.attrib.get('name', None), + ref=filter.attrib.get('ref', None), + key=filter.attrib.get('key', None), + multiple=filter.attrib.get('multiple', None), + separator=filter.attrib.get('separator', None), + keep=filter.attrib.get('keep', None), + value=filter.attrib.get('value', None), + ref_attribute=filter.attrib.get('ref_attribute', None), + index=filter.attrib.get('index', None))) + + def _load_options_select(self, root, options): + """ + Add <options> to the root (usually <param type="select" />). + + :param root: root to append the param to. + :param option: root of <options> tag. + :type float_param: :class:`xml.etree._Element` + """ + opts = gxtp.Options(from_dataset=options.attrib.get('from_dataset', None), + from_file=options.attrib.get('from_file', None), + from_data_table=options.attrib.get('from_data_table', None), + from_parameter=options.attrib.get('from_parameter', None)) + # Deal with child nodes (usually filter and column) + for opt_child in options: + try: + getattr(self, '_load_{}_options'.format(opt_child.tag))(opts, opt_child) + except AttributeError: + logger.warning(opt_child.tag + " tag is not processed for <options>.") + root.append(opts) + + def _load_select_param(self, root, sel_param): + """ + Add <param type="select" /> to the root. + + :param root: root to append the param to. + :param sel_param: root of <param> tag. + :type sel_param: :class:`xml.etree._Element` + """ + select_param = gxtp.SelectParam(sel_param.attrib['name'], + optional=sel_param.attrib.get('optional', None), + label=sel_param.attrib.get('label', None), + help=sel_param.attrib.get('help', None), + data_ref=sel_param.attrib.get('data_ref', None), + display=sel_param.attrib.get('display', None), + multiple=sel_param.attrib.get('multiple', None)) + # Deal with child nodes (usually option and options) + for sel_child in sel_param: + try: + getattr(self, '_load_{}_select'.format(sel_child.tag))(select_param, sel_child) + except AttributeError: + logger.warning(sel_child.tag + " tag is not processed for <param type='select'>.") + root.append(select_param) + + def _load_param(self, root, param_root): + """ + Method to select which type of <param> is being added to the root. + + :param root: root to attach param to. + :param param_root: root of <param> tag. + :type param_root: :class:`xml.etree._Element` + """ + param_type = param_root.attrib['type'] + try: + getattr(self, '_load_{}_param'.format(param_type))(root, param_root) + except AttributeError: + logger.warning(param_type + " tag is not processed for <param>.") + + def _load_when(self, root, when_root): + """ + Add <when> to the root (usually <conditional>). + + :param root: root to append when to. + :param when_root: root of <when> tag. + :type when_root: :class:`xml.etree._Element` + """ + when = gxtp.When(when_root.attrib['value']) + # Deal with child nodes + self.load_inputs(when, when_root) + root.append(when) + + def _load_conditional(self, root, conditional_root): + """ + Add <conditional> to the root. + + :param root: root to append conditional to. + :param conditional_root: root of <conditional> tag. + :type conditional_root: :class:`xml.etree._Element` + """ + value_ref_in_group = conditional_root.attrib.get('value_ref_in_group', None) + # Other optional parameters need to be added to conditional object + conditional = gxtp.Conditional(conditional_root.attrib['name'], + value_from=conditional_root.attrib.get('value_from', None), + value_ref=conditional_root.attrib.get('value_ref', None), + value_ref_in_group=value_ref_in_group, + label=conditional_root.attrib.get('label', None)) + # Deal with child nodes + self.load_inputs(conditional, conditional_root) + root.append(conditional) + + def _load_section(self, root, section_root): + """ + Add <section> to the root. + + :param root: root to append conditional to. + :param section_root: root of <section> tag. + :type section_root: :class:`xml.etree._Element` + """ + section = gxtp.Section(section_root.attrib['name'], + section_root.attrib['title'], + expanded=section_root.attrib.get('expanded', None), + help=section_root.attrib.get('help', None)) + # Deal with child nodes + self.load_inputs(section, section_root) + root.append(section) + + def _load_repeat(self, root, repeat_root): + """ + Add <repeat> to the root. + + :param root: root to append repeat to. + :param repeat_root: root of <repeat> tag. + :param repeat_root: :class:`xml.etree._Element` + """ + repeat = gxtp.Repeat(repeat_root.attrib['name'], + repeat_root.attrib['title'], + min=repeat_root.attrib.get('min', None), + max=repeat_root.attrib.get('max', None), + default=repeat_root.attrib.get('default', None)) + # Deal with child nodes + self.load_inputs(repeat, repeat_root) + root.append(repeat) + + def load_inputs(self, root, inputs_root): + """ + Add <inputs.tag> to the root (it can be any tags with children such as + <inputs>, <repeat>, <section> ...) + + :param root: root to attach inputs to (either <inputs> or <when>). + :param inputs_root: root of <inputs> tag. + :type inputs_root: :class:`xml.etree._Element` + """ + for inp_child in inputs_root: + try: + getattr(self, '_load_{}'.format(inp_child.tag))(root, inp_child) + except AttributeError: + logger.warning(inp_child.tag + " tag is not processed for <" + + inputs_root.tag + "> tag.") + + +class OutputsParser(object): + """ + Class to parse content of the <outputs> tag from a Galaxy XML wrapper. + """ + + def _load_data(self, outputs_root, data_root): + """ + Add <data> to <outputs>. + + :param outputs_root: <outputs> root to append <data> to. + :param data_root: root of <data> tag. + :param data_root: :class:`xml.etree._Element` + """ + data = gxtp.OutputData(data_root.attrib.get('name', None), + data_root.attrib.get('format', None), + format_source=data_root.attrib.get('format_source', None), + metadata_source=data_root.attrib.get('metadata_source', None), + label=data_root.attrib.get('label', None), + from_work_dir=data_root.attrib.get('from_work_dir', None), + hidden=data_root.attrib.get('hidden', False)) + # Deal with child nodes + for data_child in data_root: + try: + getattr(self, '_load_{}'.format(data_child.tag))(data, data_child) + except AttributeError: + logger.warning(data_child.tag + " tag is not processed for <data>.") + outputs_root.append(data) + + def _load_change_format(self, root, chfmt_root): + """ + Add <change_format> to root (<data>). + + :param root: root to append <change_format> to. + :param chfm_root: root of <change_format> tag. + :param chfm_root: :class:`xml.etree._Element` + """ + change_format = gxtp.ChangeFormat() + for chfmt_child in chfmt_root: + change_format.append(gxtp.ChangeFormatWhen(chfmt_child.attrib['input'], + chfmt_child.attrib['format'], + chfmt_child.attrib['value'])) + root.append(change_format) + + def _load_collection(self, outputs_root, coll_root): + """ + Add <collection> to <outputs>. + + :param outputs_root: <outputs> root to append <collection> to. + :param coll_root: root of <collection> tag. + :param coll_root: :class:`xml.etree._Element` + """ + collection = gxtp.OutputCollection(coll_root.attrib['name'], + type=coll_root.attrib.get('type', None), + label=coll_root.attrib.get('label', None), + format_source=coll_root.attrib.get('format_source', + None), + type_source=coll_root.attrib.get('type_source', None), + structured_like=coll_root.attrib.get('structured_like', + None), + inherit_format=coll_root.attrib.get('inherit_format', + None)) + # Deal with child nodes + for coll_child in coll_root: + try: + getattr(self, '_load_{}'.format(coll_child.tag))(collection, coll_child) + except AttributeError: + logger.warning(coll_child.tag + " tag is not processed for <collection>.") + outputs_root.append(collection) + + def _load_discover_datasets(self, root, disc_root): + """ + Add <discover_datasets> to root (<collection>). + + :param root: root to append <collection> to. + :param disc_root: root of <discover_datasets> tag. + :param disc_root: :class:`xml.etree._Element` + """ + root.append(gxtp.DiscoverDatasets(disc_root.attrib['pattern'], + directory=disc_root.attrib.get('directory', None), + format=disc_root.attrib.get('format', None), + ext=disc_root.attrib.get('ext', None), + visible=disc_root.attrib.get('visible', None))) + + def _load_filter(self, root, filter_root): + """ + Add <filter> to root (<collection> or <data>). + + :param root: root to append <collection> to. + :param coll_root: root of <filter> tag. + :param coll_root: :class:`xml.etree._Element` + """ + root.append(gxtp.OutputFilter(filter_root.text)) + + def load_outputs(self, root, outputs_root): + """ + Add <outputs> to the root. + + :param root: root to attach <outputs> to (<tool>). + :param tests_root: root of <outputs> tag. + :type tests_root: :class:`xml.etree._Element` + """ + for out_child in outputs_root: + try: + getattr(self, '_load_{}'.format(out_child.tag))(root, out_child) + except AttributeError: + logger.warning(out_child.tag + " tag is not processed for <outputs>.") + + +class TestsParser(object): + """ + Class to parse content of the <tests> tag from a Galaxy XML wrapper. + """ + + def _load_param(self, test_root, param_root): + """ + Add <param> to the <test>. + + :param root: <test> root to append <param> to. + :param repeat_root: root of <param> tag. + :param repeat_root: :class:`xml.etree._Element` + """ + test_root.append(gxtp.TestParam(param_root.attrib['name'], + value=param_root.attrib.get('value', None), + ftype=param_root.attrib.get('ftype', None), + dbkey=param_root.attrib.get('dbkey', None))) + + def _load_output(self, test_root, output_root): + """ + Add <output> to the <test>. + + :param root: <test> root to append <output> to. + :param repeat_root: root of <output> tag. + :param repeat_root: :class:`xml.etree._Element` + """ + test_root.append(gxtp.TestOutput(name=output_root.attrib.get('name', None), + file=output_root.attrib.get('file', None), + ftype=output_root.attrib.get('ftype', None), + sort=output_root.attrib.get('sort', None), + value=output_root.attrib.get('value', None), + md5=output_root.attrib.get('md5', None), + checksum=output_root.attrib.get('checksum', None), + compare=output_root.attrib.get('compare', None), + lines_diff=output_root.attrib.get('lines_diff', None), + delta=output_root.attrib.get('delta', None))) + + def load_tests(self, root, tests_root): + """ + Add <tests> to the root. + + :param root: root to attach <tests> to (<tool>). + :param tests_root: root of <tests> tag. + :type tests_root: :class:`xml.etree._Element` + """ + for test_root in tests_root: + test = gxtp.Test() + for test_child in test_root: + try: + getattr(self, '_load_{}'.format(test_child.tag))(test, test_child) + except AttributeError: + logger.warning(test_child.tag + " tag is not processed within <test>.") + root.append(test)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toolfactory/galaxyxml/tool/parameters/__init__.py Sat Aug 08 19:55:55 2020 -0400 @@ -0,0 +1,688 @@ +from builtins import str +from builtins import object +from lxml import etree +from galaxyxml import Util + + +class XMLParam(object): + name = 'node' + + def __init__(self, *args, **kwargs): + # http://stackoverflow.com/a/12118700 + self.children = [] + kwargs = {k: v for k, v in list(kwargs.items()) if v is not None} + kwargs = Util.coerce(kwargs, kill_lists=True) + kwargs = Util.clean_kwargs(kwargs, final=True) + self.node = etree.Element(self.name, **kwargs) + + def append(self, sub_node): + if self.acceptable_child(sub_node): + # If one of ours, they aren't etree nodes, they're custom objects + if issubclass(type(sub_node), XMLParam): + self.node.append(sub_node.node) + self.children.append(sub_node) + else: + raise Exception("Child was unacceptable to parent (%s is not appropriate for %s)" % ( + type(self), type(sub_node))) + else: + raise Exception("Child was unacceptable to parent (%s is not appropriate for %s)" % ( + type(self), type(sub_node))) + + def validate(self): + # Very few need validation, but some nodes we may want to have + # validation routines on. Should only be called when DONE. + for child in self.children: + # If any child fails to validate return false. + if not child.validate(): + return False + return True + + def cli(self): + lines = [] + for child in self.children: + lines.append(child.command_line()) + # lines += child.command_line() + return '\n'.join(lines) + + def command_line(self): + return None + + +class RequestParamTranslation(XMLParam): + name = 'request_param_translation' + + def __init__(self, **kwargs): + self.node = etree.Element(self.name) + + def acceptable_child(self, child): + return isinstance(child, RequestParamTranslation) + + +class RequestParam(XMLParam): + name = 'request_param' + + def __init__(self, galaxy_name, remote_name, missing, **kwargs): + # TODO: bulk copy locals into self.attr? + self.galaxy_name = galaxy_name + # http://stackoverflow.com/a/1408860 + params = Util.clean_kwargs(locals().copy()) + super(RequestParam, self).__init__(**params) + + def acceptable_child(self, child): + return isinstance(child, AppendParam) and self.galaxy_name == "URL" + + +class AppendParam(XMLParam): + name = 'append_param' + + def __init__(self, separator="&", first_separator="?", join="=", **kwargs): + params = Util.clean_kwargs(locals().copy()) + super(AppendParam, self).__init__(**params) + + def acceptable_child(self, child): + return isinstance(child, AppendParamValue) + + +class AppendParamValue(XMLParam): + name = 'value' + + def __init__(self, name="_export", missing="1", **kwargs): + params = Util.clean_kwargs(locals().copy()) + super(AppendParamValue, self).__init__(**params) + + def acceptable_child(self, child): + return False + + +class EdamOperations(XMLParam): + name = 'edam_operations' + + def acceptable_child(self, child): + return issubclass(type(child), EdamOperation) + + def has_operation(self, edam_operation): + """ + Check the presence of a given edam_operation. + + :type edam_operation: STRING + """ + for operation in self.children: + if operation.node.text == edam_operation: + return True + return False + + +class EdamOperation(XMLParam): + name = 'edam_operation' + + def __init__(self, value): + super(EdamOperation, self).__init__() + self.node.text = str(value) + + +class EdamTopics(XMLParam): + name = 'edam_topics' + + def acceptable_child(self, child): + return issubclass(type(child), EdamTopic) + + def has_topic(self, edam_topic): + """ + Check the presence of a given edam_topic. + + :type edam_topic: STRING + """ + for topic in self.children: + if topic.node.text == edam_topic: + return True + return False + + +class EdamTopic(XMLParam): + name = 'edam_topic' + + def __init__(self, value): + super(EdamTopic, self).__init__() + self.node.text = str(value) + + +class Requirements(XMLParam): + name = 'requirements' + # This bodes to be an issue -__- + + def acceptable_child(self, child): + return issubclass(type(child), Requirement) or issubclass(type(child), Container) + + +class Requirement(XMLParam): + name = 'requirement' + + def __init__(self, type, value, version=None, **kwargs): + params = Util.clean_kwargs(locals().copy()) + passed_kwargs = {} + passed_kwargs['version'] = params['version'] + passed_kwargs['type'] = params['type'] + super(Requirement, self).__init__(**passed_kwargs) + self.node.text = str(value) + + +class Container(XMLParam): + name = 'container' + + def __init__(self, type, value, **kwargs): + params = Util.clean_kwargs(locals().copy()) + passed_kwargs = {} + passed_kwargs['type'] = params['type'] + super(Container, self).__init__(**passed_kwargs) + self.node.text = str(value) + + +class Configfiles(XMLParam): + name = 'configfiles' + + def acceptable_child(self, child): + return issubclass(type(child), Configfile) or issubclass(type(child), ConfigfileDefaultInputs) + + +class Configfile(XMLParam): + name = 'configfile' + + def __init__(self, name, text, **kwargs): + params = Util.clean_kwargs(locals().copy()) + passed_kwargs = {} + passed_kwargs['name'] = params['name'] + super(Configfile, self).__init__(**passed_kwargs) + self.node.text = etree.CDATA(str(text)) + + +class ConfigfileDefaultInputs(XMLParam): + name = 'inputs' + + def __init__(self, name, **kwargs): + params = Util.clean_kwargs(locals().copy()) + passed_kwargs = {} + passed_kwargs['name'] = params['name'] + super(ConfigfileDefaultInputs, self).__init__(**passed_kwargs) + + +class Inputs(XMLParam): + name = 'inputs' + # This bodes to be an issue -__- + + def __init__(self, action=None, check_value=None, method=None, + target=None, nginx_upload=None, **kwargs): + params = Util.clean_kwargs(locals().copy()) + super(Inputs, self).__init__(**params) + + def acceptable_child(self, child): + return issubclass(type(child), InputParameter) + + +class InputParameter(XMLParam): + + def __init__(self, name, **kwargs): + # TODO: look at + self.mako_identifier = name + # We use kwargs instead of the usual locals(), so manually copy the + # name to kwargs + if name is not None: + kwargs['name'] = name + + # Handle positional parameters + if 'positional' in kwargs and kwargs['positional']: + self.positional = True + else: + self.positional = False + + if 'num_dashes' in kwargs: + self.num_dashes = kwargs['num_dashes'] + del kwargs['num_dashes'] + else: + self.num_dashes = 0 + + self.space_between_arg = " " + + # Not sure about this :( + # https://wiki.galaxyproject.org/Tools/BestPractices#Parameter_help + if 'label' in kwargs: + # TODO: replace with positional attribute + if len(self.flag()) > 0: + if kwargs['label'] is None: + kwargs[ + 'label'] = 'Author did not provide help for this parameter... ' + if not self.positional: + kwargs['argument'] = self.flag() + + super(InputParameter, self).__init__(**kwargs) + + def command_line(self): + before = self.command_line_before() + cli = self.command_line_actual() + after = self.command_line_after() + + complete = [x for x in (before, cli, after) if x is not None] + return '\n'.join(complete) + + def command_line_before(self): + try: + return self.command_line_before_override + except Exception: + return None + + def command_line_after(self): + try: + return self.command_line_after_override + except Exception: + return None + + def command_line_actual(self): + try: + return self.command_line_override + except Exception: + if self.positional: + return self.mako_name() + else: + return "%s%s%s" % (self.flag(), self.space_between_arg, self.mako_name()) + + def mako_name(self): + # TODO: enhance logic to check up parents for things like + # repeat>condotion>param + return '$' + self.mako_identifier + + def flag(self): + flag = '-' * self.num_dashes + return flag + self.mako_identifier + + +class Section(InputParameter): + name = 'section' + + def __init__(self, name, title, expanded=None, help=None, **kwargs): + params = Util.clean_kwargs(locals().copy()) + super(Section, self).__init__(**params) + + def acceptable_child(self, child): + return issubclass(type(child), InputParameter) + + +class Repeat(InputParameter): + name = 'repeat' + + def __init__(self, name, title, min=None, max=None, default=None, + **kwargs): + params = Util.clean_kwargs(locals().copy()) + # Allow overriding + self.command_line_before_override = '#for $i in $%s:' % name + self.command_line_after_override = '#end for' + # self.command_line_override + super(Repeat, self).__init__(**params) + + def acceptable_child(self, child): + return issubclass(type(child), InputParameter) + + def command_line_actual(self): + if hasattr(self, 'command_line_override'): + return self.command_line_override + else: + return "%s" % self.mako_name() + + +class Conditional(InputParameter): + name = 'conditional' + + def __init__(self, name, **kwargs): + params = Util.clean_kwargs(locals().copy()) + super(Conditional, self).__init__(**params) + + def acceptable_child(self, child): + return issubclass(type(child), InputParameter) \ + and not isinstance(child, Conditional) + + def validate(self): + # Find a way to check if one of the kids is a WHEN + pass + + +class When(InputParameter): + name = 'when' + + def __init__(self, value): + params = Util.clean_kwargs(locals().copy()) + super(When, self).__init__(None, **params) + + def acceptable_child(self, child): + return issubclass(type(child), InputParameter) + + +class Param(InputParameter): + name = 'param' + + # This...isn't really valid as-is, and shouldn't be used. + def __init__(self, name, optional=None, label=None, help=None, **kwargs): + params = Util.clean_kwargs(locals().copy()) + params['type'] = self.type + super(Param, self).__init__(**params) + + if type(self) == Param: + raise Exception( + "Param class is not an actual parameter type, use a subclass of Param") + + def acceptable_child(self, child): + return issubclass(type(child, InputParameter) or isinstance(child), ValidatorParam) + + +class TextParam(Param): + type = 'text' + + def __init__(self, name, optional=None, label=None, help=None, + value=None, **kwargs): + params = Util.clean_kwargs(locals().copy()) + super(TextParam, self).__init__(**params) + + def command_line_actual(self): + try: + return self.command_line_override + except Exception: + if self.positional: + return self.mako_name() + else: + return f"{self.flag}{self.space_between_arg}'{self.mako_name()}'" + + +class _NumericParam(Param): + + def __init__(self, name, value, optional=None, label=None, help=None, + min=None, max=None, **kwargs): + params = Util.clean_kwargs(locals().copy()) + super(_NumericParam, self).__init__(**params) + + +class IntegerParam(_NumericParam): + type = 'integer' + + +class FloatParam(_NumericParam): + type = 'float' + + +class BooleanParam(Param): + type = 'boolean' + + def __init__(self, name, optional=None, label=None, help=None, + checked=False, truevalue=None, falsevalue=None, **kwargs): + params = Util.clean_kwargs(locals().copy()) + + super(BooleanParam, self).__init__(**params) + if truevalue is None: + # If truevalue and falsevalue are None, then we use "auto", the IUC + # recommended default. + # + # truevalue is set to the parameter's value, and falsevalue is not. + # + # Unfortunately, mako_identifier is set as a result of the super + # call, which we shouldn't call TWICE, so we'll just hack around this :( + # params['truevalue'] = '%s%s' % (self.) + self.node.attrib['truevalue'] = self.flag() + + if falsevalue is None: + self.node.attrib['falsevalue'] = "" + + def command_line_actual(self): + if hasattr(self, 'command_line_override'): + return self.command_line_override + else: + return "%s" % self.mako_name() + + +class DataParam(Param): + type = 'data' + + def __init__(self, name, optional=None, label=None, help=None, format=None, + multiple=None, **kwargs): + params = Util.clean_kwargs(locals().copy()) + super(DataParam, self).__init__(**params) + + +class SelectParam(Param): + type = 'select' + + def __init__(self, name, optional=None, label=None, help=None, + data_ref=None, display=None, multiple=None, options=None, + default=None, **kwargs): + params = Util.clean_kwargs(locals().copy()) + del params['options'] + del params['default'] + + super(SelectParam, self).__init__(**params) + + if options is not None and default is not None: + if default not in options: + raise Exception("Specified a default that isn't in options") + + if options: + for k, v in list(sorted(options.items())): + selected = (k == default) + self.append(SelectOption(k, v, selected=selected)) + + def acceptable_child(self, child): + return issubclass(type(child), SelectOption) \ + or issubclass(type(child), Options) + + +class SelectOption(InputParameter): + name = 'option' + + def __init__(self, value, text, selected=False, **kwargs): + params = Util.clean_kwargs(locals().copy()) + + passed_kwargs = {} + if selected: + passed_kwargs['selected'] = "true" + passed_kwargs['value'] = params['value'] + + super(SelectOption, self).__init__(None, **passed_kwargs) + self.node.text = str(text) + + +class Options(InputParameter): + name = 'options' + + def __init__(self, from_dataset=None, from_file=None, from_data_table=None, + from_parameter=None, **kwargs): + params = Util.clean_kwargs(locals().copy()) + super(Options, self).__init__(None, **params) + + def acceptable_child(self, child): + return issubclass(type(child), Column) or issubclass(type(child), Filter) + + +class Column(InputParameter): + name = 'column' + + def __init__(self, name, index, **kwargs): + params = Util.clean_kwargs(locals().copy()) + super(Column, self).__init__(**params) + + +class Filter(InputParameter): + name = 'filter' + + def __init__(self, type, column=None, name=None, ref=None, key=None, + multiple=None, separator=None, keep=None, value=None, + ref_attribute=None, index=None, **kwargs): + params = Util.clean_kwargs(locals().copy()) + super(Filter, self).__init__(**params) + + +class ValidatorParam(InputParameter): + name = 'validator' + + def __init__(self, type, message=None, filename=None, metadata_name=None, + metadata_column=None, line_startswith=None, min=None, + max=None, **kwargs): + params = Util.clean_kwargs(locals().copy()) + super(ValidatorParam, self).__init__(**params) + + +class Outputs(XMLParam): + name = 'outputs' + + def acceptable_child(self, child): + return isinstance(child, OutputData) or isinstance(child, OutputCollection) + + +class OutputData(XMLParam): + """Copypasta of InputParameter, needs work + """ + name = 'data' + + def __init__(self, name, format, format_source=None, metadata_source=None, + label=None, from_work_dir=None, hidden=False, **kwargs): + # TODO: validate format_source&metadata_source against something in the + # XMLParam children tree. + self.mako_identifier = name + if 'num_dashes' in kwargs: + self.num_dashes = kwargs['num_dashes'] + del kwargs['num_dashes'] + else: + self.num_dashes = 0 + self.space_between_arg = " " + params = Util.clean_kwargs(locals().copy()) + + super(OutputData, self).__init__(**params) + + def command_line(self): + if hasattr(self, 'command_line_override'): + return self.command_line_override + else: + return "%s%s%s" % (self.flag(), self.space_between_arg, self.mako_name()) + + def mako_name(self): + return '$' + self.mako_identifier + + def flag(self): + flag = '-' * self.num_dashes + return flag + self.mako_identifier + + def acceptable_child(self, child): + return isinstance(child, OutputFilter) or \ + isinstance(child, ChangeFormat) or \ + isinstance(child, DiscoverDatasets) + + +class OutputFilter(XMLParam): + name = 'filter' + + def __init__(self, text, **kwargs): + params = Util.clean_kwargs(locals().copy()) + del params['text'] + super(OutputFilter, self).__init__(**params) + self.node.text = text + + def acceptable_child(self, child): + return False + + +class ChangeFormat(XMLParam): + name = 'change_format' + + def __init__(self, **kwargs): + params = Util.clean_kwargs(locals().copy()) + super(ChangeFormat, self).__init__(**params) + + def acceptable_child(self, child): + return isinstance(child, ChangeFormatWhen) + + +class ChangeFormatWhen(XMLParam): + name = 'when' + + def __init__(self, input, format, value, **kwargs): + params = Util.clean_kwargs(locals().copy()) + super(ChangeFormatWhen, self).__init__(**params) + + def acceptable_child(self, child): + return False + + +class OutputCollection(XMLParam): + name = 'collection' + + def __init__(self, name, type=None, label=None, format_source=None, + type_source=None, structured_like=None, inherit_format=None, **kwargs): + params = Util.clean_kwargs(locals().copy()) + super(OutputCollection, self).__init__(**params) + + def acceptable_child(self, child): + return isinstance(child, OutputData) or isinstance(child, OutputFilter) \ + or isinstance(child, DiscoverDatasets) + + +class DiscoverDatasets(XMLParam): + name = 'discover_datasets' + + def __init__(self, pattern, directory=None, format=None, ext=None, + visible=None, **kwargs): + params = Util.clean_kwargs(locals().copy()) + super(DiscoverDatasets, self).__init__(**params) + + +class Tests(XMLParam): + name = 'tests' + + def acceptable_child(self, child): + return issubclass(type(child), Test) + + +class Test(XMLParam): + name = 'test' + + def acceptable_child(self, child): + return isinstance(child, TestParam) or isinstance(child, TestOutput) + + +class TestParam(XMLParam): + name = 'param' + + def __init__(self, name, value=None, ftype=None, dbkey=None, **kwargs): + params = Util.clean_kwargs(locals().copy()) + super(TestParam, self).__init__(**params) + + +class TestOutput(XMLParam): + name = 'output' + + def __init__(self, name=None, file=None, ftype=None, sort=None, value=None, + md5=None, checksum=None, compare=None, lines_diff=None, + delta=None, **kwargs): + params = Util.clean_kwargs(locals().copy()) + super(TestOutput, self).__init__(**params) + + +class Citations(XMLParam): + name = 'citations' + + def acceptable_child(self, child): + return issubclass(type(child), Citation) + + def has_citation(self, type, value): + """ + Check the presence of a given citation. + + :type type: STRING + :type value: STRING + """ + for citation in self.children: + if citation.node.attrib['type'] == type and citation.node.text == value: + return True + return False + + +class Citation(XMLParam): + name = 'citation' + + def __init__(self, type, value): + passed_kwargs = {} + passed_kwargs['type'] = type + super(Citation, self).__init__(**passed_kwargs) + self.node.text = str(value)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toolfactory/sample_toolfactory_tools.ga Sat Aug 08 19:55:55 2020 -0400 @@ -0,0 +1,443 @@ +{ + "a_galaxy_workflow": "true", + "annotation": "", + "format-version": "0.1", + "name": "workflow to generate a bunch of sample toolfactory tools", + "steps": { + "0": { + "annotation": "", + "content_id": null, + "errors": null, + "id": 0, + "input_connections": {}, + "inputs": [ + { + "description": "", + "name": "rgToolFactory2.py" + } + ], + "label": "rgToolFactory2.py", + "name": "Input dataset", + "outputs": [], + "position": { + "bottom": 235.25, + "height": 81, + "left": 711.84375, + "right": 911.84375, + "top": 154.25, + "width": 200, + "x": 711.84375, + "y": 154.25 + }, + "tool_id": null, + "tool_state": "{\"optional\": false}", + "tool_version": null, + "type": "data_input", + "uuid": "b717b6ee-51d0-415d-876d-f19b42f67666", + "workflow_outputs": [ + { + "label": null, + "output_name": "output", + "uuid": "09acd6fd-4e2b-44a8-8757-35eca8d0de89" + } + ] + }, + "1": { + "annotation": "", + "content_id": null, + "errors": null, + "id": 1, + "input_connections": {}, + "inputs": [ + { + "description": "", + "name": "README.md" + } + ], + "label": "README.md", + "name": "Input dataset", + "outputs": [], + "position": { + "bottom": 760.25, + "height": 61, + "left": 711.84375, + "right": 911.84375, + "top": 699.25, + "width": 200, + "x": 711.84375, + "y": 699.25 + }, + "tool_id": null, + "tool_state": "{\"optional\": false}", + "tool_version": null, + "type": "data_input", + "uuid": "8aefae07-4fd1-44a6-bea2-5d377567ac27", + "workflow_outputs": [ + { + "label": null, + "output_name": "output", + "uuid": "5f8453d0-abd1-41d9-a4a7-1f8b82f1f095" + } + ] + }, + "2": { + "annotation": "", + "content_id": null, + "errors": null, + "id": 2, + "input_connections": {}, + "inputs": [ + { + "description": "", + "name": "testtext" + } + ], + "label": "testtext", + "name": "Input dataset", + "outputs": [], + "position": { + "bottom": 235.25, + "height": 61, + "left": 989.84375, + "right": 1189.84375, + "top": 174.25, + "width": 200, + "x": 989.84375, + "y": 174.25 + }, + "tool_id": null, + "tool_state": "{\"optional\": false}", + "tool_version": null, + "type": "data_input", + "uuid": "02a35533-a67b-44c0-bce8-96a8adddc5a9", + "workflow_outputs": [ + { + "label": null, + "output_name": "output", + "uuid": "abe4a1b1-2c0b-44d1-95f8-4f9bb38e9daa" + } + ] + }, + "3": { + "annotation": "", + "content_id": "rgTF2", + "errors": null, + "id": 3, + "input_connections": { + "ppass|history_inputs_0|input_files": { + "id": 1, + "output_name": "output" + } + }, + "inputs": [], + "label": null, + "name": "toolfactory", + "outputs": [ + { + "name": "ToolFactory_Outputs", + "type": "input" + }, + { + "name": "new_tool", + "type": "tgz" + } + ], + "position": { + "bottom": 636.25, + "height": 222, + "left": 989.84375, + "right": 1189.84375, + "top": 414.25, + "width": 200, + "x": 989.84375, + "y": 414.25 + }, + "post_job_actions": {}, + "tool_id": "rgTF2", + "tool_state": "{\"__input_ext\": \"txt\", \"chromInfo\": \"/home/ross/galaxy/tool-data/shared/ucsc/chrom/?.len\", \"interexe\": {\"interpreter\": \"bash\", \"__current_case__\": 5, \"interpreter_version\": \"\", \"exe_package_version\": \"\", \"dynScript\": \"rev | tac\"}, \"makeMode\": {\"make_Tool\": \"yes\", \"__current_case__\": 0, \"tool_version\": \"0.01\", \"tool_desc\": \"tacrev\", \"help_text\": \"**What it Does**\", \"citations\": []}, \"ppass\": {\"parampass\": \"0\", \"__current_case__\": 2, \"history_inputs\": [{\"__index__\": 0, \"input_files\": {\"__class__\": \"ConnectedValue\"}, \"input_formats\": [\"txt\"], \"input_label\": \"input file\", \"input_help\": \"parameter_help\", \"input_CL\": \"1\"}], \"history_outputs\": [{\"__index__\": 0, \"history_name\": \"outfile\", \"history_format\": \"txt\", \"history_CL\": \"2\"}]}, \"tool_name\": \"tacrev\", \"__page__\": null, \"__rerun_remap_job_id__\": null}", + "tool_version": "2.00", + "type": "tool", + "uuid": "8fab16a0-5303-4e5c-8bf6-d6ebc70aa9af", + "workflow_outputs": [ + { + "label": null, + "output_name": "ToolFactory_Outputs", + "uuid": "68d1a0b8-d897-48e9-a304-25d289e139e9" + }, + { + "label": null, + "output_name": "new_tool", + "uuid": "8669863e-a1a5-4ed6-a412-c7f341f66176" + } + ] + }, + "4": { + "annotation": "", + "content_id": "rgTF2", + "errors": null, + "id": 4, + "input_connections": { + "ppass|history_inputs_0|input_files": { + "id": 1, + "output_name": "output" + } + }, + "inputs": [], + "label": null, + "name": "toolfactory", + "outputs": [ + { + "name": "ToolFactory_Outputs", + "type": "input" + }, + { + "name": "new_tool", + "type": "tgz" + } + ], + "position": { + "bottom": 916.25, + "height": 242, + "left": 989.84375, + "right": 1189.84375, + "top": 674.25, + "width": 200, + "x": 989.84375, + "y": 674.25 + }, + "post_job_actions": {}, + "tool_id": "rgTF2", + "tool_state": "{\"__input_ext\": \"txt\", \"chromInfo\": \"/home/ross/galaxy/tool-data/shared/ucsc/chrom/?.len\", \"interexe\": {\"interpreter\": \"python\", \"__current_case__\": 2, \"interpreter_version\": \"\", \"exe_package_version\": \"\", \"dynScript\": \"# reverse order of text by row\\nimport sys\\ninp = sys.argv[1]\\noutp = sys.argv[2]\\ni = open(inp,'r').readlines()\\no = open(outp,'w')\\nfor row in i:\\n rs = row.rstrip()\\n rs = list(rs)\\n rs.reverse()\\n o.write(''.join(rs))\\n o.write('\\\\n')\\no.close()\"}, \"makeMode\": {\"make_Tool\": \"yes\", \"__current_case__\": 0, \"tool_version\": \"0.01\", \"tool_desc\": \"pyrevpos\", \"help_text\": \"**What it Does**\", \"citations\": []}, \"ppass\": {\"parampass\": \"positional\", \"__current_case__\": 1, \"history_inputs\": [{\"__index__\": 0, \"input_files\": {\"__class__\": \"ConnectedValue\"}, \"input_formats\": [\"txt\"], \"input_label\": \"inputfile\", \"input_help\": \"parameter_help\", \"input_CL\": \"1\"}], \"history_outputs\": [{\"__index__\": 0, \"history_name\": \"output\", \"history_format\": \"txt\", \"history_CL\": \"2\"}], \"edit_params\": \"yes\", \"additional_parameters\": []}, \"tool_name\": \"pyrevpos\", \"__page__\": null, \"__rerun_remap_job_id__\": null}", + "tool_version": "2.00", + "type": "tool", + "uuid": "ea0f8bbe-6b0d-4aff-bf06-6192faf8fe22", + "workflow_outputs": [ + { + "label": null, + "output_name": "ToolFactory_Outputs", + "uuid": "70755c1b-6f92-43a3-aacb-8cc508a89b74" + }, + { + "label": null, + "output_name": "new_tool", + "uuid": "ea9482d9-7836-442d-b753-ce4a201fd8c9" + } + ] + }, + "5": { + "annotation": "", + "content_id": "rgTF2", + "errors": null, + "id": 5, + "input_connections": { + "ppass|history_inputs_0|input_files": { + "id": 1, + "output_name": "output" + } + }, + "inputs": [], + "label": null, + "name": "toolfactory", + "outputs": [ + { + "name": "ToolFactory_Outputs", + "type": "input" + }, + { + "name": "new_tool", + "type": "tgz" + } + ], + "position": { + "bottom": 1216.25, + "height": 262, + "left": 989.84375, + "right": 1189.84375, + "top": 954.25, + "width": 200, + "x": 989.84375, + "y": 954.25 + }, + "post_job_actions": {}, + "tool_id": "rgTF2", + "tool_state": "{\"__input_ext\": \"txt\", \"chromInfo\": \"/home/ross/galaxy/tool-data/shared/ucsc/chrom/?.len\", \"interexe\": {\"interpreter\": \"python\", \"__current_case__\": 2, \"interpreter_version\": \"\", \"exe_package_version\": \"\", \"dynScript\": \"# reverse order of text by row\\nimport sys\\nimport argparse\\nparser = argparse.ArgumentParser()\\na = parser.add_argument\\na('--infile',default='')\\na('--outfile',default=None)\\nargs = parser.parse_args()\\ninp = args.infile\\noutp = args.outfile\\ni = open(inp,'r').readlines()\\no = open(outp,'w')\\nfor row in i:\\n rs = row.rstrip()\\n rs = list(rs)\\n rs.reverse()\\n o.write(''.join(rs))\\n o.write('\\\\n')\\no.close()\"}, \"makeMode\": {\"make_Tool\": \"yes\", \"__current_case__\": 0, \"tool_version\": \"0.01\", \"tool_desc\": \"reverse argparse\", \"help_text\": \"**What it Does**\", \"citations\": []}, \"ppass\": {\"parampass\": \"argparse\", \"__current_case__\": 0, \"history_inputs\": [{\"__index__\": 0, \"input_files\": {\"__class__\": \"ConnectedValue\"}, \"input_formats\": [\"txt\"], \"input_label\": \"infile\", \"input_help\": \"parameter_help\", \"input_CL\": \"infile\"}], \"history_outputs\": [{\"__index__\": 0, \"history_name\": \"outfile\", \"history_format\": \"txt\", \"history_CL\": \"outfile\"}], \"edit_params\": \"yes\", \"additional_parameters\": []}, \"tool_name\": \"pyrevargparse\", \"__page__\": null, \"__rerun_remap_job_id__\": null}", + "tool_version": "2.00", + "type": "tool", + "uuid": "065b274a-ae73-43b0-b015-8b60d90db78f", + "workflow_outputs": [ + { + "label": null, + "output_name": "ToolFactory_Outputs", + "uuid": "bec62d2d-b462-49bb-9646-28fea9136778" + }, + { + "label": null, + "output_name": "new_tool", + "uuid": "2e1ed464-bcff-4354-8bf3-ed01167b280f" + } + ] + }, + "6": { + "annotation": "", + "content_id": "rgTF2", + "errors": null, + "id": 6, + "input_connections": { + "ppass|history_inputs_0|input_files": { + "id": 1, + "output_name": "output" + } + }, + "inputs": [], + "label": null, + "name": "toolfactory", + "outputs": [ + { + "name": "ToolFactory_Outputs", + "type": "input" + }, + { + "name": "new_tool", + "type": "tgz" + } + ], + "position": { + "bottom": 1496.25, + "height": 242, + "left": 989.84375, + "right": 1189.84375, + "top": 1254.25, + "width": 200, + "x": 989.84375, + "y": 1254.25 + }, + "post_job_actions": {}, + "tool_id": "rgTF2", + "tool_state": "{\"__input_ext\": \"txt\", \"chromInfo\": \"/home/ross/galaxy/tool-data/shared/ucsc/chrom/?.len\", \"interexe\": {\"interpreter\": \"python\", \"__current_case__\": 2, \"interpreter_version\": \"\", \"exe_package_version\": \"\", \"dynScript\": \"# reverse order of text by row\\nimport sys\\ninp = sys.argv[1]\\noutp = sys.argv[2]\\nappendme = sys.argv[3]\\ni = open(inp,'r').readlines()\\no = open(outp,'w')\\nfor row in i:\\n rs = row.rstrip()\\n rs = list(rs)\\n rs.reverse()\\n o.write(''.join(rs))\\n o.write(appendme)\\n o.write('\\\\n')\\no.close()\"}, \"makeMode\": {\"make_Tool\": \"yes\", \"__current_case__\": 0, \"tool_version\": \"0.01\", \"tool_desc\": \"pyrevpos\", \"help_text\": \"**What it Does**\", \"citations\": []}, \"ppass\": {\"parampass\": \"positional\", \"__current_case__\": 1, \"history_inputs\": [{\"__index__\": 0, \"input_files\": {\"__class__\": \"ConnectedValue\"}, \"input_formats\": [\"txt\"], \"input_label\": \"inputfile\", \"input_help\": \"parameter_help\", \"input_CL\": \"1\"}], \"history_outputs\": [{\"__index__\": 0, \"history_name\": \"output\", \"history_format\": \"txt\", \"history_CL\": \"2\"}], \"edit_params\": \"yes\", \"additional_parameters\": [{\"__index__\": 0, \"param_name\": \"appendme\", \"param_type\": \"text\", \"param_value\": \"added at the end\", \"param_label\": \"append string\", \"param_help\": \"parameter_help\", \"param_CL\": \"3\"}]}, \"tool_name\": \"pyrevaddpos\", \"__page__\": null, \"__rerun_remap_job_id__\": null}", + "tool_version": "2.00", + "type": "tool", + "uuid": "5954323f-4ca1-4957-8250-746703dfa7c5", + "workflow_outputs": [ + { + "label": null, + "output_name": "ToolFactory_Outputs", + "uuid": "6466bf24-51b2-4fae-aac8-fc1d78faac89" + }, + { + "label": null, + "output_name": "new_tool", + "uuid": "f37589e2-3582-4443-bce8-5759485a7220" + } + ] + }, + "7": { + "annotation": "", + "content_id": "rgTF2", + "errors": null, + "id": 7, + "input_connections": { + "ppass|history_inputs_0|input_files": { + "id": 2, + "output_name": "output" + } + }, + "inputs": [], + "label": null, + "name": "toolfactory", + "outputs": [ + { + "name": "ToolFactory_Outputs", + "type": "input" + }, + { + "name": "new_tool", + "type": "tgz" + } + ], + "position": { + "bottom": 376.25, + "height": 222, + "left": 1267.84375, + "right": 1467.84375, + "top": 154.25, + "width": 200, + "x": 1267.84375, + "y": 154.25 + }, + "post_job_actions": {}, + "tool_id": "rgTF2", + "tool_state": "{\"__input_ext\": \"txt\", \"chromInfo\": \"/home/ross/galaxy/tool-data/shared/ucsc/chrom/?.len\", \"interexe\": {\"interpreter\": \"system\", \"__current_case__\": 1, \"exe_package\": \"sed\", \"exe_package_version\": \"\"}, \"makeMode\": {\"make_Tool\": \"yes\", \"__current_case__\": 0, \"tool_version\": \"0.01\", \"tool_desc\": \"sed runner\", \"help_text\": \"sed '/old/new/g input.txt\", \"citations\": []}, \"ppass\": {\"parampass\": \"positional\", \"__current_case__\": 1, \"history_inputs\": [{\"__index__\": 0, \"input_files\": {\"__class__\": \"ConnectedValue\"}, \"input_formats\": [\"txt\"], \"input_label\": \"input text\", \"input_help\": \"parameter_help\", \"input_CL\": \"3\"}], \"history_outputs\": [{\"__index__\": 0, \"history_name\": \"output\", \"history_format\": \"txt\", \"history_CL\": \"STDOUT\"}], \"edit_params\": \"yes\", \"additional_parameters\": [{\"__index__\": 0, \"param_name\": \"sedstring\", \"param_type\": \"text\", \"param_value\": \"s/Old/New/g\", \"param_label\": \"parameter_label\", \"param_help\": \"parameter_help\", \"param_CL\": \"1\"}]}, \"tool_name\": \"sedtest\", \"__page__\": null, \"__rerun_remap_job_id__\": null}", + "tool_version": "2.00", + "type": "tool", + "uuid": "e26df7b6-3899-42fb-8efc-5f13d53668f8", + "workflow_outputs": [ + { + "label": null, + "output_name": "ToolFactory_Outputs", + "uuid": "0a819390-acd4-4be6-aac9-ec3322302b0f" + }, + { + "label": null, + "output_name": "new_tool", + "uuid": "f7555059-144d-4f64-a303-b70d189e6e35" + } + ] + }, + "8": { + "annotation": "", + "content_id": "rgTF2", + "errors": null, + "id": 8, + "input_connections": { + "ppass|history_inputs_0|input_files": { + "id": 5, + "output_name": "new_tool" + } + }, + "inputs": [], + "label": null, + "name": "toolfactory", + "outputs": [ + { + "name": "ToolFactory_Outputs", + "type": "input" + }, + { + "name": "new_tool", + "type": "tgz" + } + ], + "position": { + "bottom": 1271.25, + "height": 242, + "left": 1267.84375, + "right": 1467.84375, + "top": 1029.25, + "width": 200, + "x": 1267.84375, + "y": 1029.25 + }, + "post_job_actions": {}, + "tool_id": "rgTF2", + "tool_state": "{\"__input_ext\": \"tgz\", \"chromInfo\": \"/home/ross/galaxy/tool-data/shared/ucsc/chrom/?.len\", \"interexe\": {\"interpreter\": \"python\", \"__current_case__\": 2, \"interpreter_version\": \"\", \"exe_package_version\": \"\", \"dynScript\": \"import argparse\\nimport tarfile\\nimport os\\nimport tempfile\\nimport subprocess\\n\\n\\\"\\\"\\\"\\nplanemo test --no_cleanup --no_dependency_resolution --skip_venv --galaxy_root ~/galaxy ~/galaxy/tools/tool_makers/pyrevargparse/ &> pyrevargparse\\n\\\"\\\"\\\"\\n\\nparser = argparse.ArgumentParser()\\na = parser.add_argument\\na('--tooltgz',default='')\\na('--report',default=None)\\na('--toolout',default=None)\\na('--galaxy_root',default=None)\\nargs = parser.parse_args()\\ntoolname = args.toolout.split(os.sep)[-1]\\ntoolpath = os.path.join(args.galaxy_root,args.toolout)\\ntf = tarfile.open(args.tooltgz,\\\"r:gz\\\")\\ntf.extractall(toolpath)\\ncl = \\\"planemo test --skip_venv --galaxy_root %s %s\\\" % (args.galaxy_root,toolpath)\\ncll = cl.split(' ')\\nsto = open(args.report, 'w')\\np = subprocess.run(cll, shell=False, stdout=sto)\\nretval = p.returncode\\nsto.close()\\n\"}, \"makeMode\": {\"make_Tool\": \"yes\", \"__current_case__\": 0, \"tool_version\": \"0.01\", \"tool_desc\": \"Tool to test toolshed tool archives generated by the tool factory.\", \"help_text\": \"**What it Does**\\n\\nGiven a toolshed tgz file generated by a tool factory run, this will unpack it and run planemo test, returning the planemo stdout as a report\\nIt was generated using the tool factory.\", \"citations\": []}, \"ppass\": {\"parampass\": \"argparse\", \"__current_case__\": 0, \"history_inputs\": [{\"__index__\": 0, \"input_files\": {\"__class__\": \"ConnectedValue\"}, \"input_formats\": [\"tgz\"], \"input_label\": \"tool toolshed tgz archive from history\", \"input_help\": \"Run planemo test on a tool shed tool archive tgz format file generated by the ToolFactory or Planemo\", \"input_CL\": \"tooltgz\"}], \"history_outputs\": [{\"__index__\": 0, \"history_name\": \"report\", \"history_format\": \"txt\", \"history_CL\": \"report\"}], \"edit_params\": \"yes\", \"additional_parameters\": [{\"__index__\": 0, \"param_name\": \"toolout\", \"param_type\": \"text\", \"param_value\": \"tools/toolmakers/planemotest\", \"param_label\": \"output path under galaxy root\", \"param_help\": \"This is where the tgz file will be extracted and tested by planemo\", \"param_CL\": \"toolout\"}, {\"__index__\": 1, \"param_name\": \"galaxy_root\", \"param_type\": \"text\", \"param_value\": \"/home/ross/galaxy\", \"param_label\": \"your galaxy root to use for running planemo\", \"param_help\": \"This will form the galaxy_root parameter for running planemo using an existing Galaxy source tree, and the tgz will be extracted at a path relative to that root\", \"param_CL\": \"galaxy_root\"}]}, \"tool_name\": \"planemotest\", \"__page__\": null, \"__rerun_remap_job_id__\": null}", + "tool_version": "2.00", + "type": "tool", + "uuid": "c72a7aae-3801-431b-a331-be6938d34fbd", + "workflow_outputs": [ + { + "label": null, + "output_name": "ToolFactory_Outputs", + "uuid": "75aa9815-5bd6-44a7-8210-889d3b7e5027" + }, + { + "label": null, + "output_name": "new_tool", + "uuid": "744499de-5d7e-4415-b427-315057c81ebc" + } + ] + } + }, + "tags": [], + "uuid": "490d9c7f-eea3-4616-a8b7-13510da0430b", + "version": 1 +}