diff --git a/lib/galaxy/tool_util/deps/container_classes.py b/lib/galaxy/tool_util/deps/container_classes.py index e89e55ab6b1a..f55f78614f4f 100644 --- a/lib/galaxy/tool_util/deps/container_classes.py +++ b/lib/galaxy/tool_util/deps/container_classes.py @@ -16,6 +16,7 @@ ) from uuid import uuid4 +from packaging.version import Version from typing_extensions import Protocol from galaxy.util import ( @@ -363,7 +364,7 @@ def add_var(name, value): defaults += ",$tool_directory:default_ro" if self.job_info.job_directory: defaults += ",$job_directory:default_ro,$job_directory/outputs:rw" - if self.tool_info.profile <= 19.09: + if Version(str(self.tool_info.profile)) <= Version("19.09"): defaults += ",$job_directory/configs:rw" if self.job_info.home_directory is not None: defaults += ",$home_directory:rw" diff --git a/lib/galaxy/tool_util/linters/general.py b/lib/galaxy/tool_util/linters/general.py index ee2df7f004d1..d9b06c121725 100644 --- a/lib/galaxy/tool_util/linters/general.py +++ b/lib/galaxy/tool_util/linters/general.py @@ -1,6 +1,8 @@ """This module contains linting functions for general aspects of the tool.""" import re +from packaging.version import Version + from galaxy.tool_util.version import ( LegacyVersion, parse_version, @@ -67,7 +69,7 @@ def lint_general(tool_source, lint_ctx): profile_valid = PROFILE_PATTERN.match(profile) is not None if not profile_valid: lint_ctx.error(PROFILE_INVALID_MSG % profile, node=tool_node) - elif profile == "16.01": + elif Version(profile) == Version("16.01"): lint_ctx.valid(PROFILE_INFO_DEFAULT_MSG, node=tool_node) else: lint_ctx.valid(PROFILE_INFO_SPECIFIED_MSG % profile, node=tool_node) diff --git a/lib/galaxy/tool_util/linters/inputs.py b/lib/galaxy/tool_util/linters/inputs.py index 0c619e49095f..7dd46c21f0e9 100644 --- a/lib/galaxy/tool_util/linters/inputs.py +++ b/lib/galaxy/tool_util/linters/inputs.py @@ -3,6 +3,8 @@ import re from typing import TYPE_CHECKING +from packaging.version import Version + from galaxy.util import string_as_bool from ._util import ( is_datasource, @@ -344,7 +346,7 @@ def lint_inputs(tool_source: "ToolSource", lint_ctx: "LintContext"): if param_type == "boolean": truevalue = param_attrib.get("truevalue", "true") falsevalue = param_attrib.get("falsevalue", "false") - problematic_booleans_allowed = profile < "23.1" + problematic_booleans_allowed = Version(profile) < Version("23.1") lint_level = lint_ctx.warn if problematic_booleans_allowed else lint_ctx.error if truevalue == falsevalue: lint_level( diff --git a/lib/galaxy/tool_util/linters/stdio.py b/lib/galaxy/tool_util/linters/stdio.py index 981882bbde39..ac1171b49eea 100644 --- a/lib/galaxy/tool_util/linters/stdio.py +++ b/lib/galaxy/tool_util/linters/stdio.py @@ -1,6 +1,8 @@ """This module contains a linting functions for tool error detection.""" import re +from packaging.version import Version + from galaxy.util import etree from .command import get_command @@ -20,7 +22,7 @@ def lint_stdio(tool_source, lint_ctx): if not stdios: command = get_command(tool_xml) if tool_xml else None if command is None or not command.get("detect_errors"): - if tool_source.parse_profile() <= "16.01": + if Version(tool_source.parse_profile()) <= Version("16.01"): lint_ctx.info( "No stdio definition found, tool indicates error conditions with output written to stderr.", node=tool_node, diff --git a/lib/galaxy/tool_util/parser/xml.py b/lib/galaxy/tool_util/parser/xml.py index 96b3634c333b..1b7c91755f54 100644 --- a/lib/galaxy/tool_util/parser/xml.py +++ b/lib/galaxy/tool_util/parser/xml.py @@ -130,7 +130,7 @@ def __init__(self, xml_tree: ElementTree, source_path=None, macro_paths=None): self.root = self.xml_tree.getroot() self._source_path = source_path self._macro_paths = macro_paths or [] - self.legacy_defaults = self.parse_profile() == "16.01" + self.legacy_defaults = Version(self.parse_profile()) == Version("16.01") self._string = xml_to_string(self.root) def to_string(self): @@ -250,7 +250,7 @@ def parse_environment_variables(self): return environment_variables def parse_home_target(self): - target = "job_home" if self.parse_profile() >= "18.01" else "shared_home" + target = "job_home" if Version(self.parse_profile()) >= Version("18.01") else "shared_home" command_el = self._command_el command_legacy = (command_el is not None) and command_el.get("use_shared_home", None) if command_legacy is not None: @@ -397,7 +397,7 @@ def parse_provided_metadata_style(self): style = out_elem.attrib["provided_metadata_style"] if style is None: - style = "legacy" if self.parse_profile() < "17.09" else "default" + style = "legacy" if Version(self.parse_profile()) < Version("17.09") else "default" assert style in ["legacy", "default"] return style @@ -539,7 +539,7 @@ def _parse_output( output.filters = data_elem.findall("filter") output.tool = tool output.from_work_dir = data_elem.get("from_work_dir", None) - if output.from_work_dir and getattr(tool, "profile", 0) < 21.09: + if output.from_work_dir and Version(str(getattr(tool, "profile", 0))) < Version("21.09"): # We started quoting from_work_dir outputs in 21.09. # Prior to quoting, trailing spaces had no effect. # This ensures that old tools continue to work. @@ -760,7 +760,7 @@ def __parse_element_tests(parent_element, profile=None): element_tests[identifier] = __parse_test_attributes( element, element_attrib, parse_elements=True, profile=profile ) - if profile and profile >= "20.09": + if profile and Version(profile) >= Version("20.09"): element_tests[identifier][1]["expected_sort_order"] = idx return element_tests diff --git a/lib/galaxy/tools/__init__.py b/lib/galaxy/tools/__init__.py index 3168f6a52e13..4f973befaba9 100644 --- a/lib/galaxy/tools/__init__.py +++ b/lib/galaxy/tools/__init__.py @@ -913,10 +913,10 @@ def requires_galaxy_python_environment(self): if self.tool_type not in ["default", "manage_data", "interactive", "data_source"]: return True - if self.tool_type == "manage_data" and self.profile < 18.09: + if self.tool_type == "manage_data" and Version(str(self.profile)) < Version("18.09"): return True - if self.tool_type == "data_source" and self.profile < 21.09: + if self.tool_type == "data_source" and Version(str(self.profile)) < Version("21.09"): return True config = self.app.config @@ -1019,7 +1019,7 @@ def parse(self, tool_source: ToolSource, guid=None, dynamic=False): self.python_template_version = tool_source.parse_python_template_version() if self.python_template_version is None: # If python_template_version not specified we assume tools with profile versions >= 19.05 are python 3 ready - if self.profile >= 19.05: + if profile >= Version("19.05"): self.python_template_version = Version("3.5") else: self.python_template_version = Version("2.7") @@ -1033,7 +1033,7 @@ def parse(self, tool_source: ToolSource, guid=None, dynamic=False): self.version = tool_source.parse_version() if not self.version: - if self.profile < 16.04: + if profile < Version("16.04"): # For backward compatibility, some tools may not have versions yet. self.version = "1.0.0" else: diff --git a/lib/galaxy/tools/actions/__init__.py b/lib/galaxy/tools/actions/__init__.py index cee8b06015d1..54d71b35d995 100644 --- a/lib/galaxy/tools/actions/__init__.py +++ b/lib/galaxy/tools/actions/__init__.py @@ -14,6 +14,8 @@ Union, ) +from packaging.version import Version + from galaxy import model from galaxy.exceptions import ItemAccessibilityException from galaxy.job_execution.actions.post import ActionBox @@ -417,7 +419,7 @@ def execute( # format='input" previously would give you a random extension from # the input extensions, now it should just give "input" as the output # format. - input_ext = "data" if tool.profile < 16.04 else "input" + input_ext = "data" if Version(str(tool.profile)) < Version("16.04") else "input" input_dbkey = incoming.get("dbkey", "?") for name, data in reversed(list(inp_data.items())): if not data: @@ -429,7 +431,7 @@ def execute( data = data.to_history_dataset_association(None) inp_data[name] = data - if tool.profile < 16.04: + if Version(str(tool.profile)) < Version("16.04"): input_ext = data.ext if data.dbkey not in [None, "?"]: diff --git a/lib/galaxy/tools/evaluation.py b/lib/galaxy/tools/evaluation.py index d06af3b01d53..a1673450f5f3 100644 --- a/lib/galaxy/tools/evaluation.py +++ b/lib/galaxy/tools/evaluation.py @@ -15,6 +15,8 @@ Union, ) +from packaging.version import Version + from galaxy import model from galaxy.authnz.util import provider_name_to_backend from galaxy.job_execution.compute_environment import ComputeEnvironment @@ -729,7 +731,7 @@ def _build_param_file(self): param_dict = self.param_dict directory = self.local_working_directory command = self.tool.command - if self.tool.profile < 16.04 and command and "$param_file" in command: + if Version(str(self.tool.profile)) < Version("16.04") and command and "$param_file" in command: with tempfile.NamedTemporaryFile(mode="w", dir=directory, delete=False) as param: for key, value in param_dict.items(): # parameters can be strings or lists of strings, coerce to list diff --git a/lib/galaxy/tools/execute.py b/lib/galaxy/tools/execute.py index 26d29598c740..7c0d8d87701c 100644 --- a/lib/galaxy/tools/execute.py +++ b/lib/galaxy/tools/execute.py @@ -17,6 +17,7 @@ ) from boltons.iterutils import remap +from packaging.version import Version from galaxy import model from galaxy.exceptions import ToolInputsNotOKException @@ -310,7 +311,7 @@ def output_name(self, trans, history, params, output): return output_collection_name def sliced_input_collection_structure(self, input_name): - unqualified_recurse = self.tool.profile < 18.09 and "|" not in input_name + unqualified_recurse = Version(str(self.tool.profile)) < Version("18.09") and "|" not in input_name def find_collection(input_dict, input_name): for key, value in input_dict.items(): diff --git a/lib/galaxy/tools/parameters/basic.py b/lib/galaxy/tools/parameters/basic.py index ef6a7a19613c..327f3907862c 100644 --- a/lib/galaxy/tools/parameters/basic.py +++ b/lib/galaxy/tools/parameters/basic.py @@ -19,6 +19,7 @@ Union, ) +from packaging.version import Version from webob.compat import cgi_FieldStorage from galaxy import util @@ -594,7 +595,7 @@ def __init__(self, tool, input_source): super().__init__(tool, input_source) truevalue = input_source.get("truevalue", "true") falsevalue = input_source.get("falsevalue", "false") - if tool and tool.profile >= 23.1: + if tool and Version(str(tool.profile)) >= Version("23.1"): if truevalue == falsevalue: raise ParameterValueError("Cannot set true and false to the same value", self.name) if truevalue.lower() == "false": @@ -1022,7 +1023,7 @@ def from_json(self, value, trans, other_values=None, require_legal_value=True): "an invalid option (None) was selected, please verify", self.name, None, is_dynamic=self.is_dynamic ) elif not legal_values: - if self.optional and self.tool.profile < 18.09: + if self.optional and Version(str(self.tool.profile)) < Version("18.09"): # Covers optional parameters with default values that reference other optional parameters. # These will have a value but no legal_values. # See https://github.com/galaxyproject/tools-iuc/pull/1842#issuecomment-394083768 for context. diff --git a/lib/galaxy/tools/wrappers.py b/lib/galaxy/tools/wrappers.py index 9e59536c6529..7062cc91b602 100644 --- a/lib/galaxy/tools/wrappers.py +++ b/lib/galaxy/tools/wrappers.py @@ -19,6 +19,8 @@ Union, ) +from packaging.version import Version + from galaxy.model import ( DatasetCollection, DatasetCollectionElement, @@ -128,7 +130,7 @@ def __init__( and input.type == "text" and input.optional and input.optionality_inferred - and (profile is None or profile < 23.0) + and (profile is None or Version(str(profile)) < Version("23.0")) ): # Tools with old profile versions may treat an optional text parameter as `""` value = ""