-
Notifications
You must be signed in to change notification settings - Fork 60
Expand file tree
/
Copy pathtoolbox.py
More file actions
150 lines (122 loc) · 5.13 KB
/
Copy pathtoolbox.py
File metadata and controls
150 lines (122 loc) · 5.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
from logging import getLogger
from os.path import (
abspath,
dirname,
join,
)
from xml.etree import ElementTree
from pulsar.tools.validator import ExpressionValidator
log = getLogger(__name__)
class ToolBox:
"""
Abstraction over a tool config file largely modelled after
Galaxy's shed_tool_conf.xml. Hopefully over time this toolbox
schema will be a direct superset of Galaxy's with extensions
to support simple, non-toolshed based tool setups.
"""
def __init__(self, path_string):
self.tool_configs = []
paths = [path.strip() for path in path_string.split(",")]
for path in paths:
toolbox_tree = ElementTree.parse(path)
toolbox_root = toolbox_tree.getroot()
tool_path = toolbox_root.get('tool_path')
self.__load_tools_from_els(toolbox_root, tool_path)
def __load_tools_from_els(self, toolbox_root, tool_path):
els = toolbox_root.findall('tool')
for el in els:
try:
if 'guid' in el.attrib:
tool_cls = ToolShedToolConfig
else:
tool_cls = SimpleToolConfig
tool = tool_cls(el, tool_path)
self.tool_configs.append(tool)
except Exception:
log.exception('Failed to load tool.')
def get_tool(self, id):
# Need to handle multiple tools per id someday, but
# starting simple.
tools = self.__find_tools_by_id(id)
if not tools:
raise KeyError("Failed to find tool with id '%s'" % id)
if len(tools) > 1:
log.warn("Found multiple tools with id '%s', returning first." % id)
return tools[0]
def __find_tools_by_id(self, id):
return [tool for tool in self.tool_configs if tool.id == id]
class InputsValidator:
def __init__(self, command_validator, config_validators):
self.command_validator = command_validator
self.config_validators = config_validators
def validate_command(self, job_directory, command):
return self.command_validator.validate(job_directory, command)
def validate_config(self, job_directory, name, path):
config_validator = self.config_validators.get(name, None)
valid = True
if config_validator:
with open(path, encoding="UTF-8") as fh:
contents = fh.read()
valid = config_validator.validate(job_directory, contents)
return valid
class ToolConfig:
"""
Abstract description of a Galaxy tool.
"""
def __init__(self):
super().__init__()
def get_tool_dir(self):
return abspath(dirname(self.path))
@property
def inputs_validator(self):
if not hasattr(self, "_inputs_validator"):
command_el = self._root().find("./validators/command_validator")
command_validator = ExpressionValidator(command_el)
config_validators = {}
for config_el in self._root().findall("./validators/configfile_validator"):
name = config_el.get("name")
config_validators[name] = ExpressionValidator(config_el)
self._inputs_validator = InputsValidator(command_validator, config_validators)
return self._inputs_validator
def _root(self):
return self._el().getroot()
def _el(self):
return ElementTree.parse(self.path)
class SimpleToolConfig(ToolConfig):
"""
Abstract description of a Galaxy tool loaded from a
toolbox with the `tool` tag not containing a guid, i.e.
one not from the toolshed.
"""
def __init__(self, tool_el, tool_path):
super().__init__()
rel_path = tool_el.get('file')
assert tool_path, "tool_path not set, toolbox XML files must be configured with a tool_path directory."
assert rel_path, "file not set on tool, each tool element must define a file attribute pointing to a valid tool XML file."
resolved_path = join(tool_path, rel_path)
self.path = resolved_path
root = self._root()
self.id = root.get('id')
self.version = root.get('version', '1.0.0')
self.tool_dir = dirname(resolved_path)
class ToolShedToolConfig(SimpleToolConfig):
"""
Abstract description of a Galaxy tool loaded from a
toolbox with the `tool` tag, i.e. one from the
toolshed.
::
<tool file="../shed_tools/gvk.bx.psu.edu/repos/test/column_maker/f06aa1bf1e8a/column_maker/column_maker.xml" guid\
="gvk.bx.psu.edu:9009/repos/test/column_maker/Add_a_column1/1.1.0">
<tool_shed>gvk.bx.psu.edu:9009</tool_shed>
<repository_name>column_maker</repository_name>
<repository_owner>test</repository_owner>
<installed_changeset_revision>f06aa1bf1e8a</installed_changeset_revision
<id>gvk.bx.psu.edu:9009/repos/test/column_maker/Add_a_column1/1.1.0</id>
<version>1.1.0</version>
</tool>
"""
def __init__(self, tool_el, tool_path):
super().__init__(tool_el, tool_path)
self.guid = tool_el.get("guid")
# Override id in file for tool shed tools. Use GUID instead.
self.id = self.guid