diff --git a/lib/galaxy/tool_util/linters/citations.py b/lib/galaxy/tool_util/linters/citations.py
index e799e7773528..3e57cf836927 100644
--- a/lib/galaxy/tool_util/linters/citations.py
+++ b/lib/galaxy/tool_util/linters/citations.py
@@ -26,17 +26,6 @@ def lint(cls, tool_source: "ToolSource", lint_ctx: "LintContext"):
lint_ctx.warn("No citations found, consider adding citations to your tool.", node=root)
-class CitationsMultiple(Linter):
- @classmethod
- def lint(cls, tool_source: "ToolSource", lint_ctx: "LintContext"):
- tool_xml = getattr(tool_source, "xml_tree", None)
- if not tool_xml:
- return
- citations = tool_xml.findall("citations")
- if len(citations) > 1:
- lint_ctx.error("More than one citation section found, behavior undefined.", node=citations[1])
-
-
class CitationsNoText(Linter):
@classmethod
def lint(cls, tool_source: "ToolSource", lint_ctx: "LintContext"):
diff --git a/lib/galaxy/tool_util/linters/command.py b/lib/galaxy/tool_util/linters/command.py
index be2c0338a5ed..f0b7f5bb6b80 100644
--- a/lib/galaxy/tool_util/linters/command.py
+++ b/lib/galaxy/tool_util/linters/command.py
@@ -12,17 +12,6 @@
from galaxy.tool_util.parser.interface import ToolSource
-class CommandMultiple(Linter):
- @classmethod
- def lint(cls, tool_source: "ToolSource", lint_ctx: "LintContext"):
- tool_xml = getattr(tool_source, "xml_tree", None)
- if not tool_xml:
- return
- commands = tool_xml.findall("./command")
- if len(commands) > 1:
- lint_ctx.error("More than one command tag found, behavior undefined.", node=commands[1])
-
-
class CommandMissing(Linter):
@classmethod
def lint(cls, tool_source: "ToolSource", lint_ctx: "LintContext"):
diff --git a/lib/galaxy/tool_util/linters/help.py b/lib/galaxy/tool_util/linters/help.py
index 8c2260bc9925..9b439fd53ad1 100644
--- a/lib/galaxy/tool_util/linters/help.py
+++ b/lib/galaxy/tool_util/linters/help.py
@@ -15,17 +15,6 @@
from galaxy.tool_util.parser.interface import ToolSource
-class HelpMultiple(Linter):
- @classmethod
- def lint(cls, tool_source: "ToolSource", lint_ctx: "LintContext"):
- tool_xml = getattr(tool_source, "xml_tree", None)
- if not tool_xml:
- return
- helps = tool_xml.findall("./help")
- if len(helps) > 1:
- lint_ctx.error("More than one help section found, behavior undefined.", node=helps[1])
-
-
class HelpMissing(Linter):
@classmethod
def lint(cls, tool_source: "ToolSource", lint_ctx: "LintContext"):
diff --git a/lib/galaxy/tool_util/linters/inputs.py b/lib/galaxy/tool_util/linters/inputs.py
index 55febd6269d9..b8b5ec273eef 100644
--- a/lib/galaxy/tool_util/linters/inputs.py
+++ b/lib/galaxy/tool_util/linters/inputs.py
@@ -121,7 +121,7 @@
PARAM_TYPE_CHILD_COMBINATIONS = [
("./options", ["data", "select", "drill_down"]),
("./options/option", ["drill_down"]),
- ("./column", ["data_column"]),
+ ("./options/column", ["select"]),
]
# TODO lint for valid param type - attribute combinations
@@ -1167,38 +1167,6 @@ def _iter_conditional(tool_xml: "ElementTree") -> Iterator[Tuple["Element", Opti
yield conditional, conditional_name, first_param, first_param_type
-class ConditionalName(Linter):
- @classmethod
- def lint(cls, tool_source: "ToolSource", lint_ctx: "LintContext"):
- tool_xml = getattr(tool_source, "xml_tree", None)
- if not tool_xml:
- return
- conditionals = tool_xml.findall("./inputs//conditional")
- for conditional in conditionals:
- conditional_name = conditional.get("name")
- if not conditional_name:
- lint_ctx.error("Conditional without a name", node=conditional)
-
-
-class ConditionalParamNumber(Linter):
- @classmethod
- def lint(cls, tool_source: "ToolSource", lint_ctx: "LintContext"):
- tool_xml = getattr(tool_source, "xml_tree", None)
- if not tool_xml:
- return
- conditionals = tool_xml.findall("./inputs//conditional")
- for conditional in conditionals:
- conditional_name = conditional.get("name")
- if conditional.get("value_from"): # Probably only the upload tool use this, no children elements
- continue
- first_param = conditional.findall("param")
- if len(first_param) != 1:
- lint_ctx.error(
- f"Conditional [{conditional_name}] needs exactly one child found {len(first_param)}",
- node=conditional,
- )
-
-
class ConditionalParamTypeBool(Linter):
@classmethod
def lint(cls, tool_source: "ToolSource", lint_ctx: "LintContext"):
@@ -1242,20 +1210,6 @@ def lint(cls, tool_source: "ToolSource", lint_ctx: "LintContext"):
)
-class ConditionalWhenValue(Linter):
- @classmethod
- def lint(cls, tool_source: "ToolSource", lint_ctx: "LintContext"):
- tool_xml = getattr(tool_source, "xml_tree", None)
- if not tool_xml:
- return
- for conditional, conditional_name, _, first_param_type in _iter_conditional(tool_xml):
- if first_param_type not in ["boolean", "select"]:
- continue
- whens = conditional.findall("./when")
- if any("value" not in when.attrib for when in whens):
- lint_ctx.error(f"Conditional [{conditional_name}] when without value", node=conditional)
-
-
class ConditionalWhenMissing(Linter):
@classmethod
def lint(cls, tool_source: "ToolSource", lint_ctx: "LintContext"):
diff --git a/lib/galaxy/tool_util/linters/outputs.py b/lib/galaxy/tool_util/linters/outputs.py
index 7395e1aed152..db8068f050d6 100644
--- a/lib/galaxy/tool_util/linters/outputs.py
+++ b/lib/galaxy/tool_util/linters/outputs.py
@@ -4,14 +4,13 @@
from packaging.version import Version
from galaxy.tool_util.lint import Linter
-from galaxy.util import string_as_bool
from ._util import is_valid_cheetah_placeholder
from ..parser.output_collection_def import NAMED_PATTERNS
if TYPE_CHECKING:
from galaxy.tool_util.lint import LintContext
from galaxy.tool_util.parser import ToolSource
- from galaxy.util.etree import Element
+ from galaxy.util.etree import Element, ElementTree
class OutputsMissing(Linter):
@@ -27,17 +26,6 @@ def lint(cls, tool_source: "ToolSource", lint_ctx: "LintContext"):
lint_ctx.warn("Tool contains no outputs section, most tools should produce outputs.", node=tool_node)
-class OutputsMultiple(Linter):
- @classmethod
- def lint(cls, tool_source: "ToolSource", lint_ctx: "LintContext"):
- tool_xml = getattr(tool_source, "xml_tree", None)
- if not tool_xml:
- return
- outputs = tool_xml.findall("./outputs")
- if len(outputs) > 1:
- lint_ctx.warn("Tool contains multiple output sections, behavior undefined.", node=outputs[1])
-
-
class OutputsOutput(Linter):
@classmethod
def lint(cls, tool_source: "ToolSource", lint_ctx: "LintContext"):
@@ -49,18 +37,6 @@ def lint(cls, tool_source: "ToolSource", lint_ctx: "LintContext"):
lint_ctx.warn("Avoid the use of 'output' and replace by 'data' or 'collection'", node=output)
-class OutputsNameMissing(Linter):
- @classmethod
- def lint(cls, tool_source: "ToolSource", lint_ctx: "LintContext"):
- tool_xml = getattr(tool_source, "xml_tree", None)
- if not tool_xml:
- return
- for output in tool_xml.findall("./outputs/data") + tool_xml.findall("./outputs/collection"):
- if "name" not in output.attrib:
- # TODO make this an error if there is no discover_datasets / from_work_dir (is this then still a problem)
- lint_ctx.warn("Tool output doesn't define a name - this is likely a problem.", node=output)
-
-
class OutputsNameInvalidCheetah(Linter):
@classmethod
def lint(cls, tool_source: "ToolSource", lint_ctx: "LintContext"):
@@ -187,7 +163,7 @@ def lint(cls, tool_source: "ToolSource", lint_ctx: "LintContext"):
if "structured_like" in output.attrib and "inherit_format" in output.attrib:
format_set = True
for sub in output:
- if _check_pattern(sub):
+ if _check_pattern(sub) or _has_tool_provided_metadata(tool_xml):
format_set = True
elif _check_format(sub):
format_set = True
@@ -241,10 +217,6 @@ def _check_pattern(node):
"""
if node.tag != "discover_datasets":
return False
- if "from_tool_provided_metadata" in node.attrib and string_as_bool(
- node.attrib.get("from_tool_provided_metadata", "false")
- ):
- return True
if "pattern" not in node.attrib:
return False
pattern = node.attrib["pattern"]
@@ -252,3 +224,18 @@ def _check_pattern(node):
# TODO error on wrong pattern or non-regexp
if "(?P" in regex_pattern:
return True
+
+
+def _has_tool_provided_metadata(tool_xml: "ElementTree") -> bool:
+ outputs = tool_xml.find("./outputs")
+ if outputs is not None:
+ if "provided_metadata_file" in outputs.attrib or "provided_metadata_style" in outputs.attrib:
+ return True
+ command = tool_xml.find("./command")
+ if command is not None:
+ if "galaxy.json" in command.text:
+ return True
+ config = tool_xml.find("./configfiles/configfile[@filename='galaxy.json']")
+ if config is not None:
+ return True
+ return False
diff --git a/lib/galaxy/tool_util/linters/stdio.py b/lib/galaxy/tool_util/linters/stdio.py
index 3e1bf619b279..988d66965f9c 100644
--- a/lib/galaxy/tool_util/linters/stdio.py
+++ b/lib/galaxy/tool_util/linters/stdio.py
@@ -53,21 +53,6 @@ def lint(cls, tool_source: "ToolSource", lint_ctx: "LintContext"):
)
-class StdIOMultiple(Linter):
- @classmethod
- def lint(cls, tool_source: "ToolSource", lint_ctx: "LintContext"):
- tool_xml = getattr(tool_source, "xml_tree", None)
- if not tool_xml:
- # Can only lint XML tools at this point.
- # Should probably use tool_source.parse_stdio() to abstract away XML details
- return
- stdios = tool_xml.findall("./stdio") if tool_xml else []
-
- if len(stdios) > 1:
- lint_ctx.error("More than one stdio tag found, behavior undefined.", node=stdios[1])
- return
-
-
class StdIORegex(Linter):
@classmethod
def lint(cls, tool_source: "ToolSource", lint_ctx: "LintContext"):
diff --git a/lib/galaxy/tool_util/linters/tests.py b/lib/galaxy/tool_util/linters/tests.py
index 0d7f83fd0292..08232bc9daf7 100644
--- a/lib/galaxy/tool_util/linters/tests.py
+++ b/lib/galaxy/tool_util/linters/tests.py
@@ -1,8 +1,4 @@
"""This module contains a linting functions for tool tests."""
-from inspect import (
- Parameter,
- signature,
-)
from typing import (
List,
Optional,
@@ -12,7 +8,6 @@
from galaxy.tool_util.lint import Linter
from galaxy.util import asbool
from ._util import is_datasource
-from ..verify import asserts
if TYPE_CHECKING:
from galaxy.tool_util.lint import LintContext
@@ -66,66 +61,6 @@ def lint(cls, tool_source: "ToolSource", lint_ctx: "LintContext"):
)
-class TestsAssertsUnknown(Linter):
- @classmethod
- def lint(cls, tool_source: "ToolSource", lint_ctx: "LintContext"):
- tool_xml = getattr(tool_source, "xml_tree", None)
- if not tool_xml:
- return
- tests = tool_xml.findall("./tests/test")
- for test_idx, test in enumerate(tests, start=1):
- for a in test.xpath(
- ".//*[self::assert_contents or self::assert_stdout or self::assert_stderr or self::assert_command]//*"
- ):
- assert_function_name = "assert_" + a.tag
- if assert_function_name not in asserts.assertion_functions:
- lint_ctx.error(f"Test {test_idx}: unknown assertion '{a.tag}'", node=a)
-
-
-class TestsAssertsUnknownAttrib(Linter):
- @classmethod
- def lint(cls, tool_source: "ToolSource", lint_ctx: "LintContext"):
- tool_xml = getattr(tool_source, "xml_tree", None)
- if not tool_xml:
- return
- tests = tool_xml.findall("./tests/test")
- for test_idx, test in enumerate(tests, start=1):
- for a in test.xpath(
- ".//*[self::assert_contents or self::assert_stdout or self::assert_stderr or self::assert_command]//*"
- ):
- assert_function_name = "assert_" + a.tag
- if assert_function_name not in asserts.assertion_functions:
- continue
- assert_function_sig = signature(asserts.assertion_functions[assert_function_name])
- # check of the attributes
- for attrib in a.attrib:
- if attrib not in assert_function_sig.parameters:
- lint_ctx.error(f"Test {test_idx}: unknown attribute '{attrib}' for '{a.tag}'", node=a)
-
-
-class TestsAssertsMissingAttrib(Linter):
- @classmethod
- def lint(cls, tool_source: "ToolSource", lint_ctx: "LintContext"):
- tool_xml = getattr(tool_source, "xml_tree", None)
- if not tool_xml:
- return
- tests = tool_xml.findall("./tests/test")
- for test_idx, test in enumerate(tests, start=1):
- for a in test.xpath(
- ".//*[self::assert_contents or self::assert_stdout or self::assert_stderr or self::assert_command]//*"
- ):
- assert_function_name = "assert_" + a.tag
- if assert_function_name not in asserts.assertion_functions:
- continue
- assert_function_sig = signature(asserts.assertion_functions[assert_function_name])
- # check missing required attributes
- for p in assert_function_sig.parameters:
- if p in ["output", "output_bytes", "verify_assertions_function", "children"]:
- continue
- if assert_function_sig.parameters[p].default is Parameter.empty and p not in a.attrib:
- lint_ctx.error(f"Test {test_idx}: missing attribute '{p}' for '{a.tag}'", node=a)
-
-
class TestsAssertsHasNQuant(Linter):
@classmethod
def lint(cls, tool_source: "ToolSource", lint_ctx: "LintContext"):
@@ -181,19 +116,6 @@ def lint(cls, tool_source: "ToolSource", lint_ctx: "LintContext"):
)
-class TestsParamName(Linter):
- @classmethod
- def lint(cls, tool_source: "ToolSource", lint_ctx: "LintContext"):
- tool_xml = getattr(tool_source, "xml_tree", None)
- if not tool_xml:
- return
- tests = tool_xml.findall("./tests/test")
- for test_idx, test in enumerate(tests, start=1):
- for param in test.findall("param"):
- if not param.attrib.get("name", None):
- lint_ctx.error(f"Test {test_idx}: Found test param tag without a name defined.", node=param)
-
-
class TestsParamInInputs(Linter):
"""
really simple linter that test parameters are also present in the inputs
@@ -233,7 +155,8 @@ def lint(cls, tool_source: "ToolSource", lint_ctx: "LintContext"):
return
tests = tool_xml.findall("./tests/test")
for test_idx, test in enumerate(tests, start=1):
- for output in test.findall("output") + test.findall("output_collection"):
+ # note output_collections are covered by xsd, but output is not required to have one by xsd
+ for output in test.findall("output"):
if not output.attrib.get("name", None):
lint_ctx.error(f"Test {test_idx}: Found {output.tag} tag without a name defined.", node=output)
diff --git a/test/unit/tool_util/test_tool_linters.py b/test/unit/tool_util/test_tool_linters.py
index 3412f938059f..f8f7f6fb16e1 100644
--- a/test/unit/tool_util/test_tool_linters.py
+++ b/test/unit/tool_util/test_tool_linters.py
@@ -34,18 +34,18 @@
# TODO tests tool xml for general linter
# tests tool xml for citations linter
CITATIONS_MULTIPLE = """
-
+
"""
CITATIONS_ABSENT = """
-
+
"""
CITATIONS_ERRORS = """
-
+
@@ -53,7 +53,7 @@
"""
CITATIONS_VALID = """
-
+
DOI
@@ -62,23 +62,23 @@
# tests tool xml for command linter
COMMAND_MULTIPLE = """
-
+
ls
df
"""
COMMAND_MISSING = """
-
+
"""
COMMAND_TODO = """
-
+
## TODO
"""
COMMAND_DETECT_ERRORS_INTERPRETER = """
-
+
"""
@@ -91,7 +91,7 @@
"""
GENERAL_WHITESPACE_IN_VERSIONS_AND_NAMES = """
-
+
bwa
@@ -99,7 +99,7 @@
"""
GENERAL_REQUIREMENT_WO_VERSION = """
-
+
bwa
@@ -119,31 +119,31 @@
# test tool xml for help linter
HELP_MULTIPLE = """
-
+
Help
More help
"""
HELP_ABSENT = """
-
+
"""
HELP_EMPTY = """
-
+
"""
HELP_TODO = """
-
+
TODO
"""
HELP_INVALID_RST = """
-
+
**xxl__
@@ -152,7 +152,7 @@
# test tool xml for inputs linter
INPUTS_NO_INPUTS = """
-
+
"""
@@ -163,7 +163,7 @@
"""
INPUTS_VALID = """
-
+
@@ -172,7 +172,7 @@
"""
INPUTS_PARAM_NAME = """
-
+
@@ -193,7 +193,7 @@
"""
INPUTS_DATA_PARAM = """
-
+
@@ -201,7 +201,7 @@
"""
INPUTS_DATA_PARAM_OPTIONS = """
-
+
@@ -213,7 +213,7 @@
"""
INPUTS_DATA_PARAM_OPTIONS_FILTER_ATTRIBUTE = """
-
+
@@ -225,12 +225,12 @@
"""
INPUTS_DATA_PARAM_INVALIDOPTIONS = """
-
+
-
+
@@ -238,7 +238,7 @@
"""
INPUTS_BOOLEAN_PARAM_SWAPPED_LABELS = """
-
+
@@ -246,7 +246,7 @@
"""
INPUTS_BOOLEAN_PARAM_DUPLICATE_LABELS = """
-
+
@@ -254,7 +254,7 @@
"""
INPUTS_CONDITIONAL = """
-
+
@@ -309,7 +309,7 @@
"""
INPUTS_SELECT_INCOMPATIBLE_DISPLAY = """
-
+
@@ -329,7 +329,7 @@
"""
INPUTS_SELECT_DUPLICATED_OPTIONS = """
-
+
@@ -340,7 +340,7 @@
"""
SELECT_DUPLICATED_OPTIONS_WITH_DIFF_SELECTED = """
-
+
@@ -351,7 +351,7 @@
"""
INPUTS_SELECT_DEPRECATIONS = """
-
+
@@ -404,7 +404,7 @@
"""
INPUTS_VALIDATOR_INCOMPATIBILITIES = """
-
+
TEXT
@@ -424,7 +424,7 @@
"""
INPUTS_VALIDATOR_CORRECT = """
-
+
@@ -436,7 +436,7 @@
-
+
@@ -469,7 +469,7 @@
"""
INPUTS_TYPE_CHILD_COMBINATIONS = """
-
+
@@ -480,19 +480,21 @@
-
+
+
+
"""
INPUTS_DUPLICATE_NAMES = """
-
+
-
+
@@ -517,10 +519,10 @@
# test tool xml for outputs linter
OUTPUTS_MISSING = """
-
+
"""
OUTPUTS_MULTIPLE = """
-
+
@@ -533,22 +535,23 @@
"""
OUTPUTS_UNNAMED_INVALID_NAME = """
-
+
+
"""
OUTPUTS_FORMAT_INPUT_LEGACY = """
-
+
"""
OUTPUTS_FORMAT_INPUT = """
-
+
@@ -558,7 +561,7 @@
# check that linter accepts format source for collection elements as means to specify format
# and that the linter warns if format and format_source are used
OUTPUTS_COLLECTION_FORMAT_SOURCE = """
-
+
@@ -570,7 +573,7 @@
# check that setting format with actions is supported
OUTPUTS_FORMAT_ACTION = """
-
+
@@ -589,16 +592,18 @@
# check that linter does not complain about missing format if from_tool_provided_metadata is used
OUTPUTS_DISCOVER_TOOL_PROVIDED_METADATA = """
-
+
+ galaxy.json
-
+
"""
+
OUTPUTS_DUPLICATED_NAME_LABEL = """
-
+
@@ -625,17 +630,17 @@
# tool xml for stdio linter
STDIO_DEFAULT_FOR_DEFAULT_PROFILE = """
-
+
"""
STDIO_DEFAULT_FOR_NONLEGACY_PROFILE = """
-
+
"""
STDIO_MULTIPLE_STDIO = """
-
+
@@ -652,7 +657,7 @@
"""
STDIO_INVALID_MATCH = """
-
+
@@ -661,13 +666,13 @@
# check that linter does complain about tests wo assumptions
TESTS_ABSENT = """
-
+
"""
TESTS_ABSENT_DATA_SOURCE = """
-
+
"""
TESTS_WO_EXPECTATIONS = """
-
+
@@ -676,12 +681,13 @@
"""
TESTS_PARAM_OUTPUT_NAMES = """
-
+
-
-
-
-
+
+
+
+
+
@@ -707,7 +713,7 @@
"""
TESTS_EXPECT_FAILURE_OUTPUT = """
-
+
@@ -721,7 +727,7 @@
"""
ASSERTS = """
-
+
@@ -758,7 +764,7 @@
"""
TESTS_VALID = """
-
+
@@ -770,7 +776,7 @@
"""
TESTS_OUTPUT_TYPE_MISMATCH = """
-
+
@@ -784,7 +790,7 @@
"""
TESTS_DISCOVER_OUTPUTS = """
-
+
@@ -833,9 +839,9 @@
"""
TESTS_EXPECT_NUM_OUTPUTS_FILTER = """
-
+
-
+
@@ -847,7 +853,7 @@
"""
TESTS_COMPARE_ATTRIB_INCOMPATIBILITY = """
-
+
@@ -921,7 +927,7 @@ def get_tool_xml_exact(xml_string: str):
def run_lint_module(lint_ctx, lint_module, lint_target):
- lint_tool_source_with_modules(lint_ctx, lint_target, [lint_module])
+ lint_tool_source_with_modules(lint_ctx, lint_target, list(set([lint_module, xsd])))
def run_lint(lint_ctx, lint_func, lint_target):
@@ -934,7 +940,7 @@ def run_lint(lint_ctx, lint_func, lint_target):
def test_citations_multiple(lint_ctx):
tool_source = get_xml_tool_source(CITATIONS_MULTIPLE)
run_lint_module(lint_ctx, citations, tool_source)
- assert lint_ctx.error_messages == ["More than one citation section found, behavior undefined."]
+ assert lint_ctx.error_messages == ["Invalid XML: Element 'citations': This element is not expected."]
assert not lint_ctx.info_messages
assert not lint_ctx.valid_messages
assert not lint_ctx.warn_messages
@@ -970,7 +976,7 @@ def test_citations_valid(lint_ctx):
def test_command_multiple(lint_ctx):
tool_source = get_xml_tool_source(COMMAND_MULTIPLE)
run_lint_module(lint_ctx, command, tool_source)
- assert lint_ctx.error_messages == ["More than one command tag found, behavior undefined."]
+ assert lint_ctx.error_messages == ["Invalid XML: Element 'command': This element is not expected."]
assert lint_ctx.info_messages == ["Tool contains a command."]
assert not lint_ctx.valid_messages
assert not lint_ctx.warn_messages
@@ -997,10 +1003,12 @@ def test_command_todo(lint_ctx):
def test_command_detect_errors_interpreter(lint_ctx):
tool_source = get_xml_tool_source(COMMAND_DETECT_ERRORS_INTERPRETER)
run_lint_module(lint_ctx, command, tool_source)
- assert lint_ctx.error_messages == ["Command is empty."]
+ assert "Command is empty." in lint_ctx.error_messages
+ assert "Invalid XML: Element 'command', attribute 'detect_errors': [facet 'enumeration'] The value 'nonsense' is not an element of the set {'default', 'exit_code', 'aggressive'}." in lint_ctx.error_messages
assert lint_ctx.warn_messages == ["Command uses deprecated 'interpreter' attribute."]
assert lint_ctx.info_messages == ["Tool contains a command with interpreter of type [python]."]
assert not lint_ctx.valid_messages
+ assert len(lint_ctx.error_messages) == 2
def test_general_missing_tool_id_name_version(lint_ctx):
@@ -1069,7 +1077,7 @@ def test_help_multiple(lint_ctx):
assert not lint_ctx.info_messages
assert len(lint_ctx.valid_messages) == 2 # has help and valid rst
assert not lint_ctx.warn_messages
- assert lint_ctx.error_messages == ["More than one help section found, behavior undefined."]
+ assert lint_ctx.error_messages == ["Invalid XML: Element 'help': This element is not expected."]
def test_help_absent(lint_ctx):
@@ -1170,7 +1178,6 @@ def test_inputs_param_name(lint_ctx):
def test_inputs_param_type(lint_ctx):
tool_source = get_xml_tool_source(INPUTS_PARAM_TYPE)
run_lint_module(lint_ctx, inputs, tool_source)
- run_lint_module(lint_ctx, xsd, tool_source)
assert "Found 2 input parameters." in lint_ctx.info_messages
assert "Invalid XML: Element 'param': The attribute 'type' is required but missing." in lint_ctx.error_messages
assert (
@@ -1236,7 +1243,7 @@ def test_inputs_data_param_invalid_options(lint_ctx):
assert "Data parameter [valid_name] contains multiple options elements." in lint_ctx.error_messages
assert "Data parameter [valid_name] filter needs to define a ref attribute" in lint_ctx.error_messages
assert (
- 'Data parameter [valid_name] for filters only type="data_meta" and key="dbkey" are allowed, found type="expression" and key="None"'
+ 'Data parameter [valid_name] for filters only type="data_meta" and key="dbkey" are allowed, found type="regexp" and key="None"'
in lint_ctx.error_messages
)
assert len(lint_ctx.error_messages) == 3
@@ -1246,13 +1253,13 @@ def test_inputs_conditional(lint_ctx):
tool_source = get_xml_tool_source(INPUTS_CONDITIONAL)
run_lint_module(lint_ctx, inputs, tool_source)
assert "Found 10 input parameters." in lint_ctx.info_messages
- assert "Conditional without a name" in lint_ctx.error_messages
+ assert "Invalid XML: Element 'conditional': The attribute 'name' is required but missing." in lint_ctx.error_messages
assert (
"Select parameter of a conditional [select] options have to be defined by 'option' children elements."
in lint_ctx.error_messages
)
- assert "Conditional [cond_wo_param] needs exactly one child found 0" in lint_ctx.error_messages
- assert "Conditional [cond_w_mult_param] needs exactly one child found 2" in lint_ctx.error_messages
+ assert "Invalid XML: Element 'param': This element is not expected. Expected is ( when )." in lint_ctx.error_messages # 2x param
+ assert "Invalid XML: Element 'conditional': Missing child element(s). Expected is ( param )." in lint_ctx.error_messages
assert 'Conditional [cond_text] first param should have type="select"' in lint_ctx.error_messages
assert (
'Conditional [cond_boolean] first param of type="boolean" is discouraged, use a select'
@@ -1261,7 +1268,7 @@ def test_inputs_conditional(lint_ctx):
assert "Conditional [cond_boolean] no truevalue/falsevalue found for when block 'False'" in lint_ctx.warn_messages
assert 'Conditional [cond_w_optional_select] test parameter cannot be optional="true"' in lint_ctx.warn_messages
assert 'Conditional [cond_w_multiple_select] test parameter cannot be multiple="true"' in lint_ctx.warn_messages
- assert "Conditional [when_wo_value] when without value" in lint_ctx.error_messages
+ assert "Invalid XML: Element 'when': The attribute 'value' is required but missing." in lint_ctx.error_messages
assert "Conditional [missing_when] no block found for select option 'none'" in lint_ctx.warn_messages
assert len(lint_ctx.info_messages) == 1
assert not lint_ctx.valid_messages
@@ -1363,7 +1370,6 @@ def test_inputs_select_option_definitions(lint_ctx):
def test_inputs_select_filter(lint_ctx):
tool_source = get_xml_tool_source(INPUTS_SELECT_FILTER)
run_lint_module(lint_ctx, inputs, tool_source)
- run_lint_module(lint_ctx, xsd, tool_source)
assert "Found 1 input parameters." in lint_ctx.info_messages
assert "Invalid XML: Element 'filter': The attribute 'type' is required but missing." in lint_ctx.error_messages
assert (
@@ -1447,7 +1453,7 @@ def test_inputs_type_child_combinations(lint_ctx):
in lint_ctx.error_messages
)
assert (
- "Parameter [data_param] './column' tags are only allowed for parameters of type ['data_column']"
+ "Parameter [data_param] './options/column' tags are only allowed for parameters of type ['select']"
in lint_ctx.error_messages
)
assert len(lint_ctx.error_messages) == 3
@@ -1472,7 +1478,6 @@ def test_inputs_repeats(lint_ctx):
"""
tool_source = get_xml_tool_source(REPEATS)
run_lint_module(lint_ctx, inputs, tool_source)
- run_lint_module(lint_ctx, xsd, tool_source)
assert lint_ctx.info_messages == ["Found 1 input parameters."]
assert not lint_ctx.valid_messages
assert not lint_ctx.warn_messages
@@ -1495,11 +1500,11 @@ def test_outputs_multiple(lint_ctx):
tool_source = get_xml_tool_source(OUTPUTS_MULTIPLE)
run_lint_module(lint_ctx, outputs, tool_source)
assert "0 outputs found." in lint_ctx.info_messages
- assert "Tool contains multiple output sections, behavior undefined." in lint_ctx.warn_messages
+ assert "Invalid XML: Element 'outputs': This element is not expected." in lint_ctx.error_messages
assert len(lint_ctx.info_messages) == 1
assert not lint_ctx.valid_messages
- assert len(lint_ctx.warn_messages) == 1
- assert not lint_ctx.error_messages
+ assert not lint_ctx.warn_messages
+ assert len(lint_ctx.error_messages) == 1
def test_outputs_unknown_tag(lint_ctx):
@@ -1522,16 +1527,17 @@ def test_outputs_unknown_tag(lint_ctx):
def test_outputs_unnamed_invalid_name(lint_ctx):
tool_source = get_xml_tool_source(OUTPUTS_UNNAMED_INVALID_NAME)
run_lint_module(lint_ctx, outputs, tool_source)
- assert "2 outputs found." in lint_ctx.info_messages
- assert "Tool output doesn't define a name - this is likely a problem." in lint_ctx.warn_messages
+ assert "3 outputs found." in lint_ctx.info_messages
+ assert "Invalid XML: Element 'data': The attribute 'name' is required but missing." in lint_ctx.error_messages
+ assert "Invalid XML: Element 'collection': The attribute 'name' is required but missing." in lint_ctx.error_messages
assert "Tool data output with missing name doesn't define an output format." in lint_ctx.warn_messages
assert "Tool output name [2output] is not a valid Cheetah placeholder." in lint_ctx.warn_messages
assert "Collection output with undefined 'type' found." in lint_ctx.warn_messages
assert "Tool collection output 2output doesn't define an output format." in lint_ctx.warn_messages
assert len(lint_ctx.info_messages) == 1
assert not lint_ctx.valid_messages
- assert len(lint_ctx.warn_messages) == 5
- assert not lint_ctx.error_messages
+ assert len(lint_ctx.warn_messages) == 4
+ assert len(lint_ctx.error_messages) == 2
def test_outputs_format_input_legacy(lint_ctx):
@@ -1629,7 +1635,7 @@ def test_stdio_default_for_nonlegacy_profile(lint_ctx):
def test_stdio_multiple_stdio(lint_ctx):
tool_source = get_xml_tool_source(STDIO_MULTIPLE_STDIO)
run_lint_module(lint_ctx, stdio, tool_source)
- assert "More than one stdio tag found, behavior undefined." in lint_ctx.error_messages
+ assert "Invalid XML: Element 'stdio': This element is not expected." in lint_ctx.error_messages
assert not lint_ctx.info_messages
assert not lint_ctx.valid_messages
assert not lint_ctx.warn_messages
@@ -1697,14 +1703,14 @@ def test_tests_param_output_names(lint_ctx):
tool_source = get_xml_tool_source(TESTS_PARAM_OUTPUT_NAMES)
run_lint_module(lint_ctx, tests, tool_source)
assert "1 test(s) found." in lint_ctx.valid_messages
- assert "Test 1: Found test param tag without a name defined." in lint_ctx.error_messages
+ assert "Invalid XML: Element 'param': The attribute 'name' is required but missing." in lint_ctx.error_messages
assert "Test 1: Test param non_existent_test_name not found in the inputs" in lint_ctx.error_messages
assert "Test 1: Found output tag without a name defined." in lint_ctx.error_messages
assert (
"Test 1: Found output tag with unknown name [nonexistent_output], valid names ['existent_output', 'existent_collection']"
in lint_ctx.error_messages
)
- assert "Test 1: Found output_collection tag without a name defined." in lint_ctx.error_messages
+ assert "Invalid XML: Element 'output_collection': The attribute 'name' is required but missing." in lint_ctx.error_messages
assert (
"Test 1: Found output_collection tag with unknown name [nonexistent_collection], valid names ['existent_output', 'existent_collection']"
in lint_ctx.error_messages
@@ -1756,19 +1762,19 @@ def test_tests_valid(lint_ctx):
def test_tests_asserts(lint_ctx):
tool_source = get_xml_tool_source(ASSERTS)
run_lint_module(lint_ctx, tests, tool_source)
- assert "Test 1: unknown assertion 'invalid'" in lint_ctx.error_messages
- assert "Test 1: unknown attribute 'invalid_attrib' for 'has_text'" in lint_ctx.error_messages
- assert "Test 1: missing attribute 'text' for 'has_text'" in lint_ctx.error_messages
- assert "Test 1: attribute 'value' for 'has_size' needs to be 'int' got '500k'" not in lint_ctx.error_messages
+ assert "Invalid XML: Element 'invalid': This element is not expected." in lint_ctx.error_messages
+ assert "Invalid XML: Element 'has_text', attribute 'invalid_attrib': The attribute 'invalid_attrib' is not allowed." in lint_ctx.error_messages
+ assert "Invalid XML: Element 'has_text': The attribute 'text' is required but missing." in lint_ctx.error_messages
+ assert "Invalid XML: Element 'has_size', attribute 'delta': [facet 'pattern'] The value '1O' is not accepted by the pattern '(0|[1-9][0-9]*)([kKMGTPE]i?)?'." in lint_ctx.error_messages
assert (
- "Test 1: unknown attribute 'invalid_attrib_also_checked_in_nested_asserts' for 'not_has_text'"
+ "Invalid XML: Element 'not_has_text', attribute 'invalid_attrib_also_checked_in_nested_asserts': The attribute 'invalid_attrib_also_checked_in_nested_asserts' is not allowed."
in lint_ctx.error_messages
)
assert "Test 1: 'has_size' needs to specify 'value', 'min', or 'max'" in lint_ctx.error_messages
assert "Test 1: 'has_n_columns' needs to specify 'n', 'min', or 'max'" in lint_ctx.error_messages
assert "Test 1: 'has_n_lines' needs to specify 'n', 'min', or 'max'" in lint_ctx.error_messages
assert not lint_ctx.warn_messages
- assert len(lint_ctx.error_messages) == 7
+ assert len(lint_ctx.error_messages) == 8
def test_tests_output_type_mismatch(lint_ctx):
@@ -1831,7 +1837,6 @@ def test_tests_compare_attrib_incompatibility(lint_ctx):
def test_xml_order(lint_ctx):
tool_source = get_xml_tool_source(XML_ORDER)
run_lint_module(lint_ctx, xml_order, tool_source)
- run_lint_module(lint_ctx, xsd, tool_source)
assert not lint_ctx.info_messages
assert not lint_ctx.valid_messages
assert lint_ctx.warn_messages == ["Best practice violation [stdio] elements should come before [command]"]