Restructure tool external file logic in load_tool_from_tmp_config in ToolValidator...

... so internals of tool XML description are only utilized in the galaxy.tools module (and submodules). Add some unit tests for this new method for finding externally referenced files.
This commit is contained in:
John Chilton
2014-08-04 12:18:00 -04:00
parent 9fa342559e
commit daaf2c8cf0
4 changed files with 58 additions and 9 deletions
+16 -1
View File
@@ -69,7 +69,7 @@ from galaxy.model.item_attrs import Dictifiable
from galaxy.model import Workflow
from tool_shed.util import common_util
from tool_shed.util import shed_util_common as suc
from .loader import load_tool, template_macro_params
from .loader import load_tool, template_macro_params, raw_tool_xml_tree
from .execute import execute as execute_job
from .wrappers import (
ToolParameterValueWrapper,
@@ -2989,6 +2989,21 @@ class Tool( object, Dictifiable ):
def get_default_history_by_trans( self, trans, create=False ):
return trans.get_history( create=create )
@classmethod
def get_externally_referenced_paths( self, path ):
""" Return relative paths to externally referenced files by the tool
described by file at `path`. External components should not assume things
about the structure of tool xml files (this is the tool's responsibility).
"""
tree = raw_tool_xml_tree(path)
root = tree.getroot()
external_paths = []
for code_elem in root.findall( 'code' ):
external_path = code_elem.get( 'file' )
if external_path:
external_paths.append( external_path )
return external_paths
class OutputParameterJSONTool( Tool ):
"""
+9 -1
View File
@@ -10,7 +10,7 @@ def load_tool(path):
"""
Loads tool from file system and preprocesses tool macros.
"""
tree = parse_xml(path)
tree = raw_tool_xml_tree(path)
root = tree.getroot()
_import_macros(root, path)
@@ -38,6 +38,14 @@ def template_macro_params(root):
return param_dict
def raw_tool_xml_tree(path):
""" Load raw (no macro expansion) tree representation of tool represented
at the specified path.
"""
tree = parse_xml(path)
return tree
def _import_macros(root, path):
tool_dir = os.path.dirname(path)
macros_el = root.find('macros')
+7 -7
View File
@@ -3,6 +3,7 @@ import logging
import os
import tempfile
from galaxy.tools import Tool
from galaxy.tools import parameters
from galaxy.tools.parameters import dynamic_options
@@ -311,15 +312,14 @@ class ToolValidator( object ):
message = ''
tmp_tool_config = hg_util.get_named_tmpfile_from_ctx( ctx, ctx_file, work_dir )
if tmp_tool_config:
element_tree, error_message = xml_util.parse_xml( tmp_tool_config )
if element_tree is None:
tool_element, error_message = xml_util.parse_xml( tmp_tool_config )
if tool_element is None:
return tool, message
element_tree_root = element_tree.getroot()
# Look for code files required by the tool config.
# Look for external files required by the tool config.
tmp_code_files = []
for code_elem in element_tree_root.findall( 'code' ):
code_file_name = code_elem.get( 'file' )
tmp_code_file_name = hg_util.copy_file_from_manifest( repo, ctx, code_file_name, work_dir )
external_paths = Tool.get_externally_referenced_paths( tmp_tool_config )
for path in external_paths:
tmp_code_file_name = hg_util.copy_file_from_manifest( repo, ctx, path, work_dir )
if tmp_code_file_name:
tmp_code_files.append( tmp_code_file_name )
tool, valid, message = self.load_tool_from_config( repository_id, tmp_tool_config )
@@ -0,0 +1,26 @@
""" Unit test logic related to finding externally referenced files in tool
descriptions.
"""
import tempfile
import os
import shutil
from galaxy.tools import Tool
def test_finds_external_code_file():
assert __external_files("""<tool><code file="foo.py" /></tool>""") == ["foo.py"]
def test_finds_skips_empty_code_file_attribute():
assert __external_files("""<tool><code /></tool>""") == []
def __external_files(contents):
base_path = tempfile.mkdtemp()
try:
tool_path = os.path.join(base_path, "tool.xml")
with open(tool_path, "w") as f:
f.write(contents)
return Tool.get_externally_referenced_paths(tool_path)
finally:
shutil.rmtree(base_path)