Allow loading tool confs written in YAML and JSON.

Because lets say someone was writing a programatic way to manage elements in a tool conf, that hypothetical person probably shouldn't be writing XML.
This commit is contained in:
John Chilton
2016-01-03 13:10:08 +00:00
parent fcc83d4e09
commit b68991c4ca
3 changed files with 78 additions and 20 deletions
-1
View File
@@ -53,7 +53,6 @@ class ToolSection( Dictifiable, HasPanelItems, object ):
def __init__( self, item=None ):
""" Build a ToolSection from an ElementTree element or a dictionary.
"""
item = ensure_tool_conf_item(item)
f = lambda item, val: item is not None and item.get( val ) or ''
self.name = f( item, 'name' )
self.id = f( item, 'id' )
+37 -2
View File
@@ -2,6 +2,7 @@ from abc import ABCMeta
from abc import abstractmethod
from galaxy.util import parse_xml
import yaml
class ToolConfSource(object):
@@ -34,6 +35,20 @@ class XmlToolConfSource(ToolConfSource):
return map(ensure_tool_conf_item, self.root.getchildren())
class YamlToolConfSource(ToolConfSource):
def __init__(self, config_filename):
with open(config_filename, "r") as f:
as_dict = yaml.load(f)
self.as_dict = as_dict
def parse_tool_path(self):
return self.as_dict.get('tool_path')
def parse_items(self):
return map(ToolConfItem.from_dict, self.as_dict.get('items'))
class ToolConfItem(object):
""" This interface represents an abstract source to parse tool
information from.
@@ -44,6 +59,20 @@ class ToolConfItem(object):
self.attributes = attributes
self._elem = elem
@classmethod
def from_dict(cls, _as_dict):
as_dict = _as_dict.copy()
type = as_dict.get('type')
del as_dict['type']
attributes = as_dict
if type == 'section':
items = map(cls.from_dict, as_dict['items'])
del as_dict['items']
item = ToolConfSection(attributes, items)
else:
item = ToolConfItem(type, attributes)
return item
def get(self, key, default=None):
return self.attributes.get(key, default)
@@ -73,7 +102,9 @@ class ToolConfSection(ToolConfItem):
def ensure_tool_conf_item(xml_or_item):
if isinstance(xml_or_item, ToolConfItem):
if xml_or_item is None:
return None
elif isinstance(xml_or_item, ToolConfItem):
return xml_or_item
else:
elem = xml_or_item
@@ -87,4 +118,8 @@ def ensure_tool_conf_item(xml_or_item):
def get_toolbox_parser(config_filename):
return XmlToolConfSource(config_filename)
is_yaml = any(map(lambda e: config_filename.endswith(e), [".yml", ".yaml", ".json"]))
if is_yaml:
return YamlToolConfSource(config_filename)
else:
return XmlToolConfSource(config_filename)
+41 -17
View File
@@ -1,3 +1,4 @@
import json
import os
import string
import unittest
@@ -117,10 +118,14 @@ class BaseToolBoxTestCase( unittest.TestCase, tools_support.UsesApp, tools_supp
</toolbox>"""
self._add_config( template % (self.test_directory, CONFIG_TEST_TOOL_VERSION_1, CONFIG_TEST_TOOL_VERSION_2 ) )
def _add_config( self, xml, name="tool_conf.xml" ):
def _add_config( self, content, name="tool_conf.xml" ):
is_json = name.endswith(".json")
path = self._tool_conf_path( name=name )
with open( path, "w" ) as f:
f.write( xml )
if not is_json or isinstance(content, basestring):
f.write( content )
else:
json.dump(content, f)
self.config_files.append( path )
def _tool_conf_path( self, name="tool_conf.xml" ):
@@ -146,20 +151,22 @@ class ToolBoxTestCase( BaseToolBoxTestCase ):
assert toolbox.get_tool( "not_a_test_tool" ) is None
def test_to_dict_in_panel( self ):
self._init_tool_in_section()
mapper = routes.Mapper()
mapper.connect( "tool_runner", "/test/tool_runner" )
as_dict = self.toolbox.to_dict( mock_trans() )
test_section = self._find_section(as_dict, "t")
assert len(test_section["elems"]) == 1
assert test_section["elems"][0]["id"] == "test_tool"
for json_conf in [True, False]:
self._init_tool_in_section(json=json_conf)
mapper = routes.Mapper()
mapper.connect( "tool_runner", "/test/tool_runner" )
as_dict = self.toolbox.to_dict( mock_trans() )
test_section = self._find_section(as_dict, "t")
assert len(test_section["elems"]) == 1
assert test_section["elems"][0]["id"] == "test_tool"
def test_to_dict_out_of_panel( self ):
self._init_tool_in_section()
mapper = routes.Mapper()
mapper.connect( "tool_runner", "/test/tool_runner" )
as_dict = self.toolbox.to_dict( mock_trans(), in_panel=False )
assert as_dict[0]["id"] == "test_tool"
for json_conf in [True, False]:
self._init_tool_in_section(json=json_conf)
mapper = routes.Mapper()
mapper.connect( "tool_runner", "/test/tool_runner" )
as_dict = self.toolbox.to_dict( mock_trans(), in_panel=False )
assert as_dict[0]["id"] == "test_tool"
def test_out_of_panel_filtering( self ):
self._init_tool_in_section()
@@ -183,7 +190,7 @@ class ToolBoxTestCase( BaseToolBoxTestCase ):
if elem.get("id") == section_id:
assert elem["model_class"] == "ToolSection"
return elem
assert False, "Failed to find section with id [%s]" % id
assert False, "Failed to find section with id [%s]" % section_id
def test_tool_shed_properties( self ):
self._init_tool()
@@ -275,6 +282,13 @@ class ToolBoxTestCase( BaseToolBoxTestCase ):
toolbox = self.toolbox
assert toolbox.get_tool( "test_tool" ) is not None
def test_tool_dir_json( self ):
self._init_tool()
self._add_config({"items": [{"type": "tool_dir", "dir": self.test_directory}]}, name="tool_conf.json")
toolbox = self.toolbox
assert toolbox.get_tool( "test_tool" ) is not None
def test_workflow_in_panel( self ):
stored_workflow = self.__test_workflow()
encoded_id = self.app.security.encode_id( stored_workflow.id )
@@ -305,9 +319,19 @@ class ToolBoxTestCase( BaseToolBoxTestCase ):
section = self.toolbox._tool_panel[ 'tid' ]
self.__check_test_labels( section.elems )
def _init_tool_in_section( self ):
def _init_tool_in_section( self, json=False ):
self._init_tool()
self._add_config( """<toolbox><section id="t" name="test"><tool file="tool.xml" /></section></toolbox>""" )
if not json:
self._add_config( """<toolbox><section id="t" name="test"><tool file="tool.xml" /></section></toolbox>""" )
else:
section = {
"type": "section",
"id": "t",
"name": "test",
"items": [{"type": "tool",
"file": "tool.xml"}],
}
self._add_config({"items": [section]}, name="tool_conf.json")
def __check_test_labels( self, panel_dict ):
assert panel_dict.keys() == ["label_lab1", "label_lab2"]