Warning

This document is for an old release of Galaxy. You can alternatively view this page in the latest release if it exists or view the top of the latest release's documentation.

Source code for galaxy.tool_util.toolbox.parser

"""This module is used to parse tool_conf files.

These files define tool lists, sections, labels, etc... the elements of the
Galaxy tool panel.
"""
from abc import (
    ABCMeta,
    abstractmethod,
)

import yaml

from galaxy.util import (
    parse_xml,
    string_as_bool,
)

DEFAULT_MONITOR = False


class ToolConfSource(metaclass=ABCMeta):
    """Interface represents a container of tool references."""

    @abstractmethod
    def parse_items(self):
        """Return a list of ToolConfItem describing source."""

    @abstractmethod
    def parse_tool_path(self):
        """Return tool_path for tools in this toolbox or None."""

    @abstractmethod
    def is_shed_tool_conf(self):
        """Decide if this tool conf is a shed tool conf."""

    def parse_monitor(self):
        """Monitor the toolbox configuration source for changes and reload."""
        return DEFAULT_MONITOR


class XmlToolConfSource(ToolConfSource):
    def __init__(self, config_filename):
        tree = parse_xml(config_filename)
        self.root = tree.getroot()

    def parse_tool_path(self):
        return self.root.get("tool_path")

    def parse_tool_cache_data_dir(self):
        return self.root.get("tool_cache_data_dir")

    def parse_items(self):
        return [ensure_tool_conf_item(_) for _ in self.root]

    def is_shed_tool_conf(self):
        has_tool_path = self.parse_tool_path() is not None
        is_shed_conf = string_as_bool(self.root.get("is_shed_conf", "True"))
        return has_tool_path and is_shed_conf

    def parse_monitor(self):
        return string_as_bool(self.root.get("monitor", DEFAULT_MONITOR))


class YamlToolConfSource(ToolConfSource):
    def __init__(self, config_filename):
        with open(config_filename) as f:
            as_dict = yaml.safe_load(f)
        self.as_dict = as_dict

    def parse_tool_path(self):
        return self.as_dict.get("tool_path")

    def parse_tool_cache_data_dir(self):
        return self.as_dict.get("tool_cache_data_dir")

    def parse_items(self):
        return [ToolConfItem.from_dict(_) for _ in self.as_dict.get("items")]

    def parse_monitor(self):
        return self.as_dict.get("monitor", DEFAULT_MONITOR)

    def is_shed_tool_conf(self):
        return False


class ToolConfItem:
    """Abstract description of a tool conf item.

    These may include tools, labels, sections, and workflows.
    """

    def __init__(self, type, attributes, elem=None):
        self.type = type
        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 = [cls.from_dict(_) for _ in 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)

    @property
    def has_elem(self):
        return self._elem is not None

    @property
    def elem(self):
        if self._elem is None:
            raise Exception("item.elem called on toolbox element from non-XML source")
        return self._elem

    @property
    def labels(self):
        labels = None
        if "labels" in self.attributes:
            labels = [label.strip() for label in self.attributes["labels"].split(",")]
        return labels


class ToolConfSection(ToolConfItem):
    def __init__(self, attributes, items, elem=None):
        super().__init__("section", attributes, elem)
        self.items = items


[docs]def ensure_tool_conf_item(xml_or_item): if xml_or_item is None: return None elif isinstance(xml_or_item, ToolConfItem): return xml_or_item elif isinstance(xml_or_item, dict): # TODO: handle sections... as_dict = xml_or_item.copy() type = as_dict.pop("type") attributes = as_dict return ToolConfItem(type, attributes, None) else: elem = xml_or_item type = elem.tag attributes = elem.attrib if type != "section": return ToolConfItem(type, attributes, elem) else: items = [ensure_tool_conf_item(_) for _ in elem] return ToolConfSection(attributes, items, elem=elem)
[docs]def get_toolbox_parser(config_filename): is_yaml = any(config_filename.endswith(e) for e in [".yml", ".yaml", ".json"]) if is_yaml: return YamlToolConfSource(config_filename) else: return XmlToolConfSource(config_filename)
__all__ = ( "get_toolbox_parser", "ensure_tool_conf_item", )