Advanced GetOpt Wrapper
Project description
How to use it
You write stuff that looks like this, containing all of the information you would ever need about a tool; options, test cases, metadata
"""
DESCRIPTION
===========
Print out options passed to it
"""
from galaxygetopt.ggo import GalaxyGetOpt as GGO
c = GGO(
options=[
['int', 'An integer parameter', {'required': True, 'validate':
'Int', 'default': 10}],
['float', 'A float', {'required': True, 'validate': 'Float',
'default': 1e-4}],
['string', 'A string value', {'required': True, 'multiple': True,
'default': ['Hello', 'World'],
'validate': 'String'}],
[],
['Advanced'],
['option', 'A selection type parameter', {'required': False,
'validate': 'Option',
'options': {'a': 'Alpha',
'b': 'Bravo'}
}],
],
outputs=[
[
'test_output',
'Main output file of this utility',
{
'validate': 'File/Output',
'required': True,
'default': 'ggo_out.complex',
'data_format': 'text/tabular',
'default_format': 'TSV_U',
}
]
],
defaults={
'appid': 'ggo.testscript.complex',
'appname': 'GGO Complex Test Script',
'appdesc': 'tests functinoality of ggo',
'appvers': '1.0.0',
},
tests=[
{
'test_name': 'Default',
'params': {'tag': 'CDS'},
'outputs': {
'test_output': ['ggo_out.complex.Sheet1.tsv', 'galaxygetopt/tests/test_file.tsv'],
}
}
],
doc=__doc__
})
param_dict = c.params()
And you get data back in a nice dict, just like when using Getopt::Long::Descriptive. Life is good again!
{'int': 40, 'float': '1e-4', 'string': ['Hello', 'World'] }
–help me
Automatically generated
usage: example.py [-h] [--version] [-v] [--file [FILE]] [--int [INT]] [--option [{a,b}]] [--test_output [TEST_OUTPUT]] [--test_output_format [TEST_OUTPUT_FORMAT]] Example Utility: prints out options passed to it optional arguments: -h, --help show this help message and exit --version show program's version number and exit -v, --verbose Produce more verbose output Options: --file [FILE] Input file [Required] --int [INT] An integer (Default: 30) [Required] --option [{a,b}] A selection type parameter (Default: []) (Options: Alpha [a], Bravo [b] Output Files: --test_output [TEST_OUTPUT] Output Data (Default: ggo_out.complex) [Required] --test_output_format [TEST_OUTPUT_FORMAT] Associated Format for test_output (Default: TSV_U) [Required]
XML Generation
I usually pipe my stuff through xmllint --pretty 1 - in order to reformat things nicely. The example script produces the following XML:
<?xml version="1.0"?>
<tool id="org.cpt.examples.GGOPoster" name="Example Utility" version="1.0.0">
<description>prints out options passed to it</description>
<version_command>python /home/hxr/work/gcc2014/poster/example.py --version</version_command>
<stdio>
<exit_code level="fatal" range="1:"/>
</stdio>
<command interpreter="python">/home/hxr/work/gcc2014/poster/example.py
--galaxy
--outfile_supporting $__new_file_path__
--file "${file}"
--int "${int}"
#for $item in $repeat_option:
--option "${item.option}"
#end for
--test_output "${test_output}"
--test_output_files_path "${test_output.files_path}"
--test_output_format "${test_output_format}"
--test_output_id "${test_output.id}"
</command>
<inputs>
<param help="Input file" label="file" name="file" optional="False" type="data"/>
<param help="An integer" label="int" min="10" name="int" optional="False" type="integer" value="30"/>
<repeat name="repeat_option" title="Option">
<param help="A selection type parameter" label="option" name="option" optional="True" type="select">
<option value="a">Alpha</option>
<option value="b">Bravo</option>
</param>
</repeat>
<param help="Output Data" label="Format of test_output" name="test_output_format" optional="False" type="select">
<option value="CSV">CSV</option>
<option value="CSV_U">CSV_U</option>
<option value="Dumper">Dumper</option>
<option value="JSON">JSON</option>
<option value="ODS">ODS</option>
<option value="TSV">TSV</option>
<option selected="True" value="TSV_U">TSV_U</option>
<option value="XLS">XLS</option>
<option value="XLSX">XLSX</option>
<option value="YAML">YAML</option>
</param>
</inputs>
<outputs>
<data format="TSV_U" name="test_output">
<change_format>
<when format="tabular" input="test_output_format" value="CSV"/>
<when format="tabular" input="test_output_format" value="CSV_U"/>
<when format="txt" input="test_output_format" value="Dumper"/>
<when format="txt" input="test_output_format" value="JSON"/>
<when format="data" input="test_output_format" value="ODS"/>
<when format="tabular" input="test_output_format" value="TSV"/>
<when format="tabular" input="test_output_format" value="TSV_U"/>
<when format="data" input="test_output_format" value="XLS"/>
<when format="data" input="test_output_format" value="XLSX"/>
<when format="txt" input="test_output_format" value="YAML"/>
</change_format>
</data>
</outputs>
<help>DESCRIPTION
===========
Print out options passed to it
</help>
<tests>
<test>
<output file="galaxygetopt/tests/test_file.tsv" name="test_output"/>
</test>
</tests>
</tool>
Generated Tests
Generating test scripts is very nice since that is more code that should not be duplicated. It generates a very simple test script which asserts that the created file and the static test file are equivalent.
#!/usr/bin/env python
import difflib
import unittest
import shlex, subprocess
import os
class TestScript(unittest.TestCase):
def setUp(self):
self.base = ['python', '/home/hxr/work/gcc2014/poster/example.py']
self.tests = [{'outputs': {'test_output': ['ggo_out.complex.Sheet1.tsv', 'galaxygetopt/tests/test_file.tsv']}, 'command_line': '', 'test_name': 'Default'}]
def test_run(self):
for test_case in self.tests:
failed_test = False
try:
current_command = self.base + \
shlex.split(test_case['command_line'])
# Should probably be wrapped in an assert as well
subprocess.check_call(current_command)
for fileset in test_case['outputs']:
failed_test = self.file_comparison(
test_case['outputs'][fileset][0],
test_case['outputs'][fileset][1])
except:
raise
self.assertFalse(failed_test)
def file_comparison(self, test_file, comp_file):
failed_test = False
diff=difflib.unified_diff(open(test_file).readlines(),
open(comp_file).readlines())
try:
while True:
print diff.next(),
failed_test = True
except:
pass
try:
# Attempt to remove the generated file to cut down on
# clutter/other bad things
os.unlink(test_file)
except:
pass
return failed_test
if __name__ == '__main__':
unittest.main()
Known Bugs
Currently there is a known bug in the galaxy XML, under highly specific circumstances. If you define a parameter that is
required
hidden
validate String (probably not a hard req)
_galaxy_specific
and expect it to properly generate the value, it will not. See lines 206/207 of galaxygetopt/ggo.py for the current hack I use to get around this.
Other
This library features a number of subclasses of galaxygetopt.parameter.parameter, all of which have myriad numbers of options. In order to brutally test these, I have added a class galaxygetopt/tests/parameter_generator.py which can generate every single possible combination of functional calls, given rules you specify. You can then generate hundreds of objects with different sets of options, which you can filter a subset out and test at will. See that classes’s documentation for more information.