diff --git a/lib/galaxy/managers/workflows.py b/lib/galaxy/managers/workflows.py index 2c14748468d..caed4b979c5 100644 --- a/lib/galaxy/managers/workflows.py +++ b/lib/galaxy/managers/workflows.py @@ -617,7 +617,7 @@ class WorkflowContentsManager(UsesAnnotations): continue if step.upgrade_messages: has_upgrade_messages = True - if step.type == 'tool' or step.type is None: + if step.type in ('tool', 'subworkflow', None): if step.module.version_changes: step_version_changes.extend(step.module.version_changes) step_errors = step.module.get_errors() @@ -805,7 +805,7 @@ class WorkflowContentsManager(UsesAnnotations): # Fix any missing parameters upgrade_message_dict = module.check_and_update_state() or {} if hasattr(module, "version_changes") and module.version_changes: - upgrade_message_dict[module.tool.name] = "\n".join(module.version_changes) + upgrade_message_dict[module.get_name()] = "\n".join(module.version_changes) # Get user annotation. config_form = module.get_config_form(step=step) annotation_str = self.get_item_annotation_str(trans.sa_session, trans.user, step) or '' diff --git a/lib/galaxy/tools/toolbox/base.py b/lib/galaxy/tools/toolbox/base.py index 6ab39d1f6b8..262593afc9e 100644 --- a/lib/galaxy/tools/toolbox/base.py +++ b/lib/galaxy/tools/toolbox/base.py @@ -761,21 +761,6 @@ class AbstractToolBox(Dictifiable, ManagesIntegratedToolPanelMixin): return True return False - def get_tool_id(self, tool_id): - """ Take a tool id - potentially from a different Galaxy instance or that - is no longer loaded - and find the closest match to the currently loaded - tools (using get_tool for inexact matches which currently returns the oldest - tool shed installed tool with the same short id). - """ - if tool_id not in self._tools_by_id: - tool = self.get_tool(tool_id) - if tool: - tool_id = tool.id - else: - tool_id = None - # else exact match - leave unmodified. - return tool_id - def get_loaded_tools_by_lineage(self, tool_id): """Get all loaded tools associated by lineage to the tool whose id is tool_id.""" tool_lineage = self._lineage_map.get(tool_id) diff --git a/lib/galaxy/workflow/modules.py b/lib/galaxy/workflow/modules.py index 8400f42114b..2463fcf1d02 100644 --- a/lib/galaxy/workflow/modules.py +++ b/lib/galaxy/workflow/modules.py @@ -398,6 +398,7 @@ class SubWorkflowModule(WorkflowModule): # - Second pass actually turn RuntimeInputs into inputs if possible. type = "subworkflow" name = "Subworkflow" + _modules = None @classmethod def from_dict(Class, trans, d, **kwds): @@ -455,7 +456,21 @@ class SubWorkflowModule(WorkflowModule): return inputs def get_modules(self): - return [module_factory.from_workflow_step(self.trans, step) for step in self.subworkflow.steps] + if self._modules is None: + self._modules = [module_factory.from_workflow_step(self.trans, step) for step in self.subworkflow.steps] + return self._modules + + @property + def version_changes(self): + version_changes = [] + for m in self.get_modules(): + if hasattr(m, 'version_changes'): + version_changes.extend(m.version_changes) + return version_changes + + def check_and_update_state(self): + states = (m.check_and_update_state() for m in self.get_modules()) + return [upgrade_message for upgrade_message in states if upgrade_message] or None def get_errors(self, **kwargs): errors = (module.get_errors(include_tool_id=True) for module in self.get_modules()) @@ -1244,13 +1259,15 @@ class ToolModule(WorkflowModule): def __init__(self, trans, tool_id, tool_version=None, exact_tools=True, tool_uuid=None, **kwds): super().__init__(trans, content_id=tool_id, **kwds) self.tool_id = tool_id - self.tool_version = str(tool_version) + self.tool_version = str(tool_version) if tool_version else None self.tool_uuid = tool_uuid self.tool = trans.app.toolbox.get_tool(tool_id, tool_version=tool_version, exact=exact_tools, tool_uuid=tool_uuid) if self.tool: - if tool_version and exact_tools and str(self.tool.version) != tool_version: - safe_version = WORKFLOW_SAFE_TOOL_VERSION_UPDATES.get(tool_id) - if safe_version and safe_version.current_version >= packaging.version.parse(tool_version) >= safe_version.min_version: + current_tool_id = self.tool.id + current_tool_version = str(self.tool.version) + if tool_version and exact_tools and self.tool_version != current_tool_version: + safe_version = WORKFLOW_SAFE_TOOL_VERSION_UPDATES.get(current_tool_id) + if safe_version and safe_version.current_version >= packaging.version.parse(current_tool_id) >= safe_version.min_version: self.tool = trans.app.toolbox.get_tool(tool_id, tool_version=tool_version, exact=False, tool_uuid=tool_uuid) else: log.info(f"Exact tool specified during workflow module creation for [{tool_id}] but couldn't find correct version [{tool_version}].") @@ -1299,22 +1316,19 @@ class ToolModule(WorkflowModule): @classmethod def from_workflow_step(Class, trans, step, **kwds): - if step.tool_id is not None: - tool_id = trans.app.toolbox.get_tool_id(step.tool_id) or step.tool_id - else: - tool_id = None tool_version = step.tool_version tool_uuid = step.tool_uuid - module = super().from_workflow_step(trans, step, tool_id=tool_id, tool_version=tool_version, tool_uuid=tool_uuid, **kwds) + kwds['exact_tools'] = False + module = super().from_workflow_step(trans, step, tool_id=step.tool_id, tool_version=tool_version, tool_uuid=tool_uuid, **kwds) module.workflow_outputs = step.workflow_outputs module.post_job_actions = {} for pja in step.post_job_actions: module.post_job_actions[pja.action_type] = pja if module.tool: message = "" - if step.tool_id and step.tool_id != module.tool_id: # This means the exact version of the tool is not installed. We inform the user. + if step.tool_id and step.tool_id != module.tool.id or step.tool_version and step.tool_version != module.tool.version: # This means the exact version of the tool is not installed. We inform the user. old_tool_shed = step.tool_id.split("/repos/")[0] - if old_tool_shed not in tool_id: # Only display the following warning if the tool comes from a different tool shed + if old_tool_shed not in module.tool.id: # Only display the following warning if the tool comes from a different tool shed old_tool_shed_url = get_tool_shed_url_from_tool_shed_registry(trans.app, old_tool_shed) if not old_tool_shed_url: # a tool from a different tool_shed has been found, but the original tool shed has been deactivated old_tool_shed_url = "http://" + old_tool_shed # let's just assume it's either http, or a http is forwarded to https. @@ -1324,12 +1338,12 @@ class ToolModule(WorkflowModule): message += f"The tool \'{module.tool.name}\', version {tool_version} by the owner {module.tool.repository_owner} installed from {old_tool_shed_url} is not available. " message += f"A derivation of this tool installed from {new_tool_shed_url} will be used instead. " if step.tool_version and (step.tool_version != module.tool.version): - message += f"Using version '{module.tool.version}' instead of version '{step.tool_version}' specified in this workflow. " + message += f"Using version '{module.tool.version}' instead of version '{step.tool_version}' specified in this workflow. " if message: log.debug(message) module.version_changes.append(message) else: - log.warning("The tool '%s' is missing. Cannot build workflow module." % tool_id) + log.warning("The tool '%s' is missing. Cannot build workflow module." % step.tool_id) return module # ---- Saving in various forms ------------------------------------------