diff --git a/lib/galaxy/tools/toolbox/panel.py b/lib/galaxy/tools/toolbox/panel.py
index bb1d6bbe3c5..5dd77e071c4 100644
--- a/lib/galaxy/tools/toolbox/panel.py
+++ b/lib/galaxy/tools/toolbox/panel.py
@@ -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' )
diff --git a/lib/galaxy/tools/toolbox/parser.py b/lib/galaxy/tools/toolbox/parser.py
index c6a5ad6dd15..6a075095972 100644
--- a/lib/galaxy/tools/toolbox/parser.py
+++ b/lib/galaxy/tools/toolbox/parser.py
@@ -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)
diff --git a/test/unit/tools/test_toolbox.py b/test/unit/tools/test_toolbox.py
index a29c36246b7..5e784a21172 100644
--- a/test/unit/tools/test_toolbox.py
+++ b/test/unit/tools/test_toolbox.py
@@ -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
"""
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( """""" )
+ if not json:
+ self._add_config( """""" )
+ 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"]