Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ script:
- flake8 galaxyxml --ignore=E2,E3,E4,E5,W3,W505,C901,E501
- python examples/example.py > tmp.xml
- xmldiff tmp.xml examples/tool.xml
- python examples/example_macros.py > tmp.xml
- xmldiff tmp.xml examples/example_macros.xml
- nosetests --with-coverage --cover-package=galaxyxml
deploy:
provider: pypi
Expand Down
109 changes: 109 additions & 0 deletions examples/example_macros.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
#!/usr/bin/env python
import galaxyxml.tool as gxt
import galaxyxml.tool.parameters as gxtp

# examplify the use of MacrosTool
#

tool = gxt.MacrosTool(
name="aragorn",
id="aragorn",
version="1.2.36",
description="Aragorn is a tRNA finder",
executable="aragorn.exe",
version_command="aragorn.exe --version",
)

inputs = tool.inputs
outputs = tool.outputs

# Add requirements
requirements = gxtp.Requirements()
requirements.append(gxtp.Requirement("package", "samtools", version="1.0.0"))
requirements.append(gxtp.Container("docker", "one_super_image"))
tool.requirements = requirements

# A parameter
param = gxtp.BooleanParam("flag", label="Flag label", help="Flag help", num_dashes=1)
# Yes I know this is rubbish. Please make a PR!!
param.space_between_arg = " "
inputs.append(param)


# A float in a section
section = gxtp.Section("float_section", "Float section")
param = gxtp.FloatParam("float", label="Float label", help="Float help", value=0, num_dashes=1)
param.space_between_arg = " "
section.append(param)
inputs.append(section)

# A conditional
param = gxtp.Conditional("cond", label="Conditional")
param.append(gxtp.SelectParam("Select", options={"hi": "1", "bye": "2"}))
when_a = gxtp.When(value="hi")
when_b = gxtp.When(value="bye")
when_b.append(gxtp.IntegerParam("some_int", value=0, num_dashes=1, label="Advanced value"))
param.append(when_a)
param.append(when_b)
inputs.append(param)

# Integer parameters
param_min = gxtp.IntegerParam("int_min", label="int_min label", help="int_min help", value=0, num_dashes=1)
param_max = gxtp.IntegerParam("int_max", label="int_max label", help="int_max help", value=0, num_dashes=1)

posint = gxtp.IntegerParam("posint", label="posint label", positional=True, help="posinthelp", value=0, num_dashes=2)

param_min.command_line_override = "-i$int_min,$int_max"
param_max.command_line_override = ""
param_min.space_between_arg = " "
param_max.space_between_arg = " "
inputs.append(param_min)
inputs.append(param_max)
inputs.append(posint)

# Add Select with options from_file with columns and filter
param = gxtp.SelectParam("select_local")
options = gxtp.Options(from_file="loc_file.loc")
column_a = gxtp.Column("name", 0)
options.append(column_a)
column_b = gxtp.Column("value", 1)
options.append(column_b)
filter_a = gxtp.Filter("sort_by", name="sorted", column="1")
options.append(filter_a)
param.append(options)
inputs.append(param)

# Configfiles
configfiles = gxtp.Configfiles()
configfiles.append(gxtp.Configfile(name="testing", text="Hello <> World"))
configfiles.append(gxtp.ConfigfileDefaultInputs(name="inputs"))

# Outputs
param = gxtp.OutputData("output", format="tabular", num_dashes=1)
param.space_between_arg = " "
outputs.append(param)
# Collection
collection = gxtp.OutputCollection("supercollection", label="a small label")
discover = gxtp.DiscoverDatasets("(?P&lt;designation&gt;.+)\.pdf.fasta", format="fasta")
collection.append(discover)
outputs.append(collection)

tool.inputs = inputs
tool.outputs = outputs
tool.help = "HI"
tool.configfiles = configfiles

# Add Tests sections
tool.tests = gxtp.Tests()
test_a = gxtp.Test()
param = gxtp.TestParam("float", value=5.4)
test_a.append(param)
test_out = gxtp.TestOutput(name="output", value="file.out")
test_a.append(test_out)
tool.tests.append(test_a)


# Add comment to the wrapper
tool.add_comment("This tool descriptor has been generated using galaxyxml.")

print(tool.export())
47 changes: 47 additions & 0 deletions examples/example_macros.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<macros>
<!--This tool descriptor has been generated using galaxyxml.-->
<token name="ARAGORN_INMACRO"><![CDATA[$flag
-float $float_section.float
#if str($cond.Select) == "bye"
-some_int $cond.some_int
#end if
-i$int_min,$int_max

$posint
select_local $select_local]]></token>
<token name="ARAGORN_OUTMACRO"><![CDATA[-output '$output'
## TODO CLI for OutputCollection collection]]></token>
<xml name="aragorn_inmacro">
<param name="flag" type="boolean" label="Flag label" help="Flag help" checked="false" truevalue="-flag" falsevalue=""/>
<section name="float_section" title="Float section">
<param name="float" type="float" value="0" label="Float label" help="Float help"/>
</section>
<conditional name="cond" label="Conditional">
<param name="Select" type="select" label="Author did not provide help for this parameter... ">
<option value="bye">2</option>
<option value="hi">1</option>
</param>
<when value="hi"/>
<when value="bye">
<param name="some_int" type="integer" value="0" label="Advanced value"/>
</when>
</conditional>
<param name="int_min" type="integer" value="0" label="int_min label" help="int_min help"/>
<param name="int_max" type="integer" value="0" label="int_max label" help="int_max help"/>
<param name="posint" type="integer" value="0" label="posint label" help="posinthelp"/>
<param name="select_local" type="select" label="Author did not provide help for this parameter... ">
<options from_file="loc_file.loc">
<column name="name" index="0"/>
<column name="value" index="1"/>
<filter name="sorted" type="sort_by" column="1"/>
</options>
</param>
</xml>
<xml name="aragorn_outmacro">
<data name="output" format="tabular" hidden="false"/>
<collection name="supercollection" label="a small label">
<discover_datasets pattern="(?P&amp;lt;designation&amp;gt;.+)\.pdf.fasta" format="fasta"/>
</collection>
</xml>
</macros>

14 changes: 8 additions & 6 deletions examples/tool.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,20 @@
<stdio>
<exit_code range="1:" level="fatal"/>
</stdio>
<expand macro="stdio"/>
<version_command><![CDATA[aragorn.exe --version]]></version_command>
<command><![CDATA[aragorn.exe $flag
-float $float
--float-fromarg $float_fromarg
#if str($Select) == "bye"
-some_int $some_int
-float $float_section.float
--float-fromarg $float_section.float_fromarg
#if str($cond.Select) == "bye"
-some_int $cond.some_int
#end if
-i$int_min,$int_max

$posint
select_local $select_local
#for $i in $repeat:
--data $data
#for $i_repeat in $repeat
--data $i_repeat.data
#end for]]></command>
<configfiles>
<configfile name="testing"><![CDATA[Hello <> World]]></configfile>
Expand Down Expand Up @@ -69,5 +70,6 @@ select_local $select_local
</test>
</tests>
<help><![CDATA[HI]]></help>
<expand macro="citations"/>
</tool>

13 changes: 10 additions & 3 deletions galaxyxml/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from builtins import object
from builtins import str
from builtins import (
str,
object
)

from lxml import etree

Expand All @@ -15,7 +17,12 @@ def export(self):
class Util(object):
@classmethod
def coerce(cls, data, kill_lists=False):
"""Recursive data sanitisation
"""
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}
Expand Down
101 changes: 96 additions & 5 deletions galaxyxml/tool/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,15 @@
import logging

from galaxyxml import GalaxyXML, Util
from galaxyxml.tool.parameters import XMLParam
from galaxyxml.tool.parameters import (
Expand,
Import,
Inputs,
Macro,
Macros,
Outputs,
XMLParam
)

from lxml import etree

Expand All @@ -28,8 +36,10 @@ def __init__(
interpreter=None,
version_command="interpreter filename.exe --version",
command_override=None,
macros=[],
):

self.id = id
self.executable = executable
self.interpreter = interpreter
self.command_override = command_override
Expand Down Expand Up @@ -65,6 +75,12 @@ def __init__(

description_node = etree.SubElement(self.root, "description")
description_node.text = description
if len(macros) > 0:
self.macros = Macros()
for m in macros:
self.macros.append(Import(m))
self.inputs = Inputs()
self.outputs = Outputs()

def add_comment(self, comment_txt):
comment = etree.Comment(comment_txt)
Expand All @@ -88,12 +104,15 @@ def clean_command_string(self, command_line):
for x in command_line:
if x is not [] and x is not [""]:
clean.append(x)

return "\n".join(clean)

def export(self, keep_old_command=False):
# see lib/galaxy/tool_util/linters/xml_order.py
export_xml = copy.deepcopy(self)
try:
export_xml.append(export_xml.macros)
except Exception:
pass

try:
export_xml.append(export_xml.edam_operations)
Expand All @@ -108,7 +127,7 @@ def export(self, keep_old_command=False):
try:
export_xml.append(export_xml.requirements)
except Exception:
pass
export_xml.append(Expand(macro="requirements"))

# Add stdio section - now an XMLParameter
try:
Expand All @@ -118,7 +137,10 @@ def export(self, keep_old_command=False):
if not stdio_element:
stdio_element = etree.SubElement(export_xml.root, "stdio")
etree.SubElement(stdio_element, "exit_code", range="1:", level="fatal")
export_xml.append(stdio_element)
try:
export_xml.append(export_xml.stdio)
except Exception:
export_xml.append(Expand(macro="stdio"))

# Append version command
export_xml.append_version_command()
Expand All @@ -131,6 +153,7 @@ def export(self, keep_old_command=False):
command_line.append(export_xml.inputs.cli())
except Exception as e:
logger.warning(str(e))
raise
try:
command_line.append(export_xml.outputs.cli())
except Exception:
Expand Down Expand Up @@ -172,14 +195,82 @@ def export(self, keep_old_command=False):
try:
export_xml.append(export_xml.tests)
except Exception:
pass
export_xml.append(Expand(macro="%s_tests" % self.id))

help_element = etree.SubElement(export_xml.root, "help")
help_element.text = etree.CDATA(export_xml.help)
export_xml.append(help_element)

try:
export_xml.append(export_xml.citations)
except Exception:
export_xml.append(Expand(macro="citations"))

return super(Tool, export_xml).export()


class MacrosTool(Tool):
"""
creates a <macros> tag containing macros and tokens
for the inputs and outputs:

for the inputs

- a macro `<xml name="ID_inmacro">` containing all the inputs
- a token `<token name="ID_INMACRO">` containing the CLI for the inputs

where ID is the id used in initialization.

analogously for the outputs `ID_outmacro` and `ID_OUTMACRO`
are created.

TODO all other elements, like requirements are currently ignored
"""
def __init__(self, *args, **kwargs):
super(MacrosTool, self).__init__(*args, **kwargs)
self.root = etree.Element('macros')
self.inputs = Macro("%s_inmacro" % self.id)
self.outputs = Macro("%s_outmacro" % self.id)


def export(self, keep_old_command=False): # noqa

export_xml = copy.deepcopy(self)

try:
for child in export_xml.macros:
export_xml.append(child)
except Exception:
pass

command_line = []
try:
command_line.append(export_xml.inputs.cli())
except Exception as e:
logger.warning(str(e))
raise

# Add command section
command_node = etree.SubElement(export_xml.root, 'token', {"name": "%s_INMACRO" % self.id.upper()})
actual_cli = "%s" % (export_xml.clean_command_string(command_line))
command_node.text = etree.CDATA(actual_cli.strip())

command_line = []
try:
command_line.append(export_xml.outputs.cli())
except Exception:
pass
command_node = etree.SubElement(export_xml.root, 'token', {"name": "%s_OUTMACRO" % self.id.upper()})
actual_cli = "%s" % (export_xml.clean_command_string(command_line))
command_node.text = etree.CDATA(actual_cli.strip())

try:
export_xml.append(export_xml.inputs)
except Exception:
pass

try:
export_xml.append(export_xml.outputs)
except Exception:
pass

Expand Down
Loading