Skip to content

Commit

Permalink
eliminate node_props
Browse files Browse the repository at this point in the history
  • Loading branch information
bernt-matthias committed Jan 27, 2022
1 parent f3ba64e commit 665d83e
Show file tree
Hide file tree
Showing 11 changed files with 170 additions and 183 deletions.
18 changes: 11 additions & 7 deletions lib/galaxy/tool_util/lint.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@
)

from galaxy.tool_util.parser import get_tool_source
from galaxy.util import submodules

from galaxy.util import etree, submodules

LEVEL_ALL = "all"
LEVEL_WARN = "warn"
Expand Down Expand Up @@ -52,11 +51,16 @@ def pretty_print(self, level: bool = True, **kwargs) -> str:


class XMLLintMessage(LintMessage):
def __init__(self, level: str, message: str, line="", fname="", xpath=None):
def __init__(self, level: str, message: str, node: Optional[etree.Element] = None):
super().__init__(level, message)
self.line = line # 1 based
self.fname = fname
self.xpath = xpath
self.line = None
self.fname = None
self.xpath = None
if node is not None:
self.line = node.sourceline
self.fname = node.base
tool_xml = node.getroottree()
self.xpath = tool_xml.getpath(node)

def pretty_print(self, level: bool = True, **kwargs) -> str:
"""
Expand All @@ -65,7 +69,7 @@ def pretty_print(self, level: bool = True, **kwargs) -> str:
kwargs['xpath'] is True, respectively
"""
rval = super().pretty_print(level)
if kwargs.get("fname", False) and self.line is not None:
if kwargs.get("fname", True) and self.line is not None:
rval += " ("
if self.fname:
rval += f"{self.fname}:"
Expand Down
13 changes: 0 additions & 13 deletions lib/galaxy/tool_util/linters/_util.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,6 @@
import re


def node_props_factory(tool_xml):

def node_props(node):
if node is None:
return {"line": 0, "fname": None, "xpath": None}
else:
return {"line": node.sourceline,
"fname": node.base,
"xpath": tool_xml.getpath(node)}

return node_props


def is_datasource(tool_xml):
"""Returns true if the tool is a datasource tool"""
return tool_xml.getroot().attrib.get('tool_type', '') == 'data_source'
Expand Down
23 changes: 12 additions & 11 deletions lib/galaxy/tool_util/linters/citations.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,38 @@
Citations describe references that should be used when consumers
of the tool publish results.
"""
from ._util import node_props_factory


def lint_citations(tool_xml, lint_ctx):
"""Ensure tool contains at least one valid citation."""
root = tool_xml.getroot()
node_props = node_props_factory(tool_xml)
citations = root.findall("citations")
root = tool_xml.find("./citations")
if root is None:
root = tool_xml.getroot()

citations = tool_xml.findall("citations")
if len(citations) > 1:
lint_ctx.error("More than one citation section found, behavior undefined.", **node_props(citations[1]))
lint_ctx.error("More than one citation section found, behavior undefined.", node=citations[1])
return

if len(citations) == 0:
lint_ctx.warn("No citations found, consider adding citations to your tool.", **node_props(root))
lint_ctx.warn("No citations found, consider adding citations to your tool.", node=root)
return

valid_citations = 0
for citation in citations[0]:
if citation.tag != "citation":
lint_ctx.warn(f"Unknown tag discovered in citations block [{citation.tag}], will be ignored.", **node_props(citation))
lint_ctx.warn(f"Unknown tag discovered in citations block [{citation.tag}], will be ignored.", node=citation)
continue
citation_type = citation.attrib.get("type")
if citation_type not in ('bibtex', 'doi'):
lint_ctx.warn(f"Unknown citation type discovered [{citation_type}], will be ignored.", **node_props(citation))
lint_ctx.warn(f"Unknown citation type discovered [{citation_type}], will be ignored.", node=citation)
continue
if citation.text is None or not citation.text.strip():
lint_ctx.error(f'Empty {citation_type} citation.', **node_props(citation))
lint_ctx.error(f'Empty {citation_type} citation.', node=citation)
continue
valid_citations += 1

if valid_citations > 0:
lint_ctx.valid(f"Found {valid_citations} likely valid citations.", **node_props(root))
lint_ctx.valid(f"Found {valid_citations} likely valid citations.", node=root)
else:
lint_ctx.warn("Found no valid citations.", **node_props(root))
lint_ctx.warn("Found no valid citations.", node=root)
23 changes: 12 additions & 11 deletions lib/galaxy/tool_util/linters/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,28 @@
A command description describes how to build the command-line to execute
from supplied inputs.
"""
from ._util import node_props_factory


def lint_command(tool_xml, lint_ctx):
"""Ensure tool contains exactly one command and check attributes."""
root = tool_xml.getroot()
node_props = node_props_factory(tool_xml)
commands = root.findall("command")
root = tool_xml.find("./command")
if root is None:
root = tool_xml.getroot()

commands = tool_xml.findall("./command")
if len(commands) > 1:
lint_ctx.error("More than one command tag found, behavior undefined.", **node_props(commands[1]))
lint_ctx.error("More than one command tag found, behavior undefined.", node=commands[1])
return

if len(commands) == 0:
lint_ctx.error("No command tag found, must specify a command template to execute.", **node_props(root))
lint_ctx.error("No command tag found, must specify a command template to execute.", node=root)
return

command = get_command(tool_xml)
if command.text is None:
lint_ctx.error("Command is empty.", **node_props(root))
lint_ctx.error("Command is empty.", node=root)
elif "TODO" in command.text:
lint_ctx.warn("Command template contains TODO text.", **node_props(command))
lint_ctx.warn("Command template contains TODO text.", node=command)

command_attrib = command.attrib
interpreter_type = None
Expand All @@ -33,14 +34,14 @@ def lint_command(tool_xml, lint_ctx):
elif key == "detect_errors":
detect_errors = value
if detect_errors not in ["default", "exit_code", "aggressive"]:
lint_ctx.warn(f"Unknown detect_errors attribute [{detect_errors}]", **node_props(command))
lint_ctx.warn(f"Unknown detect_errors attribute [{detect_errors}]", node=command)

interpreter_info = ""
if interpreter_type:
interpreter_info = f" with interpreter of type [{interpreter_type}]"
if interpreter_type:
lint_ctx.warn("Command uses deprecated 'interpreter' attribute.", **node_props(command))
lint_ctx.info(f"Tool contains a command{interpreter_info}.", **node_props(command))
lint_ctx.warn("Command uses deprecated 'interpreter' attribute.", node=command)
lint_ctx.info(f"Tool contains a command{interpreter_info}.", node=command)


def get_command(tool_xml):
Expand Down
30 changes: 14 additions & 16 deletions lib/galaxy/tool_util/linters/general.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

import packaging.version

from ._util import node_props_factory

ERROR_VERSION_MSG = "Tool version is missing or empty."
WARN_VERSION_MSG = "Tool version [%s] is not compliant with PEP 440."
Expand Down Expand Up @@ -32,46 +31,45 @@ def lint_general(tool_source, lint_ctx):
"""Check tool version, name, and id."""
# determine line to report for general problems with outputs
tool_xml = getattr(tool_source, "xml_tree", None)
node_props = node_props_factory(tool_xml)
if tool_xml:
tool_node = tool_xml.find("./tool")
tool_node = tool_xml.getroot()
else:
tool_node = None
version = tool_source.parse_version() or ''
parsed_version = packaging.version.parse(version)
if not version:
lint_ctx.error(ERROR_VERSION_MSG, **node_props(tool_node))
lint_ctx.error(ERROR_VERSION_MSG, node=tool_node)
elif isinstance(parsed_version, packaging.version.LegacyVersion):
lint_ctx.warn(WARN_VERSION_MSG % version, **node_props(tool_node))
lint_ctx.warn(WARN_VERSION_MSG % version, node=tool_node)
elif version != version.strip():
lint_ctx.warn(WARN_WHITESPACE_PRESUFFIX % ('Tool version', version), **node_props(tool_node))
lint_ctx.warn(WARN_WHITESPACE_PRESUFFIX % ('Tool version', version), node=tool_node)
else:
lint_ctx.valid(VALID_VERSION_MSG % version, **node_props(tool_node))
lint_ctx.valid(VALID_VERSION_MSG % version, node=tool_node)

name = tool_source.parse_name()
if not name:
lint_ctx.error(ERROR_NAME_MSG, **node_props(tool_node))
lint_ctx.error(ERROR_NAME_MSG, node=tool_node)
elif name != name.strip():
lint_ctx.warn(WARN_WHITESPACE_PRESUFFIX % ('Tool name', name), **node_props(tool_node))
lint_ctx.warn(WARN_WHITESPACE_PRESUFFIX % ('Tool name', name), node=tool_node)
else:
lint_ctx.valid(VALID_NAME_MSG % name, **node_props(tool_node))
lint_ctx.valid(VALID_NAME_MSG % name, node=tool_node)

tool_id = tool_source.parse_id()
if not tool_id:
lint_ctx.error(ERROR_ID_MSG, **node_props(tool_node))
lint_ctx.error(ERROR_ID_MSG, node=tool_node)
elif re.search(r"\s", tool_id):
lint_ctx.warn(WARN_ID_WHITESPACE_MSG % tool_id, **node_props(tool_node))
lint_ctx.warn(WARN_ID_WHITESPACE_MSG % tool_id, node=tool_node)
else:
lint_ctx.valid(VALID_ID_MSG % tool_id, **node_props(tool_node))
lint_ctx.valid(VALID_ID_MSG % tool_id, node=tool_node)

profile = tool_source.parse_profile()
profile_valid = PROFILE_PATTERN.match(profile) is not None
if not profile_valid:
lint_ctx.error(PROFILE_INVALID_MSG % profile, **node_props(tool_node))
lint_ctx.error(PROFILE_INVALID_MSG % profile, node=tool_node)
elif profile == "16.01":
lint_ctx.valid(PROFILE_INFO_DEFAULT_MSG, **node_props(tool_node))
lint_ctx.valid(PROFILE_INFO_DEFAULT_MSG, node=tool_node)
else:
lint_ctx.valid(PROFILE_INFO_SPECIFIED_MSG % profile, **node_props(tool_node))
lint_ctx.valid(PROFILE_INFO_SPECIFIED_MSG % profile, node=tool_node)

requirements, containers = tool_source.parse_requirements_and_containers()
for r in requirements:
Expand Down
22 changes: 11 additions & 11 deletions lib/galaxy/tool_util/linters/help.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,38 @@
rst_to_html,
unicodify,
)
from ._util import node_props_factory


def lint_help(tool_xml, lint_ctx):
"""Ensure tool contains exactly one valid RST help block."""
# determine node to report for general problems with help
root = tool_xml.getroot()
node_props = node_props_factory(tool_xml)
helps = root.findall("help")
root = tool_xml.find("./help")
if root is None:
root = tool_xml.getroot()
helps = tool_xml.findall("./help")
if len(helps) > 1:
lint_ctx.error("More than one help section found, behavior undefined.", **node_props(helps[1]))
lint_ctx.error("More than one help section found, behavior undefined.", node=helps[1])
return

if len(helps) == 0:
lint_ctx.warn("No help section found, consider adding a help section to your tool.", **node_props(root))
lint_ctx.warn("No help section found, consider adding a help section to your tool.", node=root)
return

help = helps[0].text or ''
if not help.strip():
lint_ctx.warn("Help section appears to be empty.", **node_props(helps[0]))
lint_ctx.warn("Help section appears to be empty.", node=helps[0])
return

lint_ctx.valid("Tool contains help section.", **node_props(helps[0]))
lint_ctx.valid("Tool contains help section.", node=helps[0])
invalid_rst = rst_invalid(help)

if "TODO" in help:
lint_ctx.warn("Help contains TODO text.", **node_props(helps[0]))
lint_ctx.warn("Help contains TODO text.", node=helps[0])

if invalid_rst:
lint_ctx.warn(f"Invalid reStructuredText found in help - [{invalid_rst}].", **node_props(helps[0]))
lint_ctx.warn(f"Invalid reStructuredText found in help - [{invalid_rst}].", node=helps[0])
else:
lint_ctx.valid("Help contains valid reStructuredText.", **node_props(helps[0]))
lint_ctx.valid("Help contains valid reStructuredText.", node=helps[0])


def rst_invalid(text):
Expand Down
Loading

0 comments on commit 665d83e

Please sign in to comment.