Repository 'tool_factory_2'
hg clone https://toolshed.g2.bx.psu.edu/repos/fubar/tool_factory_2

Changeset 138:1dba6c7687a9 (2021-04-14)
Previous changeset 137:63d15caea378 (2021-04-13) Next changeset 139:6b414af9ca11 (2021-04-17)
Commit message:
Uploaded
modified:
toolfactory/rgToolFactory2.py
toolfactory/rgToolFactory2.xml
removed:
toolfactory/galaxyxml/__init__.py
toolfactory/galaxyxml/tool/__init__.py
toolfactory/galaxyxml/tool/import_xml.py
toolfactory/galaxyxml/tool/parameters/__init__.py
b
diff -r 63d15caea378 -r 1dba6c7687a9 toolfactory/galaxyxml/__init__.py
--- a/toolfactory/galaxyxml/__init__.py Tue Apr 13 03:06:27 2021 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
[
@@ -1,71 +0,0 @@
-from builtins import (
-    object,
-    str
-)
-
-from lxml import etree
-
-
-class GalaxyXML(object):
-    def __init__(self):
-        self.root = etree.Element("root")
-
-    def export(self):
-        return etree.tostring(self.root, pretty_print=True, encoding="unicode")
-
-
-class Util(object):
-    @classmethod
-    def coerce(cls, data, kill_lists=False):
-        """
-        Recursive data sanitisation
-
-        - recurse into lists, dicts, OrderedDict
-        - remove dict/OrderedDict entries with None value
-        - kill_lists: True -> replace lists by their first element
-        """
-        if isinstance(data, dict):
-            return {k: cls.coerce(v, kill_lists=kill_lists) for k, v in list(data.items()) if v is not None}
-        elif isinstance(data, list):
-            if kill_lists:
-                return cls.coerce(data[0])
-            else:
-                return [cls.coerce(v, kill_lists=kill_lists) for v in data]
-        else:
-            return cls.coerce_value(data)
-
-    @classmethod
-    def coerce_value(cls, obj):
-        """Make everything a string!
-        """
-        if isinstance(obj, bool):
-            if obj:
-                return "true"
-            else:
-                return "false"
-        elif isinstance(obj, str):
-            return obj
-        else:
-            return str(obj)
-
-    @classmethod
-    def clean_kwargs(cls, params, final=False):
-        if "kwargs" in params:
-            kwargs = params["kwargs"]
-            for k in kwargs:
-                params[k] = kwargs[k]
-            del params["kwargs"]
-        if "self" in params:
-            del params["self"]
-
-        if "__class__" in params:
-            del params["__class__"]
-
-        # There will be more params, it would be NICE to use a whitelist
-        # instead of a blacklist, but until we have more data let's just
-        # blacklist stuff we see commonly.
-        if final:
-            for blacklist in ("positional",):
-                if blacklist in params:
-                    del params[blacklist]
-        return params
b
diff -r 63d15caea378 -r 1dba6c7687a9 toolfactory/galaxyxml/tool/__init__.py
--- a/toolfactory/galaxyxml/tool/__init__.py Tue Apr 13 03:06:27 2021 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
[
b'@@ -1,277 +0,0 @@\n-import copy\n-import logging\n-\n-from galaxyxml import GalaxyXML, Util\n-from galaxyxml.tool.parameters import (\n-    Expand,\n-    Import,\n-    Inputs,\n-    Macro,\n-    Macros,\n-    Outputs,\n-    XMLParam\n-)\n-\n-from lxml import etree\n-\n-VALID_TOOL_TYPES = ("data_source", "data_source_async")\n-VALID_URL_METHODS = ("get", "post")\n-\n-logging.basicConfig(level=logging.INFO)\n-logger = logging.getLogger(__name__)\n-\n-\n-class Tool(GalaxyXML):\n-    def __init__(\n-        self,\n-        name,\n-        id,\n-        version,\n-        description,\n-        executable,\n-        hidden=False,\n-        tool_type=None,\n-        URL_method=None,\n-        workflow_compatible=True,\n-        interpreter=None,\n-        version_command="interpreter filename.exe --version",\n-        command_override=None,\n-        macros=[],\n-    ):\n-\n-        self.id = id\n-        self.executable = executable\n-        self.interpreter = interpreter\n-        self.command_override = command_override\n-        kwargs = {\n-            "name": name,\n-            "id": id,\n-            "version": version,\n-            "hidden": hidden,\n-            "workflow_compatible": workflow_compatible,\n-        }\n-        self.version_command = version_command\n-\n-        # Remove some of the default values to make tools look a bit nicer\n-        if not hidden:\n-            del kwargs["hidden"]\n-        if workflow_compatible:\n-            del kwargs["workflow_compatible"]\n-\n-        kwargs = Util.coerce(kwargs)\n-        self.root = etree.Element("tool", **kwargs)\n-\n-        if tool_type is not None:\n-            if tool_type not in VALID_TOOL_TYPES:\n-                raise Exception("Tool type must be one of %s" % ",".join(VALID_TOOL_TYPES))\n-            else:\n-                kwargs["tool_type"] = tool_type\n-\n-                if URL_method is not None:\n-                    if URL_method in VALID_URL_METHODS:\n-                        kwargs["URL_method"] = URL_method\n-                    else:\n-                        raise Exception("URL_method must be one of %s" % ",".join(VALID_URL_METHODS))\n-\n-        description_node = etree.SubElement(self.root, "description")\n-        description_node.text = description\n-        if len(macros) > 0:\n-            self.macros = Macros()\n-            for m in macros:\n-                self.macros.append(Import(m))\n-        self.inputs = Inputs()\n-        self.outputs = Outputs()\n-\n-    def add_comment(self, comment_txt):\n-        comment = etree.Comment(comment_txt)\n-        self.root.insert(0, comment)\n-\n-    def append_version_command(self):\n-        version_command = etree.SubElement(self.root, "version_command")\n-        try:\n-            version_command.text = etree.CDATA(self.version_command)\n-        except Exception:\n-            pass\n-\n-    def append(self, sub_node):\n-        if issubclass(type(sub_node), XMLParam):\n-            self.root.append(sub_node.node)\n-        else:\n-            self.root.append(sub_node)\n-\n-    def clean_command_string(self, command_line):\n-        clean = []\n-        for x in command_line:\n-            if x is not [] and x is not [""]:\n-                clean.append(x)\n-        return "\\n".join(clean)\n-\n-    def export(self, keep_old_command=False):\n-        # see lib/galaxy/tool_util/linters/xml_order.py\n-        export_xml = copy.deepcopy(self)\n-        try:\n-            export_xml.append(export_xml.macros)\n-        except Exception:\n-            pass\n-\n-        try:\n-            export_xml.append(export_xml.edam_operations)\n-        except Exception:\n-            pass\n-\n-        try:\n-            export_xml.append(export_xml.edam_topics)\n-        except Exception:\n-            pass\n-\n-        try:\n-            export_xml.append(export_xml.requirements)\n-        except Exception:\n-            export_xml.append(Expand(macro="requirements"))\n-\n-        # Add stdio section - now an XMLParameter\n-        try:\n-            stdio_element = export_xml.stdios\n-        except Exception:\n-            std'..b'wargs\n-        command_kwargs = {}\n-        if export_xml.interpreter is not None:\n-            command_kwargs["interpreter"] = export_xml.interpreter\n-        # Add command section\n-        command_node = etree.SubElement(export_xml.root, "command", **command_kwargs)\n-        if keep_old_command:\n-            if getattr(self, "command", None):\n-                command_node.text = etree.CDATA(export_xml.command)\n-            else:\n-                logger.warning("The tool does not have any old command stored. Only the command line is written.")\n-                command_node.text = export_xml.executable\n-        else:\n-            if self.command_override:\n-                actual_cli = export_xml.clean_command_string(command_line)\n-            else:\n-                actual_cli = "%s %s" % (export_xml.executable, export_xml.clean_command_string(command_line),)\n-            command_node.text = etree.CDATA(actual_cli.strip())\n-        export_xml.append(command_node)\n-\n-        try:\n-            export_xml.append(export_xml.configfiles)\n-        except Exception:\n-            pass\n-\n-        try:\n-            export_xml.append(export_xml.inputs)\n-        except Exception:\n-            pass\n-        try:\n-            export_xml.append(export_xml.outputs)\n-        except Exception:\n-            pass\n-\n-        try:\n-            export_xml.append(export_xml.tests)\n-        except Exception:\n-            export_xml.append(Expand(macro="%s_tests" % self.id))\n-\n-        help_element = etree.SubElement(export_xml.root, "help")\n-        help_element.text = etree.CDATA(export_xml.help)\n-        export_xml.append(help_element)\n-\n-        try:\n-            export_xml.append(export_xml.citations)\n-        except Exception:\n-            export_xml.append(Expand(macro="citations"))\n-\n-        return super(Tool, export_xml).export()\n-\n-\n-class MacrosTool(Tool):\n-    """\n-    creates a <macros> tag containing macros and tokens\n-    for the inputs and outputs:\n-\n-    for the inputs\n-\n-    - a macro `<xml name="ID_inmacro">` containing all the inputs\n-    - a token `<token name="ID_INMACRO">` containing the CLI for the inputs\n-\n-    where ID is the id used in initialization.\n-\n-    analogously for the outputs `ID_outmacro` and `ID_OUTMACRO`\n-    are created.\n-\n-    TODO all other elements, like requirements are currently ignored\n-    """\n-    def __init__(self, *args, **kwargs):\n-        super(MacrosTool, self).__init__(*args, **kwargs)\n-        self.root = etree.Element(\'macros\')\n-        self.inputs = Macro("%s_inmacro" % self.id)\n-        self.outputs = Macro("%s_outmacro" % self.id)\n-\n-\n-    def export(self, keep_old_command=False):  # noqa\n-\n-        export_xml = copy.deepcopy(self)\n-\n-        try:\n-            for child in export_xml.macros:\n-                export_xml.append(child)\n-        except Exception:\n-            pass\n-\n-        command_line = []\n-        try:\n-            command_line.append(export_xml.inputs.cli())\n-        except Exception as e:\n-            logger.warning(str(e))\n-            raise\n-\n-        # Add command section\n-        command_node = etree.SubElement(export_xml.root, \'token\', {"name": "%s_INMACRO" % self.id.upper()})\n-        actual_cli = "%s" % (export_xml.clean_command_string(command_line))\n-        command_node.text = etree.CDATA(actual_cli.strip())\n-\n-        command_line = []\n-        try:\n-            command_line.append(export_xml.outputs.cli())\n-        except Exception:\n-            pass\n-        command_node = etree.SubElement(export_xml.root, \'token\', {"name": "%s_OUTMACRO" % self.id.upper()})\n-        actual_cli = "%s" % (export_xml.clean_command_string(command_line))\n-        command_node.text = etree.CDATA(actual_cli.strip())\n-\n-        try:\n-            export_xml.append(export_xml.inputs)\n-        except Exception:\n-            pass\n-\n-        try:\n-            export_xml.append(export_xml.outputs)\n-        except Exception:\n-            pass\n-\n-        return super(Tool, export_xml).export()\n'
b
diff -r 63d15caea378 -r 1dba6c7687a9 toolfactory/galaxyxml/tool/import_xml.py
--- a/toolfactory/galaxyxml/tool/import_xml.py Tue Apr 13 03:06:27 2021 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
[
b'@@ -1,785 +0,0 @@\n-import logging\n-import xml.etree.ElementTree as ET\n-\n-import galaxyxml.tool as gxt\n-import galaxyxml.tool.parameters as gxtp\n-\n-logging.basicConfig(level=logging.INFO)\n-logger = logging.getLogger(__name__)\n-\n-\n-class GalaxyXmlParser(object):\n-    """\n-    Class to import content from an existing Galaxy XML wrapper.\n-    """\n-\n-    def _init_tool(self, xml_root):\n-        """\n-        Init tool from existing xml tool.\n-\n-        :param xml_root: root of the galaxy xml file.\n-        :type xml_root: :class:`xml.etree._Element`\n-        """\n-        version_cmd = None\n-        description = None\n-        for child in xml_root:\n-            if child.tag == "description":\n-                description = child.text\n-            elif child.tag == "command":\n-                executable = child.text.split()[0]\n-                command = child.text\n-            elif child.tag == "version_command":\n-                version_cmd = child.text\n-\n-        tool = gxt.Tool(\n-            xml_root.attrib["name"],\n-            xml_root.attrib["id"],\n-            xml_root.attrib.get("version", None),\n-            description,\n-            executable,\n-            hidden=xml_root.attrib.get("hidden", False),\n-            tool_type=xml_root.attrib.get("tool_type", None),\n-            URL_method=xml_root.attrib.get("URL_method", None),\n-            workflow_compatible=xml_root.attrib.get("workflow_compatible", True),\n-            version_command=version_cmd,\n-        )\n-        tool.command = command\n-        return tool\n-\n-    def _load_description(self, tool, desc_root):\n-        """\n-        <description> is already loaded during initiation.\n-\n-        :param tool: Tool object from galaxyxml.\n-        :type tool: :class:`galaxyxml.tool.Tool`\n-        :param desc_root: root of <description> tag.\n-        :type desc_root: :class:`xml.etree._Element`\n-        """\n-        logger.info("<description> is loaded during initiation of the object.")\n-\n-    def _load_version_command(self, tool, vers_root):\n-        """\n-        <version_command> is already loaded during initiation.\n-\n-        :param tool: Tool object from galaxyxml.\n-        :type tool: :class:`galaxyxml.tool.Tool`\n-        :param vers_root: root of <version_command> tag.\n-        :type vers_root: :class:`xml.etree._Element`\n-        """\n-        logger.info("<version_command> is loaded during initiation of the object.")\n-\n-    def _load_stdio(self, tool, stdio_root):\n-        """\n-\n-        :param tool: <test> root to append <stdio> to.\n-        :param stdio_root: root of <param> tag.\n-        :param stdio_root: :class:`xml.etree._Element`\n-        """\n-        tool.stdios = gxtp.Stdios()\n-        for std in stdio_root:\n-            slevel = std.attrib[\'level\']\n-            srange = std.attrib[\'range\']\n-            tool.stdios.append(gxtp.Stdio(level=slevel, range=srange))\n-        logger.info("<stdio> loaded.")\n-\n-    def _load_command(self, tool, desc_root):\n-        """\n-        <command> is already loaded during initiation.\n-\n-        :param tool: Tool object from galaxyxml.\n-        :type tool: :class:`galaxyxml.tool.Tool`\n-        :param desc_root: root of <command> tag.\n-        :type desc_root: :class:`xml.etree._Element`\n-        """\n-        logger.info("<command> is loaded during initiation of the object.")\n-\n-    def _load_help(self, tool, help_root):\n-        """\n-        Load the content of the <help> into the tool.\n-\n-        :param tool: Tool object from galaxyxml.\n-        :type tool: :class:`galaxyxml.tool.Tool`\n-        :param requirements_root: root of <help> tag.\n-        :type requirements_root: :class:`xml.etree._Element`\n-        """\n-        tool.help = help_root.text\n-\n-    def _load_requirements(self, tool, requirements_root):\n-        """\n-        Add <requirements> to the tool.\n-\n-        :param tool: Tool object from galaxyxml.\n-        :type tool: :class:`galaxyxml.tool.Tool`\n-        :param requirements_root: root of <requirements> tag.\n-   '..b'file=output_root.attrib.get("file", None),\n-                ftype=output_root.attrib.get("ftype", None),\n-                sort=output_root.attrib.get("sort", None),\n-                value=output_root.attrib.get("value", None),\n-                md5=output_root.attrib.get("md5", None),\n-                checksum=output_root.attrib.get("checksum", None),\n-                compare=output_root.attrib.get("compare", None),\n-                lines_diff=output_root.attrib.get("lines_diff", None),\n-                delta=output_root.attrib.get("delta", None),\n-            )\n-        )\n-\n-    def _load_output_collection(self, test_root, output_root):\n-        """\n-        Add <output_collection> to the <test>.\n-\n-        :param root: <test> root to append <output> to.\n-        :param repeat_root: root of <output_collection> tag.\n-        :param repeat_root: :class:`xml.etree._Element`\n-        """\n-        collection = gxtp.TestOutputCollection(\n-            name=output_root.attrib.get("name", None),\n-            ftype=output_root.attrib.get("ftype", None),\n-            sort=output_root.attrib.get("sort", None),\n-            value=output_root.attrib.get("value", None),\n-            compare=output_root.attrib.get("compare", None),\n-            lines_diff=output_root.attrib.get("lines_diff", None),\n-            delta=output_root.attrib.get("delta", None),\n-        )\n-        # Deal with child nodes\n-        self.load_inputs(collection, output_root)\n-        test_root.append(collection)\n-\n-    def _load_element(self, test_root, element_root):\n-        """\n-        Add <element> to the <test>.\n-\n-        :param root: <test> root to append <output> to.\n-        :param repeat_root: root of <output_collection> tag.\n-        :param repeat_root: :class:`xml.etree._Element`\n-        """\n-        test_root.append(gxtp.TestOCElement(\n-            name=element_root.attrib.get("name", None),\n-            ftype=element_root.attrib.get("ftype", None),\n-            file=element_root.attrib.get("file", None)\n-        )\n-        )\n-\n-    def _load_repeat(self, test_root, repeat_root):\n-        """\n-        Add <repeat> to the <test>.\n-\n-        :param root: <test> root to append <output> to.\n-        :param output_root: root of <repeat> tag.\n-        :param output_root: :class:`xml.etree._Element`\n-        """\n-        repeat = gxtp.TestRepeat(\n-            repeat_root.attrib.get("name", None),\n-            repeat_root.attrib.get("title", None),\n-            min=repeat_root.attrib.get("min", None),\n-            max=repeat_root.attrib.get("max", None),\n-            default=repeat_root.attrib.get("default", None)\n-        )\n-        # Deal with child nodes\n-        self.load_inputs(repeat, repeat_root)\n-        test_root.append(repeat)\n-\n-    def load_inputs(self, repeat, repeat_root):\n-        """\n-        Add children to repeat/collection for test\n-\n-        :param repeat_root: repeat to attach inputs to.\n-        :param repeat: root of <repeat> or <collection> tag.\n-        :type repeat_root: :class:`xml.etree._Element`\n-        """\n-        for rep_child in repeat_root:\n-            try:\n-                getattr(self, "_load_{}".format(rep_child.tag))(repeat, rep_child)\n-            except AttributeError:\n-                logger.warning(rep_child.tag + " tag is not processed for <" + repeat_root.tag + "> tag.")\n-\n-    def load_tests(self, root, tests_root):\n-        """\n-        Add <tests> to the root.\n-\n-        :param root: root to attach <tests> to (<tool>).\n-        :param tests_root: root of <tests> tag.\n-        :type tests_root: :class:`xml.etree._Element`\n-        """\n-        for test_root in tests_root:\n-            test = gxtp.Test()\n-            for test_child in test_root:\n-                try:\n-                    getattr(self, "_load_{}".format(test_child.tag))(test, test_child)\n-                except AttributeError:\n-                    logger.warning(test_child.tag + " tag is not processed within <test>.")\n-            root.append(test)\n'
b
diff -r 63d15caea378 -r 1dba6c7687a9 toolfactory/galaxyxml/tool/parameters/__init__.py
--- a/toolfactory/galaxyxml/tool/parameters/__init__.py Tue Apr 13 03:06:27 2021 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
[
b'@@ -1,1012 +0,0 @@\n-import logging\n-from builtins import (\n-    object,\n-    str\n-)\n-\n-from galaxy.tool_util.parser.util import _parse_name\n-\n-from galaxyxml import Util\n-\n-from lxml import etree\n-\n-logging.basicConfig(level=logging.INFO)\n-logger = logging.getLogger(__name__)\n-\n-\n-class XMLParam(object):\n-    name = "node"\n-\n-    def __init__(self, *args, **kwargs):\n-        # http://stackoverflow.com/a/12118700\n-        self.children = []\n-        self.parent = None\n-        kwargs = {k: v for k, v in list(kwargs.items()) if v is not None}\n-        kwargs = Util.coerce(kwargs, kill_lists=True)\n-        kwargs = Util.clean_kwargs(kwargs, final=True)\n-        self.node = etree.Element(self.name, **kwargs)\n-\n-    def __getattr__(self, name):\n-        """\n-        Allow to access keys of the node "attributes" (i.e. the dict\n-        self.node.attrib) as attributes.\n-        """\n-        # https://stackoverflow.com/questions/47299243/recursionerror-when-python-copy-deepcopy\n-        if name == "__setstate__":\n-            raise AttributeError(name)\n-        try:\n-            return self.node.attrib[name]\n-        except KeyError:\n-            raise AttributeError(name)\n-\n-    def append(self, sub_node):\n-        if self.acceptable_child(sub_node):\n-            # If one of ours, they aren\'t etree nodes, they\'re custom objects\n-            if issubclass(type(sub_node), XMLParam):\n-                self.node.append(sub_node.node)\n-                self.children.append(sub_node)\n-                self.children[-1].parent = self\n-            else:\n-                raise Exception(\n-                    "Child was unacceptable to parent (%s is not appropriate for %s)" % (type(self), type(sub_node))\n-                )\n-        else:\n-            raise Exception(\n-                "Child was unacceptable to parent (%s is not appropriate for %s)" % (type(self), type(sub_node))\n-            )\n-\n-    def validate(self):\n-        # Very few need validation, but some nodes we may want to have\n-        # validation routines on. Should only be called when DONE.\n-        for child in self.children:\n-            # If any child fails to validate return false.\n-            if not child.validate():\n-                return False\n-        return True\n-\n-    def cli(self):\n-        lines = []\n-        for child in self.children:\n-            lines.append(child.command_line())\n-        return "\\n".join(lines)\n-\n-    def command_line(self, mako_path=None):\n-        """\n-        genetate the command line for the node (and its childres)\n-\n-        mako_path override the path to the node\n-        """\n-        return None\n-\n-\n-class Stdios(XMLParam):\n-    name = "stdio"\n-\n-    def acceptable_child(self, child):\n-        return isinstance(child, Stdio)\n-\n-\n-class Stdio(XMLParam):\n-    name = "exit_code"\n-\n-    def __init__(self, range="1:", level="fatal", **kwargs):\n-        params = Util.clean_kwargs(locals().copy())\n-        super(Stdio, self).__init__(**params)\n-\n-\n-class Macros(XMLParam):\n-    name = "macros"\n-\n-    def acceptable_child(self, child):\n-        return isinstance(child, (Macro, Import))\n-\n-\n-class Macro(XMLParam):\n-    name = "xml"\n-\n-    def __init__(self, name):\n-        params = Util.clean_kwargs(locals().copy())\n-        passed_kwargs = {}\n-        passed_kwargs[\'name\'] = params[\'name\']\n-        super(Macro, self).__init__(**passed_kwargs)\n-\n-    def acceptable_child(self, child):\n-        return issubclass(type(child), XMLParam) and not isinstance(child, Macro)\n-\n-\n-class Import(XMLParam):\n-    name = "import"\n-\n-    def __init__(self, value):\n-        super(Import, self).__init__()\n-        self.node.text = value\n-\n-    def acceptable_child(self, child):\n-        return issubclass(type(child), XMLParam) and not isinstance(child, Macro)\n-\n-\n-class Expand(XMLParam):\n-    """\n-    <expand macro="...">\n-    """\n-    name = "expand"\n-\n-    def __init__(self, macro):\n-        params = Util.clean_kwargs(locals().copy())\n-        passed_kwargs = {}'..b'\n-\n-    def acceptable_child(self, child):\n-        return issubclass(type(child), Test) \\\n-            or isinstance(child, Expand)\n-\n-\n-class Test(XMLParam):\n-    name = "test"\n-\n-    def acceptable_child(self, child):\n-        return isinstance(child, TestParam) \\\n-            or isinstance(child, TestOutput) \\\n-            or isinstance(child, TestOutputCollection) \\\n-            or isinstance(child, TestRepeat) \\\n-            or isinstance(child, Expand)\n-\n-\n-class TestParam(XMLParam):\n-    name = "param"\n-\n-    def __init__(self, name, value=None, ftype=None, dbkey=None, **kwargs):\n-        params = Util.clean_kwargs(locals().copy())\n-        super(TestParam, self).__init__(**params)\n-\n-\n-class TestOutput(XMLParam):\n-    name = "output"\n-\n-    def __init__(\n-        self,\n-        name=None,\n-        file=None,\n-        ftype=None,\n-        sort=None,\n-        value=None,\n-        md5=None,\n-        checksum=None,\n-        compare=None,\n-        lines_diff=None,\n-        delta=None,\n-        **kwargs,\n-    ):\n-        params = Util.clean_kwargs(locals().copy())\n-        super(TestOutput, self).__init__(**params)\n-\n-\n-class TestOCElement(XMLParam):\n-    name = "element"\n-\n-    def __init__(self, name=None, file=None, ftype=None, **kwargs):\n-        params = Util.clean_kwargs(locals().copy())\n-        super(TestOCElement, self).__init__(**params)\n-\n-\n-class TestOutputCollection(XMLParam):\n-    name = "output_collection"\n-\n-    def __init__(\n-        self,\n-        name=None,\n-        ftype=None,\n-        sort=None,\n-        value=None,\n-        compare=None,\n-        lines_diff=None,\n-        delta=None,\n-        **kwargs,\n-    ):\n-        params = Util.clean_kwargs(locals().copy())\n-        super(TestOutputCollection, self).__init__(**params)\n-\n-    def acceptable_child(self, child):\n-        return isinstance(child, TestOCElement)\n-\n-    def command_line_before(self, mako_path):\n-        return "<output_collection name = \'%s\'>" % self.name\n-\n-    def command_line_after(self):\n-        return "</output_collection>"\n-\n-    def command_line_actual(self, mako_path):\n-        lines = []\n-        for child in self.children:\n-            lines.append(child.command_line())\n-        return "\\n".join(lines)\n-\n-\n-class TestRepeat(XMLParam):\n-    name = "repeat"\n-\n-    def __init__(\n-        self,\n-        name=None,\n-        ftype=None,\n-        sort=None,\n-        value=None,\n-        compare=None,\n-        lines_diff=None,\n-        delta=None,\n-        **kwargs,\n-    ):\n-        params = Util.clean_kwargs(locals().copy())\n-        super(TestRepeat, self).__init__(**params)\n-\n-    def acceptable_child(self, child):\n-        return issubclass(type(child), TestParam) \\\n-            or issubclass(type(child), TestOutput) \\\n-            or issubclass(type(child), TestOutputCollection)\n-\n-    def command_line_before(self, mako_path):\n-        return "<repeat name = \'%s\'>" % self.name\n-\n-    def command_line_after(self):\n-        return "</repeat>"\n-\n-    def command_line_actual(self, mako_path):\n-        lines = []\n-        for child in self.children:\n-            lines.append(child.command_line())\n-        return "\\n".join(lines)\n-\n-\n-class Citations(XMLParam):\n-    name = "citations"\n-\n-    def acceptable_child(self, child):\n-        return issubclass(type(child), Citation) \\\n-            or isinstance(child, Expand)\n-\n-    def has_citation(self, type, value):\n-        """\n-        Check the presence of a given citation.\n-\n-        :type type: STRING\n-        :type value: STRING\n-        """\n-        for citation in self.children:\n-            if citation.node.attrib[\'type\'] == type \\\n-               and citation.node.text == value:\n-                return True\n-        return False\n-\n-\n-class Citation(XMLParam):\n-    name = "citation"\n-\n-    def __init__(self, type, value):\n-        passed_kwargs = {}\n-        passed_kwargs["type"] = type\n-        super(Citation, self).__init__(**passed_kwargs)\n-        self.node.text = str(value)\n'
b
diff -r 63d15caea378 -r 1dba6c7687a9 toolfactory/rgToolFactory2.py
--- a/toolfactory/rgToolFactory2.py Tue Apr 13 03:06:27 2021 +0000
+++ b/toolfactory/rgToolFactory2.py Wed Apr 14 07:05:22 2021 +0000
[
@@ -1044,9 +1044,9 @@
         supplied test outputs are sent to repdir for display
         """
         penv = os.environ
-        pconfig = os.path.join(self.args.tool_dir,'.planemo.yml')
+        pconfig = os.path.join(self.args.tool_dir, '.planemo.yml')
         penv["PLANEMO_GLOBAL_CONFIG_PATH"] = pconfig
-        self.set_planemo_galaxy_root(self.args.galaxy_root,config_path=pconfig)
+        self.set_planemo_galaxy_root(self.args.galaxy_root, config_path=pconfig)
         xreal = "%s.xml" % self.tool_name
         tool_test_path = os.path.join(
             self.repdir, f"{self.tool_name}_planemo_test_report.html"
@@ -1071,7 +1071,7 @@
         p = subprocess.run(
             cll,
             shell=False,
-            env = penv,
+            env=penv,
             cwd=self.tooloutdir,
             stderr=tout,
             stdout=tout,
@@ -1081,7 +1081,7 @@
 
     def set_planemo_galaxy_root(self, galaxyroot='/galaxy-central', config_path=".planemo.yml"):
         # bug in planemo - bogus '--dev-wheels' passed to run_tests.sh as at april 2021 - need a fiddled copy so it is ignored until fixed
-        CONFIG_TEMPLATE = f"""## Planemo Global Configuration File.
+        CONFIG_TEMPLATE = """## Planemo Global Configuration File.
 ## Everything in this file is completely optional - these values can all be
 ## configured via command line options for the corresponding commands.
 
b
diff -r 63d15caea378 -r 1dba6c7687a9 toolfactory/rgToolFactory2.xml
--- a/toolfactory/rgToolFactory2.xml Tue Apr 13 03:06:27 2021 +0000
+++ b/toolfactory/rgToolFactory2.xml Wed Apr 14 07:05:22 2021 +0000
b
@@ -180,7 +180,7 @@
   </macros>
 
 <requirements>
-   <!-- <requirement type="package" version="0.4.13">galaxyxml</requirement> -->
+   <requirement type="package" version="0.4.14">galaxyxml</requirement>
    <requirement type="package" version="0.15.0">bioblend</requirement>
    <requirement type="package" version="0.10.6">ephemeris</requirement>
    <requirement type="package" version="0.74.3">planemo</requirement>