Mercurial > repos > guerler > springsuite
comparison planemo/lib/python3.7/site-packages/galaxy/tool_util/parser/interface.py @ 1:56ad4e20f292 draft
"planemo upload commit 6eee67778febed82ddd413c3ca40b3183a3898f1"
| author | guerler |
|---|---|
| date | Fri, 31 Jul 2020 00:32:28 -0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 0:d30785e31577 | 1:56ad4e20f292 |
|---|---|
| 1 import os | |
| 2 from abc import ( | |
| 3 ABCMeta, | |
| 4 abstractmethod | |
| 5 ) | |
| 6 | |
| 7 import six | |
| 8 | |
| 9 from .util import _parse_name | |
| 10 | |
| 11 NOT_IMPLEMENTED_MESSAGE = "Galaxy tool format does not yet support this tool feature." | |
| 12 | |
| 13 | |
| 14 @six.python_2_unicode_compatible | |
| 15 @six.add_metaclass(ABCMeta) | |
| 16 class ToolSource(object): | |
| 17 """ This interface represents an abstract source to parse tool | |
| 18 information from. | |
| 19 """ | |
| 20 default_is_multi_byte = False | |
| 21 | |
| 22 @abstractmethod | |
| 23 def parse_id(self): | |
| 24 """ Parse an ID describing the abstract tool. This is not the | |
| 25 GUID tracked by the tool shed but the simple id (there may be | |
| 26 multiple tools loaded in Galaxy with this same simple id). | |
| 27 """ | |
| 28 | |
| 29 @abstractmethod | |
| 30 def parse_version(self): | |
| 31 """ Parse a version describing the abstract tool. | |
| 32 """ | |
| 33 | |
| 34 def parse_tool_module(self): | |
| 35 """ Load Tool class from a custom module. (Optional). | |
| 36 | |
| 37 If not None, return pair containing module and class (as strings). | |
| 38 """ | |
| 39 return None | |
| 40 | |
| 41 def parse_action_module(self): | |
| 42 """ Load Tool class from a custom module. (Optional). | |
| 43 | |
| 44 If not None, return pair containing module and class (as strings). | |
| 45 """ | |
| 46 return None | |
| 47 | |
| 48 def parse_tool_type(self): | |
| 49 """ Load simple tool type string (e.g. 'data_source', 'default'). | |
| 50 """ | |
| 51 return None | |
| 52 | |
| 53 @abstractmethod | |
| 54 def parse_name(self): | |
| 55 """ Parse a short name for tool (required). """ | |
| 56 | |
| 57 @abstractmethod | |
| 58 def parse_description(self): | |
| 59 """ Parse a description for tool. Longer than name, shorted than help. """ | |
| 60 | |
| 61 def parse_is_multi_byte(self): | |
| 62 """ Parse is_multi_byte from tool - TODO: figure out what this is and | |
| 63 document. | |
| 64 """ | |
| 65 return self.default_is_multi_byte | |
| 66 | |
| 67 def parse_display_interface(self, default): | |
| 68 """ Parse display_interface - fallback to default for the tool type | |
| 69 (supplied as default parameter) if not specified. | |
| 70 """ | |
| 71 return default | |
| 72 | |
| 73 def parse_require_login(self, default): | |
| 74 """ Parse whether the tool requires login (as a bool). | |
| 75 """ | |
| 76 return default | |
| 77 | |
| 78 def parse_request_param_translation_elem(self): | |
| 79 """ Return an XML element describing require parameter translation. | |
| 80 | |
| 81 If we wish to support this feature for non-XML based tools this should | |
| 82 be converted to return some sort of object interface instead of a RAW | |
| 83 XML element. | |
| 84 """ | |
| 85 return None | |
| 86 | |
| 87 @abstractmethod | |
| 88 def parse_command(self): | |
| 89 """ Return string contianing command to run. | |
| 90 """ | |
| 91 | |
| 92 def parse_expression(self): | |
| 93 """ Return string contianing command to run. | |
| 94 """ | |
| 95 return None | |
| 96 | |
| 97 @abstractmethod | |
| 98 def parse_environment_variables(self): | |
| 99 """ Return environment variable templates to expose. | |
| 100 """ | |
| 101 | |
| 102 def parse_home_target(self): | |
| 103 """Should be "job_home", "shared_home", "job_tmp", "pwd", or None. | |
| 104 """ | |
| 105 return "pwd" | |
| 106 | |
| 107 def parse_tmp_target(self): | |
| 108 """Should be "pwd", "shared_home", "job_tmp", "job_tmp_if_explicit", or None. | |
| 109 """ | |
| 110 return "job_tmp" | |
| 111 | |
| 112 def parse_tmp_directory_vars(self): | |
| 113 """Directories to override if a tmp_target is not None.""" | |
| 114 return ["TMPDIR", "TMP", "TEMP"] | |
| 115 | |
| 116 def parse_docker_env_pass_through(self): | |
| 117 return ["GALAXY_SLOTS", "HOME", "_GALAXY_JOB_HOME_DIR", "_GALAXY_JOB_TMP_DIR"] + self.parse_tmp_directory_vars() | |
| 118 | |
| 119 @abstractmethod | |
| 120 def parse_interpreter(self): | |
| 121 """ Return string containing the interpreter to prepend to the command | |
| 122 (for instance this might be 'python' to run a Python wrapper located | |
| 123 adjacent to the tool). | |
| 124 """ | |
| 125 | |
| 126 @abstractmethod | |
| 127 def parse_interactivetool(self): | |
| 128 """ Return InteractiveTool entry point templates to expose. | |
| 129 """ | |
| 130 | |
| 131 def parse_redirect_url_params_elem(self): | |
| 132 """ Return an XML element describing redirect_url_params. | |
| 133 | |
| 134 If we wish to support this feature for non-XML based tools this should | |
| 135 be converted to return some sort of object interface instead of a RAW | |
| 136 XML element. | |
| 137 """ | |
| 138 return None | |
| 139 | |
| 140 def parse_version_command(self): | |
| 141 """ Parse command used to determine version of primary application | |
| 142 driving the tool. Return None to not generate or record such a command. | |
| 143 """ | |
| 144 return None | |
| 145 | |
| 146 def parse_version_command_interpreter(self): | |
| 147 """ Parse command used to determine version of primary application | |
| 148 driving the tool. Return None to not generate or record such a command. | |
| 149 """ | |
| 150 return None | |
| 151 | |
| 152 def parse_parallelism(self): | |
| 153 """ Return a galaxy.jobs.ParallismInfo object describing task splitting | |
| 154 or None. | |
| 155 """ | |
| 156 return None | |
| 157 | |
| 158 def parse_hidden(self): | |
| 159 """ Return boolean indicating whether tool should be hidden in the tool menu. | |
| 160 """ | |
| 161 return False | |
| 162 | |
| 163 def parse_sanitize(self): | |
| 164 """ Return boolean indicating whether tool should be sanitized or not. | |
| 165 """ | |
| 166 return True | |
| 167 | |
| 168 def parse_refresh(self): | |
| 169 """ Return boolean indicating ... I have no clue... | |
| 170 """ | |
| 171 return False | |
| 172 | |
| 173 @abstractmethod | |
| 174 def parse_requirements_and_containers(self): | |
| 175 """ Return pair of ToolRequirement and ContainerDescription lists. """ | |
| 176 | |
| 177 @abstractmethod | |
| 178 def parse_input_pages(self): | |
| 179 """ Return a PagesSource representing inputs by page for tool. """ | |
| 180 | |
| 181 def parse_provided_metadata_style(self): | |
| 182 """Return style of tool provided metadata file (e.g. galaxy.json). | |
| 183 | |
| 184 A value of of "default" indicates the newer galaxy.json style | |
| 185 (the default for XML-based tools with profile >= 17.09) and a value | |
| 186 of "legacy" indicates the older galaxy.json style. | |
| 187 | |
| 188 A short description of these two styles can be found at | |
| 189 https://github.com/galaxyproject/galaxy/pull/4437. | |
| 190 """ | |
| 191 return "default" | |
| 192 | |
| 193 def parse_provided_metadata_file(self): | |
| 194 """Return location of provided metadata file (e.g. galaxy.json).""" | |
| 195 return "galaxy.json" | |
| 196 | |
| 197 @abstractmethod | |
| 198 def parse_outputs(self, tool): | |
| 199 """ Return a pair of output and output collections ordered | |
| 200 dictionaries for use by Tool. | |
| 201 """ | |
| 202 | |
| 203 @abstractmethod | |
| 204 def parse_strict_shell(self): | |
| 205 """ Return True if tool commands should be executed with | |
| 206 set -e. | |
| 207 """ | |
| 208 | |
| 209 @abstractmethod | |
| 210 def parse_stdio(self): | |
| 211 """ Builds lists of ToolStdioExitCode and ToolStdioRegex objects | |
| 212 to describe tool execution error conditions. | |
| 213 """ | |
| 214 return [], [] | |
| 215 | |
| 216 @abstractmethod | |
| 217 def parse_help(self): | |
| 218 """ Return RST definition of help text for tool or None if the tool | |
| 219 doesn't define help text. | |
| 220 """ | |
| 221 | |
| 222 @abstractmethod | |
| 223 def parse_profile(self): | |
| 224 """ Return tool profile version as Galaxy major e.g. 16.01 or 16.04. | |
| 225 """ | |
| 226 | |
| 227 @abstractmethod | |
| 228 def parse_python_template_version(self): | |
| 229 """ | |
| 230 Return minimum python version that the tool template has been developed against. | |
| 231 """ | |
| 232 | |
| 233 @property | |
| 234 def macro_paths(self): | |
| 235 return [] | |
| 236 | |
| 237 @property | |
| 238 def source_path(self): | |
| 239 return None | |
| 240 | |
| 241 def paths_and_modtimes(self): | |
| 242 paths_and_modtimes = {p: os.path.getmtime(p) for p in self.macro_paths} | |
| 243 if self.source_path: | |
| 244 paths_and_modtimes[self.source_path] = os.path.getmtime(self.source_path) | |
| 245 return paths_and_modtimes | |
| 246 | |
| 247 def parse_tests_to_dict(self): | |
| 248 return {'tests': []} | |
| 249 | |
| 250 def __str__(self): | |
| 251 source_path = self.source_path | |
| 252 if source_path: | |
| 253 as_str = u'%s[%s]' % (self.__class__.__name__, source_path) | |
| 254 else: | |
| 255 as_str = u'%s[In-memory]' % (self.__class__.__name__) | |
| 256 return as_str | |
| 257 | |
| 258 | |
| 259 class PagesSource(object): | |
| 260 """ Contains a list of Pages - each a list of InputSources - | |
| 261 each item in the outer list representing a page of inputs. | |
| 262 Pages are deprecated so ideally this outer list will always | |
| 263 be exactly a singleton. | |
| 264 """ | |
| 265 | |
| 266 def __init__(self, page_sources): | |
| 267 self.page_sources = page_sources | |
| 268 | |
| 269 @property | |
| 270 def inputs_defined(self): | |
| 271 return True | |
| 272 | |
| 273 | |
| 274 @six.add_metaclass(ABCMeta) | |
| 275 class PageSource(object): | |
| 276 | |
| 277 def parse_display(self): | |
| 278 return None | |
| 279 | |
| 280 @abstractmethod | |
| 281 def parse_input_sources(self): | |
| 282 """ Return a list of InputSource objects. """ | |
| 283 | |
| 284 | |
| 285 @six.add_metaclass(ABCMeta) | |
| 286 class InputSource(object): | |
| 287 default_optional = False | |
| 288 | |
| 289 def elem(self): | |
| 290 # For things in transition that still depend on XML - provide a way | |
| 291 # to grab it and just throw an error if feature is attempted to be | |
| 292 # used with other tool sources. | |
| 293 raise NotImplementedError(NOT_IMPLEMENTED_MESSAGE) | |
| 294 | |
| 295 @abstractmethod | |
| 296 def get(self, key, value=None): | |
| 297 """ Return simple named properties as string for this input source. | |
| 298 keys to be supported depend on the parameter type. | |
| 299 """ | |
| 300 | |
| 301 @abstractmethod | |
| 302 def get_bool(self, key, default): | |
| 303 """ Return simple named properties as boolean for this input source. | |
| 304 keys to be supported depend on the parameter type. | |
| 305 """ | |
| 306 | |
| 307 def parse_label(self): | |
| 308 return self.get("label") | |
| 309 | |
| 310 def parse_name(self): | |
| 311 """Return name of an input source | |
| 312 returns the name or if absent the argument property | |
| 313 In the latter case, leading dashes are stripped and | |
| 314 all remaining dashes are replaced by underscores. | |
| 315 """ | |
| 316 return _parse_name(self.get('name'), self.get('argument')) | |
| 317 | |
| 318 def parse_help(self): | |
| 319 return self.get("help") | |
| 320 | |
| 321 def parse_sanitizer_elem(self): | |
| 322 """ Return an XML description of sanitizers. This is a stop gap | |
| 323 until we can rework galaxy.tools.parameters.sanitize to not | |
| 324 explicitly depend on XML. | |
| 325 """ | |
| 326 return None | |
| 327 | |
| 328 def parse_validator_elems(self): | |
| 329 """ Return an XML description of sanitizers. This is a stop gap | |
| 330 until we can rework galaxy.tools.parameters.validation to not | |
| 331 explicitly depend on XML. | |
| 332 """ | |
| 333 return [] | |
| 334 | |
| 335 def parse_optional(self, default=None): | |
| 336 """ Return boolean indicating wheter parameter is optional. """ | |
| 337 if default is None: | |
| 338 default = self.default_optional | |
| 339 return self.get_bool("optional", default) | |
| 340 | |
| 341 def parse_dynamic_options_elem(self): | |
| 342 """ Return an XML elemnt describing dynamic options. | |
| 343 """ | |
| 344 return None | |
| 345 | |
| 346 def parse_static_options(self): | |
| 347 """ Return list of static options if this is a select type without | |
| 348 defining a dynamic options. | |
| 349 """ | |
| 350 return [] | |
| 351 | |
| 352 def parse_conversion_tuples(self): | |
| 353 """ Return list of (name, extension) to describe explicit conversions. | |
| 354 """ | |
| 355 return [] | |
| 356 | |
| 357 def parse_nested_inputs_source(self): | |
| 358 # For repeats | |
| 359 raise NotImplementedError(NOT_IMPLEMENTED_MESSAGE) | |
| 360 | |
| 361 def parse_test_input_source(self): | |
| 362 # For conditionals | |
| 363 raise NotImplementedError(NOT_IMPLEMENTED_MESSAGE) | |
| 364 | |
| 365 def parse_when_input_sources(self): | |
| 366 raise NotImplementedError(NOT_IMPLEMENTED_MESSAGE) | |
| 367 | |
| 368 | |
| 369 class TestCollectionDef(object): | |
| 370 | |
| 371 def __init__(self, attrib, name, collection_type, elements): | |
| 372 self.attrib = attrib | |
| 373 self.collection_type = collection_type | |
| 374 self.elements = elements | |
| 375 self.name = name | |
| 376 | |
| 377 @staticmethod | |
| 378 def from_xml(elem, parse_param_elem): | |
| 379 elements = [] | |
| 380 attrib = dict(elem.attrib) | |
| 381 collection_type = attrib["type"] | |
| 382 name = attrib.get("name", "Unnamed Collection") | |
| 383 for element in elem.findall("element"): | |
| 384 element_attrib = dict(element.attrib) | |
| 385 element_identifier = element_attrib["name"] | |
| 386 nested_collection_elem = element.find("collection") | |
| 387 if nested_collection_elem is not None: | |
| 388 element_definition = TestCollectionDef.from_xml(nested_collection_elem, parse_param_elem) | |
| 389 else: | |
| 390 element_definition = parse_param_elem(element) | |
| 391 elements.append({"element_identifier": element_identifier, "element_definition": element_definition}) | |
| 392 | |
| 393 return TestCollectionDef( | |
| 394 attrib=attrib, | |
| 395 collection_type=collection_type, | |
| 396 elements=elements, | |
| 397 name=name, | |
| 398 ) | |
| 399 | |
| 400 def to_dict(self): | |
| 401 def element_to_dict(element_dict): | |
| 402 element_identifier, element_def = element_dict["element_identifier"], element_dict["element_definition"] | |
| 403 if isinstance(element_def, TestCollectionDef): | |
| 404 element_def = element_def.to_dict() | |
| 405 return { | |
| 406 "element_identifier": element_identifier, | |
| 407 "element_definition": element_def, | |
| 408 } | |
| 409 | |
| 410 return { | |
| 411 "model_class": "TestCollectionDef", | |
| 412 "attributes": self.attrib, | |
| 413 "collection_type": self.collection_type, | |
| 414 "elements": list(map(element_to_dict, self.elements or [])), | |
| 415 "name": self.name, | |
| 416 } | |
| 417 | |
| 418 @staticmethod | |
| 419 def from_dict(as_dict): | |
| 420 assert as_dict["model_class"] == "TestCollectionDef" | |
| 421 | |
| 422 def element_from_dict(element_dict): | |
| 423 if "element_definition" not in element_dict: | |
| 424 raise Exception("Invalid element_dict %s" % element_dict) | |
| 425 element_def = element_dict["element_definition"] | |
| 426 if element_def.get("model_class", None) == "TestCollectionDef": | |
| 427 element_def = TestCollectionDef.from_dict(element_def) | |
| 428 return {"element_identifier": element_dict["element_identifier"], "element_definition": element_def} | |
| 429 | |
| 430 return TestCollectionDef( | |
| 431 attrib=as_dict["attributes"], | |
| 432 name=as_dict["name"], | |
| 433 elements=list(map(element_from_dict, as_dict["elements"] or [])), | |
| 434 collection_type=as_dict["collection_type"], | |
| 435 ) | |
| 436 | |
| 437 def collect_inputs(self): | |
| 438 inputs = [] | |
| 439 for element in self.elements: | |
| 440 value = element["element_definition"] | |
| 441 if isinstance(value, TestCollectionDef): | |
| 442 inputs.extend(value.collect_inputs()) | |
| 443 else: | |
| 444 inputs.append(value) | |
| 445 return inputs | |
| 446 | |
| 447 | |
| 448 class TestCollectionOutputDef(object): | |
| 449 | |
| 450 def __init__(self, name, attrib, element_tests): | |
| 451 self.name = name | |
| 452 self.collection_type = attrib.get("type", None) | |
| 453 count = attrib.get("count", None) | |
| 454 self.count = int(count) if count is not None else None | |
| 455 self.attrib = attrib | |
| 456 self.element_tests = element_tests | |
| 457 | |
| 458 @staticmethod | |
| 459 def from_dict(as_dict): | |
| 460 return TestCollectionOutputDef( | |
| 461 name=as_dict["name"], | |
| 462 attrib=as_dict["attributes"], | |
| 463 element_tests=as_dict["element_tests"], | |
| 464 ) | |
| 465 | |
| 466 def to_dict(self): | |
| 467 return dict( | |
| 468 name=self.name, | |
| 469 attributes=self.attrib, | |
| 470 element_tests=self.element_tests | |
| 471 ) |
