changeset 36:ce2b1f8ea68d draft

passes flake8 tests finally :)
author fubar
date Mon, 10 Aug 2020 23:24:41 -0400
parents 5d38cb3d9be8
children 099047ee7094
files toolfactory/galaxyxml/__init__.py toolfactory/galaxyxml/tool/__init__.py toolfactory/galaxyxml/tool/import_xml.py toolfactory/galaxyxml/tool/parameters/__init__.py toolfactory/rgToolFactory2.py toolfactory/rgToolFactory2.xml toolfactory/sample_toolfactory_tools.ga toolfactory/sample_toolfactory_tools.tgz toolfactory/tf_tests_history.tar.gz toolfactory/tfwfsample.tgz toolfactory/tfworkflowsample.ga
diffstat 11 files changed, 1793 insertions(+), 1077 deletions(-) [+]
line wrap: on
line diff
--- a/toolfactory/galaxyxml/__init__.py	Sat Aug 08 19:55:55 2020 -0400
+++ b/toolfactory/galaxyxml/__init__.py	Mon Aug 10 23:24:41 2020 -0400
@@ -4,23 +4,24 @@
 
 
 class GalaxyXML(object):
-
     def __init__(self):
-        self.root = etree.Element('root')
+        self.root = etree.Element("root")
 
     def export(self):
-        return etree.tostring(self.root, pretty_print=True, encoding='unicode')
+        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}
+            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])
@@ -45,22 +46,22 @@
 
     @classmethod
     def clean_kwargs(cls, params, final=False):
-        if 'kwargs' in params:
-            kwargs = params['kwargs']
+        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']
+            del params["kwargs"]
+        if "self" in params:
+            del params["self"]
 
-        if '__class__' in params:
-            del params['__class__']
+        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',):
+            for blacklist in ("positional",):
                 if blacklist in params:
                     del params[blacklist]
         return params
--- a/toolfactory/galaxyxml/tool/__init__.py	Sat Aug 08 19:55:55 2020 -0400
+++ b/toolfactory/galaxyxml/tool/__init__.py	Mon Aug 10 23:24:41 2020 -0400
@@ -4,56 +4,68 @@
 from galaxyxml import Util, GalaxyXML
 from galaxyxml.tool.parameters import XMLParam
 
-VALID_TOOL_TYPES = ('data_source', 'data_source_async')
-VALID_URL_METHODS = ('get', 'post')
+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):
+    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,
+            "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']
+            del kwargs["hidden"]
         if workflow_compatible:
-            del kwargs['workflow_compatible']
+            del kwargs["workflow_compatible"]
 
         kwargs = Util.coerce(kwargs)
-        self.root = etree.Element('tool', **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))
+                raise Exception(
+                    "Tool type must be one of %s" % ",".join(VALID_TOOL_TYPES)
+                )
             else:
-                kwargs['tool_type'] = tool_type
+                kwargs["tool_type"] = tool_type
 
                 if URL_method is not None:
                     if URL_method in VALID_URL_METHODS:
-                        kwargs['URL_method'] = URL_method
+                        kwargs["URL_method"] = URL_method
                     else:
-                        raise Exception("URL_method must be one of %s" %
-                                        ','.join(VALID_URL_METHODS))
+                        raise Exception(
+                            "URL_method must be one of %s" % ",".join(VALID_URL_METHODS)
+                        )
 
-        description_node = etree.SubElement(self.root, 'description')
+        description_node = etree.SubElement(self.root, "description")
         description_node.text = description
 
     def add_comment(self, comment_txt):
@@ -61,7 +73,7 @@
         self.root.insert(0, comment)
 
     def append_version_command(self):
-        version_command = etree.SubElement(self.root, 'version_command')
+        version_command = etree.SubElement(self.root, "version_command")
         try:
             version_command.text = etree.CDATA(self.version_command)
         except Exception:
@@ -76,10 +88,10 @@
     def clean_command_string(self, command_line):
         clean = []
         for x in command_line:
-            if x is not [] and x is not ['']:
+            if x is not [] and x is not [""]:
                 clean.append(x)
 
-        return '\n'.join(clean)
+        return "\n".join(clean)
 
     def export(self, keep_old_command=False):  # noqa
 
@@ -105,7 +117,7 @@
         except Exception:
             pass
 
-        if self.command_line_override != None:
+        if self.command_line_override:
             command_line = self.command_line_override
         else:
             command_line = []
@@ -120,8 +132,8 @@
                 pass
 
         # Add stdio section
-        stdio = etree.SubElement(export_xml.root, 'stdio')
-        etree.SubElement(stdio, 'exit_code', range='1:', level='fatal')
+        stdio = etree.SubElement(export_xml.root, "stdio")
+        etree.SubElement(stdio, "exit_code", range="1:", level="fatal")
 
         # Append version command
         export_xml.append_version_command()
@@ -129,21 +141,25 @@
         # Steal interpreter from kwargs
         command_kwargs = {}
         if export_xml.interpreter is not None:
-            command_kwargs['interpreter'] = export_xml.interpreter
+            command_kwargs["interpreter"] = export_xml.interpreter
 
         # Add command section
-        command_node = etree.SubElement(export_xml.root, 'command', **command_kwargs)
+        command_node = etree.SubElement(export_xml.root, "command", **command_kwargs)
 
         if keep_old_command:
-            if getattr(self, 'command', None):
+            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.')
+                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))
+                export_xml.executable,
+                export_xml.clean_command_string(command_line),
+            )
             command_node.text = etree.CDATA(actual_cli.strip())
 
         try:
@@ -161,7 +177,7 @@
         except Exception:
             pass
 
-        help_element = etree.SubElement(export_xml.root, 'help')
+        help_element = etree.SubElement(export_xml.root, "help")
         help_element.text = etree.CDATA(export_xml.help)
 
         try:
--- a/toolfactory/galaxyxml/tool/import_xml.py	Sat Aug 08 19:55:55 2020 -0400
+++ b/toolfactory/galaxyxml/tool/import_xml.py	Mon Aug 10 23:24:41 2020 -0400
@@ -22,24 +22,26 @@
         version_cmd = None
         description = None
         for child in xml_root:
-            if child.tag == 'description':
+            if child.tag == "description":
                 description = child.text
-            elif child.tag == 'command':
+            elif child.tag == "command":
                 executable = child.text.split()[0]
                 command = child.text
-            elif child.tag == 'version_command':
+            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 = 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
 
@@ -109,15 +111,17 @@
         """
         tool.requirements = gxtp.Requirements()
         for req in requirements_root:
-            req_type = req.attrib['type']
+            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':
+            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')
+                logger.warning(req.tag + " is not a valid tag for requirements child")
 
     def _load_edam_topics(self, tool, topics_root):
         """
@@ -156,7 +160,7 @@
         """
         tool.configfiles = gxtp.Configfiles()
         for conf in configfiles_root:
-            name = conf.attrib['name']
+            name = conf.attrib["name"]
             value = conf.text
             tool.configfiles.append(gxtp.Configfile(name, value))
 
@@ -171,7 +175,7 @@
         """
         tool.citations = gxtp.Citations()
         for cit in citations_root:
-            cit_type = cit.attrib['type']
+            cit_type = cit.attrib["type"]
             value = cit.text
             tool.citations.append(gxtp.Citation(cit_type, value))
 
@@ -228,7 +232,7 @@
         # Now we import each tag's field
         for child in xml_root:
             try:
-                getattr(self, '_load_{}'.format(child.tag))(tool, child)
+                getattr(self, "_load_{}".format(child.tag))(tool, child)
             except AttributeError:
                 logger.warning(child.tag + " tag is not processed.")
         return tool
@@ -247,11 +251,15 @@
         :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)))
+        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):
         """
@@ -261,12 +269,16 @@
         :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)))
+        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):
         """
@@ -276,13 +288,17 @@
         :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)))
+        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):
         """
@@ -292,13 +308,17 @@
         :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)))
+        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):
         """
@@ -308,13 +328,17 @@
         :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)))
+        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):
         """
@@ -324,9 +348,13 @@
         :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)))
+        root.append(
+            gxtp.SelectOption(
+                option.attrib.get("value", None),
+                option.text,
+                selected=option.attrib.get("selected", False),
+            )
+        )
 
     def _load_column_options(self, root, column):
         """
@@ -336,7 +364,7 @@
         :param option: root of <column> tag.
         :type float_param: :class:`xml.etree._Element`
         """
-        root.append(gxtp.Column(column.attrib['name'], column.attrib['index']))
+        root.append(gxtp.Column(column.attrib["name"], column.attrib["index"]))
 
     def _load_filter_options(self, root, filter):
         """
@@ -346,17 +374,21 @@
         :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)))
+        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):
         """
@@ -366,14 +398,16 @@
         :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))
+        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)
+                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)
@@ -386,19 +420,25 @@
         :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))
+        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)
+                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'>.")
+                logger.warning(
+                    sel_child.tag + " tag is not processed for <param type='select'>."
+                )
         root.append(select_param)
 
     def _load_param(self, root, param_root):
@@ -409,9 +449,9 @@
         :param param_root: root of <param> tag.
         :type param_root: :class:`xml.etree._Element`
         """
-        param_type = param_root.attrib['type']
+        param_type = param_root.attrib["type"]
         try:
-            getattr(self, '_load_{}_param'.format(param_type))(root, param_root)
+            getattr(self, "_load_{}_param".format(param_type))(root, param_root)
         except AttributeError:
             logger.warning(param_type + " tag is not processed for <param>.")
 
@@ -423,7 +463,7 @@
         :param when_root: root of <when> tag.
         :type when_root: :class:`xml.etree._Element`
         """
-        when = gxtp.When(when_root.attrib['value'])
+        when = gxtp.When(when_root.attrib["value"])
         # Deal with child nodes
         self.load_inputs(when, when_root)
         root.append(when)
@@ -436,13 +476,15 @@
         :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)
+        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))
+        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)
@@ -455,10 +497,12 @@
         :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))
+        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)
@@ -471,11 +515,13 @@
         :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))
+        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)
@@ -491,10 +537,14 @@
         """
         for inp_child in inputs_root:
             try:
-                getattr(self, '_load_{}'.format(inp_child.tag))(root, inp_child)
+                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.")
+                logger.warning(
+                    inp_child.tag
+                    + " tag is not processed for <"
+                    + inputs_root.tag
+                    + "> tag."
+                )
 
 
 class OutputsParser(object):
@@ -510,17 +560,19 @@
         :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))
+        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)
+                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)
@@ -535,9 +587,13 @@
         """
         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']))
+            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):
@@ -548,22 +604,23 @@
         :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))
+        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)
+                getattr(self, "_load_{}".format(coll_child.tag))(collection, coll_child)
             except AttributeError:
-                logger.warning(coll_child.tag + " tag is not processed for <collection>.")
+                logger.warning(
+                    coll_child.tag + " tag is not processed for <collection>."
+                )
         outputs_root.append(collection)
 
     def _load_discover_datasets(self, root, disc_root):
@@ -574,11 +631,15 @@
         :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)))
+        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):
         """
@@ -600,7 +661,7 @@
         """
         for out_child in outputs_root:
             try:
-                getattr(self, '_load_{}'.format(out_child.tag))(root, out_child)
+                getattr(self, "_load_{}".format(out_child.tag))(root, out_child)
             except AttributeError:
                 logger.warning(out_child.tag + " tag is not processed for <outputs>.")
 
@@ -618,10 +679,14 @@
         :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)))
+        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):
         """
@@ -631,16 +696,20 @@
         :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)))
+        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):
         """
@@ -654,7 +723,9 @@
             test = gxtp.Test()
             for test_child in test_root:
                 try:
-                    getattr(self, '_load_{}'.format(test_child.tag))(test, test_child)
+                    getattr(self, "_load_{}".format(test_child.tag))(test, test_child)
                 except AttributeError:
-                    logger.warning(test_child.tag + " tag is not processed within <test>.")
+                    logger.warning(
+                        test_child.tag + " tag is not processed within <test>."
+                    )
             root.append(test)
--- a/toolfactory/galaxyxml/tool/parameters/__init__.py	Sat Aug 08 19:55:55 2020 -0400
+++ b/toolfactory/galaxyxml/tool/parameters/__init__.py	Mon Aug 10 23:24:41 2020 -0400
@@ -5,7 +5,7 @@
 
 
 class XMLParam(object):
-    name = 'node'
+    name = "node"
 
     def __init__(self, *args, **kwargs):
         # http://stackoverflow.com/a/12118700
@@ -22,11 +22,15 @@
                 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)))
+                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)))
+            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
@@ -42,14 +46,14 @@
         for child in self.children:
             lines.append(child.command_line())
             # lines += child.command_line()
-        return '\n'.join(lines)
+        return "\n".join(lines)
 
     def command_line(self):
         return None
 
 
 class RequestParamTranslation(XMLParam):
-    name = 'request_param_translation'
+    name = "request_param_translation"
 
     def __init__(self, **kwargs):
         self.node = etree.Element(self.name)
@@ -59,7 +63,7 @@
 
 
 class RequestParam(XMLParam):
-    name = 'request_param'
+    name = "request_param"
 
     def __init__(self, galaxy_name, remote_name, missing, **kwargs):
         # TODO: bulk copy locals into self.attr?
@@ -73,7 +77,7 @@
 
 
 class AppendParam(XMLParam):
-    name = 'append_param'
+    name = "append_param"
 
     def __init__(self, separator="&amp;", first_separator="?", join="=", **kwargs):
         params = Util.clean_kwargs(locals().copy())
@@ -84,7 +88,7 @@
 
 
 class AppendParamValue(XMLParam):
-    name = 'value'
+    name = "value"
 
     def __init__(self, name="_export", missing="1", **kwargs):
         params = Util.clean_kwargs(locals().copy())
@@ -95,7 +99,7 @@
 
 
 class EdamOperations(XMLParam):
-    name = 'edam_operations'
+    name = "edam_operations"
 
     def acceptable_child(self, child):
         return issubclass(type(child), EdamOperation)
@@ -113,7 +117,7 @@
 
 
 class EdamOperation(XMLParam):
-    name = 'edam_operation'
+    name = "edam_operation"
 
     def __init__(self, value):
         super(EdamOperation, self).__init__()
@@ -121,7 +125,7 @@
 
 
 class EdamTopics(XMLParam):
-    name = 'edam_topics'
+    name = "edam_topics"
 
     def acceptable_child(self, child):
         return issubclass(type(child), EdamTopic)
@@ -139,7 +143,7 @@
 
 
 class EdamTopic(XMLParam):
-    name = 'edam_topic'
+    name = "edam_topic"
 
     def __init__(self, value):
         super(EdamTopic, self).__init__()
@@ -147,70 +151,81 @@
 
 
 class Requirements(XMLParam):
-    name = 'requirements'
+    name = "requirements"
     # This bodes to be an issue -__-
 
     def acceptable_child(self, child):
-        return issubclass(type(child), Requirement) or issubclass(type(child), Container)
+        return issubclass(type(child), Requirement) or issubclass(
+            type(child), Container
+        )
 
 
 class Requirement(XMLParam):
-    name = 'requirement'
+    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']
+        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'
+    name = "container"
 
     def __init__(self, type, value, **kwargs):
         params = Util.clean_kwargs(locals().copy())
         passed_kwargs = {}
-        passed_kwargs['type'] = params['type']
+        passed_kwargs["type"] = params["type"]
         super(Container, self).__init__(**passed_kwargs)
         self.node.text = str(value)
 
 
 class Configfiles(XMLParam):
-    name = 'configfiles'
+    name = "configfiles"
 
     def acceptable_child(self, child):
-        return issubclass(type(child), Configfile) or issubclass(type(child), ConfigfileDefaultInputs)
+        return issubclass(type(child), Configfile) or issubclass(
+            type(child), ConfigfileDefaultInputs
+        )
 
 
 class Configfile(XMLParam):
-    name = 'configfile'
+    name = "configfile"
 
     def __init__(self, name, text, **kwargs):
         params = Util.clean_kwargs(locals().copy())
         passed_kwargs = {}
-        passed_kwargs['name'] = params['name']
+        passed_kwargs["name"] = params["name"]
         super(Configfile, self).__init__(**passed_kwargs)
         self.node.text = etree.CDATA(str(text))
 
 
 class ConfigfileDefaultInputs(XMLParam):
-    name = 'inputs'
+    name = "inputs"
 
     def __init__(self, name, **kwargs):
         params = Util.clean_kwargs(locals().copy())
         passed_kwargs = {}
-        passed_kwargs['name'] = params['name']
+        passed_kwargs["name"] = params["name"]
         super(ConfigfileDefaultInputs, self).__init__(**passed_kwargs)
 
 
 class Inputs(XMLParam):
-    name = 'inputs'
+    name = "inputs"
     # This bodes to be an issue -__-
 
-    def __init__(self, action=None, check_value=None, method=None,
-                 target=None, nginx_upload=None, **kwargs):
+    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)
 
@@ -219,24 +234,23 @@
 
 
 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
+            kwargs["name"] = name
 
         # Handle positional parameters
-        if 'positional' in kwargs and kwargs['positional']:
+        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']
+        if "num_dashes" in kwargs:
+            self.num_dashes = kwargs["num_dashes"]
+            del kwargs["num_dashes"]
         else:
             self.num_dashes = 0
 
@@ -244,14 +258,15 @@
 
         # Not sure about this :(
         # https://wiki.galaxyproject.org/Tools/BestPractices#Parameter_help
-        if 'label' in kwargs:
+        if "label" in kwargs:
             # TODO: replace with positional attribute
             if len(self.flag()) > 0:
-                if kwargs['label'] is None:
+                if kwargs["label"] is None:
                     kwargs[
-                        'label'] = 'Author did not provide help for this parameter... '
+                        "label"
+                    ] = "Author did not provide help for this parameter... "
                 if not self.positional:
-                    kwargs['argument'] = self.flag()
+                    kwargs["argument"] = self.flag()
 
         super(InputParameter, self).__init__(**kwargs)
 
@@ -261,7 +276,7 @@
         after = self.command_line_after()
 
         complete = [x for x in (before, cli, after) if x is not None]
-        return '\n'.join(complete)
+        return "\n".join(complete)
 
     def command_line_before(self):
         try:
@@ -282,20 +297,24 @@
             if self.positional:
                 return self.mako_name()
             else:
-                return "%s%s%s" % (self.flag(), self.space_between_arg, self.mako_name())
+                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
+        return "$" + self.mako_identifier
 
     def flag(self):
-        flag = '-' * self.num_dashes
+        flag = "-" * self.num_dashes
         return flag + self.mako_identifier
 
 
 class Section(InputParameter):
-    name = 'section'
+    name = "section"
 
     def __init__(self, name, title, expanded=None, help=None, **kwargs):
         params = Util.clean_kwargs(locals().copy())
@@ -306,14 +325,13 @@
 
 
 class Repeat(InputParameter):
-    name = 'repeat'
+    name = "repeat"
 
-    def __init__(self, name, title, min=None, max=None, default=None,
-                 **kwargs):
+    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_before_override = "#for $i in $%s:" % name
+        self.command_line_after_override = "#end for"
         # self.command_line_override
         super(Repeat, self).__init__(**params)
 
@@ -321,22 +339,23 @@
         return issubclass(type(child), InputParameter)
 
     def command_line_actual(self):
-        if hasattr(self, 'command_line_override'):
+        if hasattr(self, "command_line_override"):
             return self.command_line_override
         else:
             return "%s" % self.mako_name()
 
 
 class Conditional(InputParameter):
-    name = 'conditional'
+    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)
+        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
@@ -344,7 +363,7 @@
 
 
 class When(InputParameter):
-    name = 'when'
+    name = "when"
 
     def __init__(self, value):
         params = Util.clean_kwargs(locals().copy())
@@ -355,27 +374,31 @@
 
 
 class Param(InputParameter):
-    name = 'param'
+    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
+        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")
+                "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)
+        return issubclass(
+            type(child, InputParameter) or isinstance(child), ValidatorParam
+        )
 
 
 class TextParam(Param):
-    type = 'text'
+    type = "text"
 
-    def __init__(self, name, optional=None, label=None, help=None,
-                 value=None, **kwargs):
+    def __init__(
+        self, name, optional=None, label=None, help=None, value=None, **kwargs
+    ):
         params = Util.clean_kwargs(locals().copy())
         super(TextParam, self).__init__(**params)
 
@@ -390,26 +413,43 @@
 
 
 class _NumericParam(Param):
-
-    def __init__(self, name, value, optional=None, label=None, help=None,
-                 min=None, max=None, **kwargs):
+    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'
+    type = "integer"
 
 
 class FloatParam(_NumericParam):
-    type = 'float'
+    type = "float"
 
 
 class BooleanParam(Param):
-    type = 'boolean'
+    type = "boolean"
 
-    def __init__(self, name, optional=None, label=None, help=None,
-                 checked=False, truevalue=None, falsevalue=None, **kwargs):
+    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)
@@ -422,36 +462,54 @@
             # 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()
+            self.node.attrib["truevalue"] = self.flag()
 
         if falsevalue is None:
-            self.node.attrib['falsevalue'] = ""
+            self.node.attrib["falsevalue"] = ""
 
     def command_line_actual(self):
-        if hasattr(self, 'command_line_override'):
+        if hasattr(self, "command_line_override"):
             return self.command_line_override
         else:
             return "%s" % self.mako_name()
 
 
 class DataParam(Param):
-    type = 'data'
+    type = "data"
 
-    def __init__(self, name, optional=None, label=None, help=None, format=None,
-                 multiple=None, **kwargs):
+    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'
+    type = "select"
 
-    def __init__(self, name, optional=None, label=None, help=None,
-                 data_ref=None, display=None, multiple=None, options=None,
-                 default=None, **kwargs):
+    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']
+        del params["options"]
+        del params["default"]
 
         super(SelectParam, self).__init__(**params)
 
@@ -461,34 +519,39 @@
 
         if options:
             for k, v in list(sorted(options.items())):
-                selected = (k == default)
+                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)
+        return issubclass(type(child), SelectOption) or issubclass(type(child), Options)
 
 
 class SelectOption(InputParameter):
-    name = 'option'
+    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']
+            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'
+    name = "options"
 
-    def __init__(self, from_dataset=None, from_file=None, from_data_table=None,
-                 from_parameter=None, **kwargs):
+    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)
 
@@ -497,7 +560,7 @@
 
 
 class Column(InputParameter):
-    name = 'column'
+    name = "column"
 
     def __init__(self, name, index, **kwargs):
         params = Util.clean_kwargs(locals().copy())
@@ -505,27 +568,48 @@
 
 
 class Filter(InputParameter):
-    name = 'filter'
+    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):
+    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'
+    name = "validator"
 
-    def __init__(self, type, message=None, filename=None, metadata_name=None,
-                 metadata_column=None, line_startswith=None, min=None,
-                 max=None, **kwargs):
+    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'
+    name = "outputs"
 
     def acceptable_child(self, child):
         return isinstance(child, OutputData) or isinstance(child, OutputCollection)
@@ -534,16 +618,26 @@
 class OutputData(XMLParam):
     """Copypasta of InputParameter, needs work
     """
-    name = 'data'
+
+    name = "data"
 
-    def __init__(self, name, format, format_source=None, metadata_source=None,
-                 label=None, from_work_dir=None, hidden=False, **kwargs):
+    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']
+        if "num_dashes" in kwargs:
+            self.num_dashes = kwargs["num_dashes"]
+            del kwargs["num_dashes"]
         else:
             self.num_dashes = 0
         self.space_between_arg = " "
@@ -552,30 +646,32 @@
         super(OutputData, self).__init__(**params)
 
     def command_line(self):
-        if hasattr(self, 'command_line_override'):
+        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
+        return "$" + self.mako_identifier
 
     def flag(self):
-        flag = '-' * self.num_dashes
+        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)
+        return (
+            isinstance(child, OutputFilter)
+            or isinstance(child, ChangeFormat)
+            or isinstance(child, DiscoverDatasets)
+        )
 
 
 class OutputFilter(XMLParam):
-    name = 'filter'
+    name = "filter"
 
     def __init__(self, text, **kwargs):
         params = Util.clean_kwargs(locals().copy())
-        del params['text']
+        del params["text"]
         super(OutputFilter, self).__init__(**params)
         self.node.text = text
 
@@ -584,7 +680,7 @@
 
 
 class ChangeFormat(XMLParam):
-    name = 'change_format'
+    name = "change_format"
 
     def __init__(self, **kwargs):
         params = Util.clean_kwargs(locals().copy())
@@ -595,7 +691,7 @@
 
 
 class ChangeFormatWhen(XMLParam):
-    name = 'when'
+    name = "when"
 
     def __init__(self, input, format, value, **kwargs):
         params = Util.clean_kwargs(locals().copy())
@@ -606,43 +702,56 @@
 
 
 class OutputCollection(XMLParam):
-    name = 'collection'
+    name = "collection"
 
-    def __init__(self, name, type=None, label=None, format_source=None,
-                 type_source=None, structured_like=None, inherit_format=None, **kwargs):
+    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) \
+        return (
+            isinstance(child, OutputData)
+            or isinstance(child, OutputFilter)
             or isinstance(child, DiscoverDatasets)
+        )
 
 
 class DiscoverDatasets(XMLParam):
-    name = 'discover_datasets'
+    name = "discover_datasets"
 
-    def __init__(self, pattern, directory=None, format=None, ext=None,
-                 visible=None, **kwargs):
+    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'
+    name = "tests"
 
     def acceptable_child(self, child):
         return issubclass(type(child), Test)
 
 
 class Test(XMLParam):
-    name = 'test'
+    name = "test"
 
     def acceptable_child(self, child):
         return isinstance(child, TestParam) or isinstance(child, TestOutput)
 
 
 class TestParam(XMLParam):
-    name = 'param'
+    name = "param"
 
     def __init__(self, name, value=None, ftype=None, dbkey=None, **kwargs):
         params = Util.clean_kwargs(locals().copy())
@@ -650,17 +759,28 @@
 
 
 class TestOutput(XMLParam):
-    name = 'output'
+    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):
+    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'
+    name = "citations"
 
     def acceptable_child(self, child):
         return issubclass(type(child), Citation)
@@ -673,16 +793,16 @@
         :type value: STRING
         """
         for citation in self.children:
-            if citation.node.attrib['type'] == type and citation.node.text == value:
+            if citation.node.attrib["type"] == type and citation.node.text == value:
                 return True
         return False
 
 
 class Citation(XMLParam):
-    name = 'citation'
+    name = "citation"
 
     def __init__(self, type, value):
         passed_kwargs = {}
-        passed_kwargs['type'] = type
+        passed_kwargs["type"] = type
         super(Citation, self).__init__(**passed_kwargs)
         self.node.text = str(value)
--- a/toolfactory/rgToolFactory2.py	Sat Aug 08 19:55:55 2020 -0400
+++ b/toolfactory/rgToolFactory2.py	Mon Aug 10 23:24:41 2020 -0400
@@ -19,27 +19,30 @@
 # TODO: add option to run that code as a post execution hook
 # TODO: add additional history input parameters - currently only one
 
-import sys
+
+import argparse
+import logging
+import os
+import re
+import shutil
 import subprocess
-import shutil
-import os
+import sys
+import tarfile
+import tempfile
 import time
-import tempfile
-import argparse
-import tarfile
-import re
+
 import galaxyxml.tool as gxt
 import galaxyxml.tool.parameters as gxtp
-import logging
+import lxml
 
-
+foo = lxml.__name__   # fug you, flake8. Say my name! Please accept the PR, Helena!
 
 progname = os.path.split(sys.argv[0])[1]
-myversion = 'V2.1 July 2020'
+myversion = "V2.1 July 2020"
 verbose = True
 debug = True
-toolFactoryURL = 'https://github.com/fubar2/toolfactory'
-ourdelim = '~~~'
+toolFactoryURL = "https://github.com/fubar2/toolfactory"
+ourdelim = "~~~"
 
 # --input_files="$input_files~~~$CL~~~$input_formats~~~$input_label~~~$input_help"
 IPATHPOS = 0
@@ -54,7 +57,7 @@
 OCLPOS = 2
 OOCLPOS = 3
 
-#--additional_parameters="$i.param_name~~~$i.param_value~~~$i.param_label~~~$i.param_help~~~$i.param_type~~~$i.CL"
+# --additional_parameters="$i.param_name~~~$i.param_value~~~$i.param_label~~~$i.param_help~~~$i.param_type~~~$i.CL"
 ANAMEPOS = 0
 AVALPOS = 1
 ALABPOS = 2
@@ -63,10 +66,11 @@
 ACLPOS = 5
 AOCLPOS = 6
 
+
 def timenow():
     """return current time as a string
     """
-    return time.strftime('%d/%m/%Y %H:%M:%S', time.localtime(time.time()))
+    return time.strftime("%d/%m/%Y %H:%M:%S", time.localtime(time.time()))
 
 
 def quote_non_numeric(s):
@@ -80,12 +84,7 @@
         return '"%s"' % s
 
 
-html_escape_table = {
-    "&": "&amp;",
-    ">": "&gt;",
-    "<": "&lt;",
-    "$": r"\$"
-}
+html_escape_table = {"&": "&amp;", ">": "&gt;", "<": "&lt;", "$": r"\$"}
 
 
 def html_escape(text):
@@ -95,10 +94,10 @@
 
 def html_unescape(text):
     """Revert entities within text. Multiple character targets so use replace"""
-    t = text.replace('&amp;', '&')
-    t = t.replace('&gt;', '>')
-    t = t.replace('&lt;', '<')
-    t = t.replace('\\$', '$')
+    t = text.replace("&amp;", "&")
+    t = t.replace("&gt;", ">")
+    t = t.replace("&lt;", "<")
+    t = t.replace("\\$", "$")
     return t
 
 
@@ -111,8 +110,7 @@
         if citation.startswith("doi"):
             citation_tuples.append(("doi", citation[len("doi"):].strip()))
         else:
-            citation_tuples.append(
-                ("bibtex", citation[len("bibtex"):].strip()))
+            citation_tuples.append(("bibtex", citation[len("bibtex"):].strip()))
     return citation_tuples
 
 
@@ -121,8 +119,7 @@
     uses galaxyxml
 
     """
-    
-    
+
     def __init__(self, args=None):
         """
         prepare command line cl for running the tool here
@@ -138,38 +135,43 @@
         self.lastxclredirect = None
         self.cl = []
         self.xmlcl = []
+        self.is_positional = self.args.parampass == "positional"
         aCL = self.cl.append
-        assert args.parampass in ['0','argparse','positional'],'Parameter passing in args.parampass must be "0","positional" or "argparse"'
-        self.tool_name = re.sub('[^a-zA-Z0-9_]+', '', args.tool_name)
+        assert args.parampass in [
+            "0",
+            "argparse",
+            "positional",
+        ], 'Parameter passing in args.parampass must be "0","positional" or "argparse"'
+        self.tool_name = re.sub("[^a-zA-Z0-9_]+", "", args.tool_name)
         self.tool_id = self.tool_name
-        self.xmlfile = '%s.xml' % self.tool_name
-        if self.args.runmode == "Executable" or self.args.runmode == "system":  # binary - no need
+        self.xmlfile = "%s.xml" % self.tool_name
+        if self.args.interpreter_name:
+            exe = "$runMe"
+        else:
+            exe = self.args.exe_package
+        assert (
+            exe is not None
+        ), "No interpeter or executable passed in - nothing to run so cannot build"
+        self.tool = gxt.Tool(
+            self.args.tool_name,
+            self.tool_id,
+            self.args.tool_version,
+            self.args.tool_desc,
+            exe,
+        )
+        self.tinputs = gxtp.Inputs()
+        self.toutputs = gxtp.Outputs()
+        self.testparam = []
+        if (
+            self.args.runmode == "Executable" or self.args.runmode == "system"
+        ):  # binary - no need
             aCL(self.args.exe_package)  # this little CL will just run
-        else: 
-            rx = open(self.args.script_path, 'r').readlines()
-            rx = [x.rstrip() for x in rx ]
-            rxcheck = [x.strip() for x in rx if x.strip() > '']
-            assert len(rxcheck) > 0,"Supplied script is empty. Cannot run"
-            self.script = '\n'.join(rx)
-            fhandle, self.sfile = tempfile.mkstemp(
-                prefix=self.tool_name, suffix=".%s" % (args.interpreter_name))
-            tscript = open(self.sfile, 'w')
-            tscript.write(self.script)
-            tscript.close()
-            self.indentedScript = "  %s" % '\n'.join(
-                [' %s' % html_escape(x) for x in rx]) 
-            self.escapedScript = "%s" % '\n'.join(
-                [' %s' % html_escape(x) for x in rx])
-            art = '%s.%s' % (self.tool_name, args.interpreter_name)
-            artifact = open(art, 'wb')
-            artifact.write(bytes(self.script, "utf8"))
-            artifact.close()            
-            aCL(self.args.interpreter_name)
-            aCL(self.sfile)
+        else:
+            self.prepScript()
         self.elog = "%s_error_log.txt" % self.tool_name
         self.tlog = "%s_runner_log.txt" % self.tool_name
 
-        if self.args.parampass == '0':
+        if self.args.parampass == "0":
             self.clsimple()
         else:
             clsuffix = []
@@ -177,92 +179,120 @@
             for i, p in enumerate(self.infiles):
                 appendme = [p[IOCLPOS], p[ICLPOS], p[IPATHPOS]]
                 clsuffix.append(appendme)
-                xclsuffix.append([p[IOCLPOS],p[ICLPOS],'$%s' % p[ICLPOS]])
-                #print('##infile i=%d, appendme=%s' % (i,appendme))
+                xclsuffix.append([p[IOCLPOS], p[ICLPOS], "$%s" % p[ICLPOS]])
+                # print('##infile i=%d, appendme=%s' % (i,appendme))
             for i, p in enumerate(self.outfiles):
                 if p[OOCLPOS] == "STDOUT":
-                    self.lastclredirect = ['>',p[ONAMEPOS]]
-                    self.lastxclredirect = ['>','$%s' % p[OCLPOS]]
-                    #print('##outfiles i=%d lastclredirect = %s' % (i,self.lastclredirect))
+                    self.lastclredirect = [">", p[ONAMEPOS]]
+                    self.lastxclredirect = [">", "$%s" % p[OCLPOS]]
+                    # print('##outfiles i=%d lastclredirect = %s' % (i,self.lastclredirect))
                 else:
-                    appendme = [p[OOCLPOS], p[OCLPOS],p[ONAMEPOS]]
-                    clsuffix.append(appendme)    
-                    xclsuffix.append([p[OOCLPOS], p[OCLPOS],'$%s' % p[ONAMEPOS]])    
-                    #print('##outfiles i=%d' % i,'appendme',appendme)
-            for p in self.addpar: 
+                    appendme = [p[OOCLPOS], p[OCLPOS], p[ONAMEPOS]]
+                    clsuffix.append(appendme)
+                    xclsuffix.append([p[OOCLPOS], p[OCLPOS], "$%s" % p[ONAMEPOS]])
+                    # print('##outfiles i=%d' % i,'appendme',appendme)
+            for p in self.addpar:
                 appendme = [p[AOCLPOS], p[ACLPOS], p[AVALPOS]]
                 clsuffix.append(appendme)
                 xclsuffix.append([p[AOCLPOS], p[ACLPOS], '"$%s"' % p[ANAMEPOS]])
-                #print('##adpar %d' % i,'appendme=',appendme)
+                # print('##adpar %d' % i,'appendme=',appendme)
             clsuffix.sort()
             xclsuffix.sort()
             self.xclsuffix = xclsuffix
             self.clsuffix = clsuffix
-            if self.args.parampass == 'positional':
+            if self.args.parampass == "positional":
                 self.clpositional()
             else:
                 self.clargparse()
-                
+
+    def prepScript(self):
+        aCL = self.cl.append
+        rx = open(self.args.script_path, "r").readlines()
+        rx = [x.rstrip() for x in rx]
+        rxcheck = [x.strip() for x in rx if x.strip() > ""]
+        assert len(rxcheck) > 0, "Supplied script is empty. Cannot run"
+        self.script = "\n".join(rx)
+        fhandle, self.sfile = tempfile.mkstemp(
+            prefix=self.tool_name, suffix=".%s" % (self.args.interpreter_name)
+        )
+        tscript = open(self.sfile, "w")
+        tscript.write(self.script)
+        tscript.close()
+        self.indentedScript = "  %s" % "\n".join([" %s" % html_escape(x) for x in rx])
+        self.escapedScript = "%s" % "\n".join([" %s" % html_escape(x) for x in rx])
+        art = "%s.%s" % (self.tool_name, self.args.interpreter_name)
+        artifact = open(art, "wb")
+        artifact.write(bytes(self.script, "utf8"))
+        artifact.close()
+        aCL(self.args.interpreter_name)
+        aCL(self.sfile)
+
     def cleanuppar(self):
         """ positional parameters are complicated by their numeric ordinal"""
-        for i,p in enumerate(self.infiles):
-            if self.args.parampass == 'positional':
-                assert p[ICLPOS].isdigit(), "Positional parameters must be ordinal integers - got %s for %s" % (p[ICLPOS],p[ILABPOS]) 
+        for i, p in enumerate(self.infiles):
+            if self.args.parampass == "positional":
+                assert p[ICLPOS].isdigit(), (
+                    "Positional parameters must be ordinal integers - got %s for %s"
+                    % (p[ICLPOS], p[ILABPOS])
+                )
             p.append(p[ICLPOS])
             if p[ICLPOS].isdigit() or self.args.parampass == "0":
-                scl = 'input%d' % (i+1)
+                scl = "input%d" % (i + 1)
                 p[ICLPOS] = scl
             self.infiles[i] = p
-        for i,p in enumerate(self.outfiles):  # trying to automagically gather using extensions
-            if self.args.parampass == 'positional' and p[OCLPOS] != "STDOUT":
-                assert p[OCLPOS].isdigit(), "Positional parameters must be ordinal integers - got %s for %s" % (p[OCLPOS],p[ONAMEPOS]) 
+        for i, p in enumerate(
+            self.outfiles
+        ):  # trying to automagically gather using extensions
+            if self.args.parampass == "positional" and p[OCLPOS] != "STDOUT":
+                assert p[OCLPOS].isdigit(), (
+                    "Positional parameters must be ordinal integers - got %s for %s"
+                    % (p[OCLPOS], p[ONAMEPOS])
+                )
             p.append(p[OCLPOS])
             if p[OCLPOS].isdigit() or p[OCLPOS] == "STDOUT":
                 scl = p[ONAMEPOS]
                 p[OCLPOS] = scl
             self.outfiles[i] = p
-        for i,p in enumerate(self.addpar):
-            if self.args.parampass == 'positional':
-                assert p[ACLPOS].isdigit(), "Positional parameters must be ordinal integers - got %s for %s" % (p[ACLPOS],p[ANAMEPOS]) 
+        for i, p in enumerate(self.addpar):
+            if self.args.parampass == "positional":
+                assert p[ACLPOS].isdigit(), (
+                    "Positional parameters must be ordinal integers - got %s for %s"
+                    % (p[ACLPOS], p[ANAMEPOS])
+                )
             p.append(p[ACLPOS])
             if p[ACLPOS].isdigit():
-                scl = 'input%s' % p[ACLPOS]
+                scl = "input%s" % p[ACLPOS]
                 p[ACLPOS] = scl
             self.addpar[i] = p
-                
- 
-            
+
     def clsimple(self):
         """ no parameters - uses < and > for i/o
         """
         aCL = self.cl.append
-        aCL('<')
+        aCL("<")
         aCL(self.infiles[0][IPATHPOS])
-        aCL('>')
+        aCL(">")
         aCL(self.outfiles[0][OCLPOS])
         aXCL = self.xmlcl.append
-        aXCL('<')
-        aXCL('$%s' % self.infiles[0][ICLPOS])
-        aXCL('>')
-        aXCL('$%s' % self.outfiles[0][ONAMEPOS])
-       
+        aXCL("<")
+        aXCL("$%s" % self.infiles[0][ICLPOS])
+        aXCL(">")
+        aXCL("$%s" % self.outfiles[0][ONAMEPOS])
 
     def clpositional(self):
         # inputs in order then params
         aCL = self.cl.append
-        for (o_v,k, v) in self.clsuffix:
+        for (o_v, k, v) in self.clsuffix:
             if " " in v:
                 aCL("%s" % v)
             else:
                 aCL(v)
         aXCL = self.xmlcl.append
-        for (o_v,k, v) in self.xclsuffix:
+        for (o_v, k, v) in self.xclsuffix:
             aXCL(v)
         if self.lastxclredirect:
             aXCL(self.lastxclredirect[0])
             aXCL(self.lastxclredirect[1])
-        
-
 
     def clargparse(self):
         """ argparse style
@@ -270,23 +300,142 @@
         aCL = self.cl.append
         aXCL = self.xmlcl.append
         # inputs then params in argparse named form
-        for (o_v,k, v) in self.xclsuffix:
+        for (o_v, k, v) in self.xclsuffix:
             if len(k.strip()) == 1:
-                k = '-%s' % k
+                k = "-%s" % k
             else:
-                k = '--%s' % k
+                k = "--%s" % k
             aXCL(k)
             aXCL(v)
-        for (o_v,k, v) in self.clsuffix:
+        for (o_v, k, v) in self.clsuffix:
             if len(k.strip()) == 1:
-                k = '-%s' % k
+                k = "-%s" % k
             else:
-                k = '--%s' % k
+                k = "--%s" % k
             aCL(k)
             aCL(v)
 
-                
+    def getNdash(self, newname):
+        if self.is_positional:
+            ndash = 0
+        else:
+            ndash = 2
+            if len(newname) < 2:
+                ndash = 1
+        return ndash
 
+    def doXMLparam(self):
+        """flake8 made me do this..."""
+        for p in self.outfiles:
+            newname, newfmt, newcl, oldcl = p
+            ndash = self.getNdash(newcl)
+            aparm = gxtp.OutputData(newcl, format=newfmt, num_dashes=ndash)
+            aparm.positional = self.is_positional
+            if self.is_positional:
+                if oldcl == "STDOUT":
+                    aparm.positional = 9999999
+                    aparm.command_line_override = "> $%s" % newcl
+                else:
+                    aparm.positional = int(oldcl)
+                    aparm.command_line_override = "$%s" % newcl
+            self.toutputs.append(aparm)
+            tp = gxtp.TestOutput(name=newcl, value="%s_sample" % newcl, format=newfmt)
+            self.testparam.append(tp)
+        for p in self.infiles:
+            newname = p[ICLPOS]
+            newfmt = p[IFMTPOS]
+            ndash = self.getNdash(newname)
+            if not len(p[ILABPOS]) > 0:
+                alab = p[ICLPOS]
+            else:
+                alab = p[ILABPOS]
+            aninput = gxtp.DataParam(
+                newname,
+                optional=False,
+                label=alab,
+                help=p[IHELPOS],
+                format=newfmt,
+                multiple=False,
+                num_dashes=ndash,
+            )
+            aninput.positional = self.is_positional
+            self.tinputs.append(aninput)
+            tparm = gxtp.TestParam(name=newname, value="%s_sample" % newname)
+            self.testparam.append(tparm)
+        for p in self.addpar:
+            newname, newval, newlabel, newhelp, newtype, newcl, oldcl = p
+            if not len(newlabel) > 0:
+                newlabel = newname
+            ndash = self.getNdash(newname)
+            if newtype == "text":
+                aparm = gxtp.TextParam(
+                    newname,
+                    label=newlabel,
+                    help=newhelp,
+                    value=newval,
+                    num_dashes=ndash,
+                )
+            elif newtype == "integer":
+                aparm = gxtp.IntegerParam(
+                    newname,
+                    label=newname,
+                    help=newhelp,
+                    value=newval,
+                    num_dashes=ndash,
+                )
+            elif newtype == "float":
+                aparm = gxtp.FloatParam(
+                    newname,
+                    label=newname,
+                    help=newhelp,
+                    value=newval,
+                    num_dashes=ndash,
+                )
+            else:
+                raise ValueError(
+                    'Unrecognised parameter type "%s" for\
+                 additional parameter %s in makeXML'
+                    % (newtype, newname)
+                )
+            aparm.positional = self.is_positional
+            if self.is_positional:
+                aninput.positional = int(oldcl)
+            self.tinputs.append(aparm)
+            self.tparm = gxtp.TestParam(newname, value=newval)
+            self.testparam.append(tparm)
+
+    def doNoXMLparam(self):
+        alab = self.infiles[0][ILABPOS]
+        if len(alab) == 0:
+            alab = self.infiles[0][ICLPOS]
+        max1s = (
+            "Maximum one input if parampass is 0 - more than one input files supplied - %s"
+            % str(self.infiles)
+        )
+        assert len(self.infiles) == 1, max1s
+        newname = self.infiles[0][ICLPOS]
+        aninput = gxtp.DataParam(
+            newname,
+            optional=False,
+            label=alab,
+            help=self.infiles[0][IHELPOS],
+            format=self.infiles[0][IFMTPOS],
+            multiple=False,
+            num_dashes=0,
+        )
+        aninput.command_line_override = "< $%s" % newname
+        aninput.positional = self.is_positional
+        self.tinputs.append(aninput)
+        tp = gxtp.TestParam(name=newname, value="%s_sample" % newname)
+        self.testparam.append(tp)
+        newname = self.outfiles[0][OCLPOS]
+        newfmt = self.outfiles[0][OFMTPOS]
+        anout = gxtp.OutputData(newname, format=newfmt, num_dashes=0)
+        anout.command_line_override = "> $%s" % newname
+        anout.positional = self.is_positional
+        self.toutputs.append(anout)
+        tp = gxtp.TestOutput(name=newname, value="%s_sample" % newname, format=newfmt)
+        self.testparam.append(tp)
 
     def makeXML(self):
         """
@@ -294,159 +443,71 @@
         Uses galaxyhtml
         Hmmm. How to get the command line into correct order...
         """
-       
+        self.tool.command_line_override = self.xmlcl
         if self.args.interpreter_name:
-            exe = "$runMe" 
-            interp = self.args.interpreter_name
-        else:
-            interp = None
-            exe = self.args.exe_package
-        assert exe is not None, 'No interpeter or executable passed in to makeXML'
-        tool = gxt.Tool(self.args.tool_name, self.tool_id, 
-                        self.args.tool_version, self.args.tool_desc, exe)
-        tool.command_line_override = self.xmlcl
-        if interp:
-            tool.interpreter = interp
+            self.tool.interpreter = self.interp
         if self.args.help_text:
-            helptext = open(self.args.help_text, 'r').readlines()
+            helptext = open(self.args.help_text, "r").readlines()
             helptext = [html_escape(x) for x in helptext]
-            tool.help = ''.join([x for x in helptext])
+            self.tool.help = "".join([x for x in helptext])
         else:
-            tool.help = 'Please ask the tool author (%s) for help \
-              as none was supplied at tool generation\n' % (self.args.user_email)
-        tool.version_command = None  # do not want
-        tinputs = gxtp.Inputs()
-        toutputs = gxtp.Outputs()
+            self.tool.help = (
+                "Please ask the tool author (%s) for help \
+              as none was supplied at tool generation\n"
+                % (self.args.user_email)
+            )
+        self.tool.version_command = None  # do not want
         requirements = gxtp.Requirements()
-        testparam = []
-        is_positional = (self.args.parampass == 'positional')
+
         if self.args.interpreter_name:
-            if self.args.interpreter_name == 'python':  
-                requirements.append(gxtp.Requirement(
-                    'package', 'python', self.args.interpreter_version))
-            elif self.args.interpreter_name not in ['bash', 'sh']:
-                requirements.append(gxtp.Requirement(
-                    'package', self.args.interpreter_name, self.args.interpreter_version))
+            if self.args.interpreter_name == "python":
+                requirements.append(
+                    gxtp.Requirement("package", "python", self.args.interpreter_version)
+                )
+            elif self.args.interpreter_name not in ["bash", "sh"]:
+                requirements.append(
+                    gxtp.Requirement(
+                        "package",
+                        self.args.interpreter_name,
+                        self.args.interpreter_version,
+                    )
+                )
         else:
             if self.args.exe_package and self.args.parampass != "system":
-                requirements.append(gxtp.Requirement(
-                    'package', self.args.exe_package, self.args.exe_package_version))
-        tool.requirements = requirements
-        if self.args.parampass == '0':
-            alab = self.infiles[0][ILABPOS]
-            if len(alab) == 0:
-                alab = self.infiles[0][ICLPOS]
-            max1s = 'Maximum one input if parampass is 0 - more than one input files supplied - %s' % str(self.infiles)
-            assert len(self.infiles) == 1,max1s
-            newname = self.infiles[0][ICLPOS]
-            aninput = gxtp.DataParam(newname, optional=False, label=alab, help=self.infiles[0][IHELPOS],
-                                    format=self.infiles[0][IFMTPOS], multiple=False, num_dashes=0)
-            aninput.command_line_override = '< $%s' % newname
-            aninput.positional = is_positional
-            tinputs.append(aninput)
-            tp = gxtp.TestParam(name=newname, value='%s_sample' % newname)
-            testparam.append(tp)
-            newname = self.outfiles[0][OCLPOS]
-            newfmt = self.outfiles[0][OFMTPOS]
-            anout = gxtp.OutputData(newname, format=newfmt, num_dashes=0)
-            anout.command_line_override = '> $%s' % newname
-            anout.positional = is_positional
-            toutputs.append(anout)
-            tp = gxtp.TestOutput(name=newname, value='%s_sample' % newname,format=newfmt)
-            testparam.append(tp)
+                requirements.append(
+                    gxtp.Requirement(
+                        "package", self.args.exe_package, self.args.exe_package_version
+                    )
+                )
+        self.tool.requirements = requirements
+        if self.args.parampass == "0":
+            self.doXMLNoparam()
         else:
-            for p in self.outfiles:
-                newname,newfmt,newcl,oldcl = p
-                if is_positional:
-                    ndash = 0
-                else:
-                    ndash = 2
-                    if len(newcl) < 2:
-                        ndash = 1
-                aparm = gxtp.OutputData(newcl, format=newfmt, num_dashes=ndash)
-                aparm.positional = is_positional
-                if is_positional:
-                    if oldcl == "STDOUT":
-                        aparm.positional = 9999999
-                        aparm.command_line_override = "> $%s" % newcl
-                    else:
-                        aparm.positional = int(oldcl)
-                        aparm.command_line_override = '$%s' % newcl
-                toutputs.append(aparm)
-                tp = gxtp.TestOutput(name=newcl, value='%s_sample' % newcl ,format=newfmt)
-                testparam.append(tp)
-            for p in self.infiles:
-                newname = p[ICLPOS]
-                newfmt = p[IFMTPOS]
-                if is_positional:
-                    ndash = 0
-                else:
-                    if len(newname) > 1:
-                        ndash = 2
-                    else:
-                        ndash = 1
-                if not len(p[ILABPOS]) > 0:
-                    alab = p[ICLPOS]
-                else:
-                    alab = p[ILABPOS]
-                aninput = gxtp.DataParam(newname, optional=False, label=alab, help=p[IHELPOS],
-                                         format=newfmt, multiple=False, num_dashes=ndash)
-                aninput.positional = is_positional
-                if is_positional:
-                    aninput.positional = is_positional
-                tinputs.append(aninput)
-                tparm = gxtp.TestParam(name=newname, value='%s_sample' % newname )
-                testparam.append(tparm)
-            for p in self.addpar:
-                newname, newval, newlabel, newhelp, newtype, newcl, oldcl = p
-                if not len(newlabel) > 0:
-                    newlabel = newname
-                if is_positional:
-                    ndash = 0
-                else:
-                    if len(newname) > 1:
-                        ndash = 2
-                    else:
-                        ndash = 1
-                if newtype == "text":
-                    aparm = gxtp.TextParam(
-                        newname, label=newlabel, help=newhelp, value=newval, num_dashes=ndash)
-                elif newtype == "integer":
-                    aparm = gxtp.IntegerParam(
-                        newname, label=newname, help=newhelp, value=newval, num_dashes=ndash)
-                elif newtype == "float":
-                    aparm = gxtp.FloatParam(
-                        newname, label=newname, help=newhelp, value=newval, num_dashes=ndash)
-                else:
-                    raise ValueError('Unrecognised parameter type "%s" for\
-                     additional parameter %s in makeXML' % (newtype, newname))
-                aparm.positional = is_positional
-                if is_positional:
-                    aninput.positional = int(oldcl)
-                tinputs.append(aparm)
-                tparm = gxtp.TestParam(newname, value=newval)
-                testparam.append(tparm)
-        tool.outputs = toutputs
-        tool.inputs = tinputs
-        if not self.args.runmode in ['Executable','system']:
+            self.doXMLParam()
+        self.tool.outputs = self.toutputs
+        self.tool.inputs = self.tinputs
+        if self.args.runmode not in ["Executable", "system"]:
             configfiles = gxtp.Configfiles()
             configfiles.append(gxtp.Configfile(name="runMe", text=self.script))
-            tool.configfiles = configfiles
+            self.tool.configfiles = configfiles
         tests = gxtp.Tests()
         test_a = gxtp.Test()
-        for tp in testparam:
+        for tp in self.testparam:
             test_a.append(tp)
         tests.append(test_a)
-        tool.tests = tests
-        tool.add_comment('Created by %s at %s using the Galaxy Tool Factory.' % (
-            self.args.user_email, timenow()))
-        tool.add_comment('Source in git at: %s' % (toolFactoryURL))
-        tool.add_comment(
-            'Cite: Creating re-usable tools from scripts doi: 10.1093/bioinformatics/bts573')
-        exml = tool.export()
-        xf = open(self.xmlfile, 'w')
+        self.tool.tests = tests
+        self.tool.add_comment(
+            "Created by %s at %s using the Galaxy Tool Factory."
+            % (self.args.user_email, timenow())
+        )
+        self.tool.add_comment("Source in git at: %s" % (toolFactoryURL))
+        self.tool.add_comment(
+            "Cite: Creating re-usable tools from scripts doi: 10.1093/bioinformatics/bts573"
+        )
+        exml = self.tool.export()
+        xf = open(self.xmlfile, "w")
         xf.write(exml)
-        xf.write('\n')
+        xf.write("\n")
         xf.close()
         # ready for the tarball
 
@@ -459,49 +520,46 @@
         """
         retval = self.run()
         if retval:
-            sys.stderr.write(
-                '## Run failed. Cannot build yet. Please fix and retry')
+            sys.stderr.write("## Run failed. Cannot build yet. Please fix and retry")
             sys.exit(1)
-        tdir = 'tfout' 
+        tdir = "tfout"
         if not os.path.exists(tdir):
             os.mkdir(tdir)
         self.makeXML()
-        testdir = os.path.join(tdir,'test-data')
+        testdir = os.path.join(tdir, "test-data")
         if not os.path.exists(testdir):
             os.mkdir(testdir)  # make tests directory
         for p in self.infiles:
             pth = p[IPATHPOS]
-            dest = os.path.join(testdir, '%s_sample' % 
-              p[ICLPOS])
+            dest = os.path.join(testdir, "%s_sample" % p[ICLPOS])
             shutil.copyfile(pth, dest)
         for p in self.outfiles:
             pth = p[OCLPOS]
-            if p[OOCLPOS] == 'STDOUT' or self.args.parampass == "0":
+            if p[OOCLPOS] == "STDOUT" or self.args.parampass == "0":
                 pth = p[ONAMEPOS]
-                dest = os.path.join(testdir,'%s_sample' % p[ONAMEPOS])
+                dest = os.path.join(testdir, "%s_sample" % p[ONAMEPOS])
                 shutil.copyfile(pth, dest)
                 dest = os.path.join(tdir, p[ONAMEPOS])
-                shutil.copyfile(pth, dest)   
+                shutil.copyfile(pth, dest)
             else:
                 pth = p[OCLPOS]
-                dest = os.path.join(testdir,'%s_sample' % p[OCLPOS])
+                dest = os.path.join(testdir, "%s_sample" % p[OCLPOS])
                 shutil.copyfile(pth, dest)
                 dest = os.path.join(tdir, p[OCLPOS])
-                shutil.copyfile(pth, dest)   
+                shutil.copyfile(pth, dest)
 
         if os.path.exists(self.tlog) and os.stat(self.tlog).st_size > 0:
-            shutil.copyfile(self.tlog, os.path.join(
-                testdir, 'test1_log.txt'))
-        if not self.args.runmode in ['Executable','system']:
-            stname = os.path.join(tdir, '%s' % (self.sfile))
+            shutil.copyfile(self.tlog, os.path.join(testdir, "test1_log.txt"))
+        if self.args.runmode not in ["Executable", "system"]:
+            stname = os.path.join(tdir, "%s" % (self.sfile))
             if not os.path.exists(stname):
                 shutil.copyfile(self.sfile, stname)
-        xtname = os.path.join(tdir,self.xmlfile)
+        xtname = os.path.join(tdir, self.xmlfile)
         if not os.path.exists(xtname):
             shutil.copyfile(self.xmlfile, xtname)
-        tarpath = 'toolfactory_%s.tgz' % self.tool_name
-        tf = tarfile.open(tarpath,"w:gz")
-        tf.add(name=tdir,arcname=self.tool_name)
+        tarpath = "toolfactory_%s.tgz" % self.tool_name
+        tf = tarfile.open(tarpath, "w:gz")
+        tf.add(name=tdir, arcname=self.tool_name)
         tf.close()
         shutil.copyfile(tarpath, self.args.new_tool)
         return retval
@@ -511,26 +569,29 @@
         Some devteam tools have this defensive stderr read so I'm keeping with the faith
         Feel free to update.
         """
-        s = 'run cl=%s' % str(self.cl)
-        
+        s = "run cl=%s" % str(self.cl)
+
         logging.debug(s)
-        scl = ' '.join(self.cl)
+        scl = " ".join(self.cl)
         err = None
-        if self.args.parampass != '0':
-            ste = open(self.elog, 'wb')
+        if self.args.parampass != "0":
+            ste = open(self.elog, "wb")
             if self.lastclredirect:
-                sto = open(self.lastclredirect[1],'wb') # is name of an output file
+                sto = open(self.lastclredirect[1], "wb")  # is name of an output file
             else:
-                sto = open(self.tlog, 'wb')
+                sto = open(self.tlog, "wb")
                 sto.write(
-                    bytes('## Executing Toolfactory generated command line = %s\n' % scl, "utf8"))
+                    bytes(
+                        "## Executing Toolfactory generated command line = %s\n" % scl,
+                        "utf8",
+                    )
+                )
             sto.flush()
-            p = subprocess.run(self.cl, shell=False, stdout=sto,
-                               stderr=ste)
+            p = subprocess.run(self.cl, shell=False, stdout=sto, stderr=ste)
             sto.close()
             ste.close()
-            tmp_stderr = open(self.elog, 'rb')
-            err = ''
+            tmp_stderr = open(self.elog, "rb")
+            err = ""
             buffsize = 1048576
             try:
                 while True:
@@ -542,8 +603,8 @@
             tmp_stderr.close()
             retval = p.returncode
         else:  # work around special case of simple scripts that take stdin and write to stdout
-            sti = open(self.infiles[0][IPATHPOS], 'rb')
-            sto = open(self.outfiles[0][ONAMEPOS], 'wb')
+            sti = open(self.infiles[0][IPATHPOS], "rb")
+            sto = open(self.outfiles[0][ONAMEPOS], "wb")
             # must use shell to redirect
             p = subprocess.run(self.cl, shell=False, stdout=sto, stdin=sti)
             retval = p.returncode
@@ -555,7 +616,7 @@
             os.unlink(self.elog)
         if p.returncode != 0 and err:  # problem
             sys.stderr.write(err)
-        logging.debug('run done')
+        logging.debug("run done")
         return retval
 
 
@@ -567,40 +628,43 @@
     """
     parser = argparse.ArgumentParser()
     a = parser.add_argument
-    a('--script_path', default='')
-    a('--tool_name', default=None)
-    a('--interpreter_name', default=None)
-    a('--interpreter_version', default=None)
-    a('--exe_package', default=None)
-    a('--exe_package_version', default=None)
-    a('--input_files', default=[], action="append")
-    a('--output_files', default=[], action="append")
-    a('--user_email', default='Unknown')
-    a('--bad_user', default=None)
-    a('--make_Tool', default=None)
-    a('--help_text', default=None)
-    a('--tool_desc', default=None)
-    a('--tool_version', default=None)
-    a('--citations', default=None)
-    a('--additional_parameters', action='append', default=[])
-    a('--edit_additional_parameters', action="store_true", default=False)
-    a('--parampass', default="positional")
-    a('--tfout', default="./tfout")
-    a('--new_tool',default="new_tool")
-    a('--runmode',default=None)
+    a("--script_path", default="")
+    a("--tool_name", default=None)
+    a("--interpreter_name", default=None)
+    a("--interpreter_version", default=None)
+    a("--exe_package", default=None)
+    a("--exe_package_version", default=None)
+    a("--input_files", default=[], action="append")
+    a("--output_files", default=[], action="append")
+    a("--user_email", default="Unknown")
+    a("--bad_user", default=None)
+    a("--make_Tool", default=None)
+    a("--help_text", default=None)
+    a("--tool_desc", default=None)
+    a("--tool_version", default=None)
+    a("--citations", default=None)
+    a("--additional_parameters", action="append", default=[])
+    a("--edit_additional_parameters", action="store_true", default=False)
+    a("--parampass", default="positional")
+    a("--tfout", default="./tfout")
+    a("--new_tool", default="new_tool")
+    a("--runmode", default=None)
     args = parser.parse_args()
-    assert not args.bad_user, 'UNAUTHORISED: %s is NOT authorized to use this tool until Galaxy admin adds %s to "admin_users" in the Galaxy configuration file' % (
-        args.bad_user, args.bad_user)
-    assert args.tool_name, '## Tool Factory expects a tool name - eg --tool_name=DESeq'
-    assert (args.interpreter_name or args.exe_package), '## Tool Factory wrapper expects an interpreter - eg --interpreter_name=Rscript or an executable package findable by the dependency management package'
-    assert args.exe_package or (len(args.script_path) > 0 and os.path.isfile(
-        args.script_path)), '## Tool Factory wrapper expects a script path - eg --script_path=foo.R if no executable'
-    args.input_files = [x.replace('"', '').replace("'", '')
-                        for x in args.input_files]
+    assert not args.bad_user, (
+        'UNAUTHORISED: %s is NOT authorized to use this tool until Galaxy admin adds %s to "admin_users" in the Galaxy configuration file'
+        % (args.bad_user, args.bad_user)
+    )
+    assert args.tool_name, "## Tool Factory expects a tool name - eg --tool_name=DESeq"
+    assert (
+        args.interpreter_name or args.exe_package
+    ), "## Tool Factory wrapper expects an interpreter or an executable package"
+    assert args.exe_package or (
+        len(args.script_path) > 0 and os.path.isfile(args.script_path)
+    ), "## Tool Factory wrapper expects a script path - eg --script_path=foo.R if no executable"
+    args.input_files = [x.replace('"', "").replace("'", "") for x in args.input_files]
     # remove quotes we need to deal with spaces in CL params
     for i, x in enumerate(args.additional_parameters):
-        args.additional_parameters[i] = args.additional_parameters[i].replace(
-            '"', '')
+        args.additional_parameters[i] = args.additional_parameters[i].replace('"', "")
     r = ScriptRunner(args)
     if args.make_Tool:
         retcode = r.makeTooltar()
--- a/toolfactory/rgToolFactory2.xml	Sat Aug 08 19:55:55 2020 -0400
+++ b/toolfactory/rgToolFactory2.xml	Mon Aug 10 23:24:41 2020 -0400
@@ -122,6 +122,7 @@
   </macros>
    <requirements>
       <requirement type="package">python</requirement>
+      <requirement type="package">lxml</requirement>
   </requirements>
   <command interpreter="python"><![CDATA[
 #import os
--- a/toolfactory/sample_toolfactory_tools.ga	Sat Aug 08 19:55:55 2020 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,443 +0,0 @@
-{
-    "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
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/toolfactory/sample_toolfactory_tools.tgz	Mon Aug 10 23:24:41 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
+}
Binary file toolfactory/tf_tests_history.tar.gz has changed
Binary file toolfactory/tfwfsample.tgz has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/toolfactory/tfworkflowsample.ga	Mon Aug 10 23:24:41 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
+}