Permalink
Browse files

Add --macros flag to tool_init command.

Will pull citations, requirements, stdio, and version_command out into an imported macros file. Subsequent suite definitions in the same directory generated with --macros will reuse the same file.

Fixes to lint and extensions to testing to enable this.
  • Loading branch information...
jmchilton committed Mar 12, 2015
1 parent ab06ff6 commit ec6e30f8f7106bb749d13d8796145507e6c3d87d
Showing with 91 additions and 21 deletions.
  1. +5 −0 planemo/commands/cmd_lint.py
  2. +16 −0 planemo/commands/cmd_tool_init.py
  3. +58 −5 planemo/tool_builder.py
  4. +11 −16 tests/test_build_and_lint.py
  5. +1 −0 tests/test_utils.py
@@ -34,6 +34,7 @@ def cli(ctx, path, report_level="all", fail_level="warn"):
exit = 0
lint_args = dict(level=report_level, fail_level=fail_level)
tools = load_tool_elements_from_path(path, load_exception_handler)
valid_tools = 0
for (tool_path, tool_xml) in tools:
if tool_xml.getroot().tag != "tool":
if ctx.verbose:
@@ -42,6 +43,10 @@ def cli(ctx, path, report_level="all", fail_level="warn"):
info("Linting tool %s" % tool_path)
if not lint_xml(tool_xml, **lint_args):
exit = 1
else:
valid_tools += 1
if exit == 0 and valid_tools == 0:
exit = 2
sys.exit(exit)


@@ -4,6 +4,9 @@
from planemo import io
from planemo import tool_builder

REUSING_MACROS_MESSAGE = ("Macros file macros.xml already exists, assuming "
" it has relevant planemo-generated definitions.")


# --input_format
# --output_format
@@ -169,6 +172,13 @@
help=("For use with --example_commmand, generate a tool test case from "
"the supplied example."),
)
@click.option(
"--macros",
is_flag=True,
default=None,
prompt=False,
help="Generate a macros.xml for reuse across many tools.",
)
@click.command("tool_init")
@pass_context
def cli(ctx, **kwds):
@@ -186,6 +196,12 @@ def cli(ctx, **kwds):
tool_description = tool_builder.build(**kwds)
open(output, "w").write(tool_description.contents)
io.info("Tool written to %s" % output)
macros = kwds["macros"]
macros_file = "macros.xml"
if macros and not os.path.exists(macros_file):
open(macros_file, "w").write(tool_description.macro_contents)
else:
io.info(REUSING_MACROS_MESSAGE)
if tool_description.test_files:
if not os.path.exists("test-data"):
io.info("No test-data directory, creating one.")
@@ -10,6 +10,16 @@
{%- if description %}
<description>{{ description }}</description>
{% endif %}
{%- if macros %}
<macros>
<import>macros.xml</import>
</macros>
<expand macro="requirements" />
<expand macro="stdio" />
{%- if version_command %}
<expand macro="version_command" />
{% endif %}
{%- else %}
<stdio>
<exit_code range="1:" />
</stdio>
@@ -24,6 +34,7 @@
{%- if version_command %}
<version_command>{{ version_command }}</version_command>
{%- endif %}
{% endif %}
<command><![CDATA[
{%- if command %}
{{ command }}
@@ -62,16 +73,53 @@
TODO: Fill in help.
{%- endif %}
]]></help>
{%- if macros %}
<expand macro="citations" />
{%- else %}
{%- if doi %}
<citations>
{%- for single_doi in doi %}
<citation type="doi">{{ single_doi }}</citation>
{%- endfor %}
</citations>
{%- endif %}
{%- endif %}
</tool>
"""

MACROS_TEMPLATE = """<macros>
<xml name="requirements">
<requirements>
{%- for requirement in requirements %}
{{ requirement }}
{%- endfor %}
<yield/>
{%- for container in containers %}
{{ container }}
{%- endfor %}
</requirements>
</xml>
<xml name="stdio">
<stdio>
<exit_code range="1:" />
</stdio>
</xml>
<xml name="citations">
<citations>
{%- for single_doi in doi %}
<citation type="doi">{{ single_doi }}</citation>
{%- endfor %}
<yield />
</citations>
</xml>
{%- if version_command %}
<xml name="version_command">
<version_command>{{ version_command }}</version_command>
</xml>
{%- endif %}
</macros>
"""


def build(**kwds):
if Template is None:
@@ -131,16 +179,20 @@ def build(**kwds):
kwds["tests"] = tests

# Render tool content from template.
contents = _render_tool(kwds)
contents = _render(kwds)

macro_contents = None
if kwds["macros"]:
macro_contents = _render(kwds, MACROS_TEMPLATE)

return ToolDescription(contents, test_files)
return ToolDescription(contents, macro_contents, test_files)


def _render_tool(kwds):
def _render(kwds, template_str=TOOL_TEMPLATE):
""" Apply supplied template variables to TOOL_TEMPLATE to generate
the final tool.
"""
template = Template(TOOL_TEMPLATE)
template = Template(template_str)
contents = template.render(**kwds)
return contents

@@ -227,8 +279,9 @@ def _find_command(kwds):

class ToolDescription(object):

def __init__(self, contents, test_files):
def __init__(self, contents, macro_contents, test_files):
self.contents = contents
self.macro_contents = macro_contents
self.test_files = test_files


@@ -1,28 +1,21 @@

import os
from .test_utils import CliTestCase


INIT_COMMAND = [
"tool_init", "--force",
"--id", "seqtk_seq",
"--name", "Convert to FASTA (seqtk)",
"--requirement", "seqtk@1.0-r68",
"--example_command", "seqtk seq -a 2.fastq > 2.fasta",
"--example_input", "2.fastq",
"--example_output", "2.fasta",
"--test_case",
"--help_text", "The help text.",
"--doi", "10.1101/014043"
]


class BuildAndLintTestCase(CliTestCase):

def test_build_and_lint(self):
with self._isolate():
self._check_exit_code(_init_command())
self._check_lint(exit_code=0)

def test_build_and_lint_with_macros(self):
with self._isolate() as f:
self._check_exit_code(_init_command(macros=True))
self._check_lint(exit_code=0)
macros_file = os.path.join(f, "macros.xml")
assert os.path.exists(macros_file)

def test_lint_fails_if_no_help(self):
with self._isolate():
self._check_exit_code(_init_command(help_text=False))
@@ -43,7 +36,7 @@ def _check_lint(self, exit_code=0):
self._check_exit_code(lint_cmd, exit_code=exit_code)


def _init_command(test_case=True, help_text=True, doi=True):
def _init_command(test_case=True, help_text=True, doi=True, macros=False):
command = [
"tool_init", "--force",
"--id", "seqtk_seq",
@@ -59,4 +52,6 @@ def _init_command(test_case=True, help_text=True, doi=True):
command.extend(["--help_text", "The help text."])
if doi:
command.extend(["--doi", "10.1101/014043"])
if macros:
command.append("--macros")
return command
@@ -43,6 +43,7 @@ def _check_exit_code(self, command_list, exit_code=0):
result.output,
)
raise AssertionError(message)
return result


__all__ = [

0 comments on commit ec6e30f

Please sign in to comment.