mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
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:
@@ -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' )
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"]
|
||||
|
||||
Reference in New Issue
Block a user