Merge branch 'release_22.05' into dev

This commit is contained in:
Nicola Soranzo
2022-11-07 23:12:32 +00:00
6 changed files with 86 additions and 13 deletions
+17 -6
View File
@@ -581,6 +581,7 @@ class WorkflowContentsManager(UsesAnnotations):
source=None,
add_to_menu=False,
hidden=False,
is_subworkflow=False,
):
data = raw_workflow_description.as_dict
# Put parameters in workflow mode
@@ -600,6 +601,7 @@ class WorkflowContentsManager(UsesAnnotations):
raw_workflow_description,
workflow_create_options,
name=name,
is_subworkflow=is_subworkflow,
)
if "uuid" in data:
workflow.uuid = data["uuid"]
@@ -689,7 +691,7 @@ class WorkflowContentsManager(UsesAnnotations):
return workflow, errors
def _workflow_from_raw_description(
self, trans, raw_workflow_description, workflow_state_resolution_options, name, **kwds
self, trans, raw_workflow_description, workflow_state_resolution_options, name, is_subworkflow=False, **kwds
):
# don't commit the workflow or attach its part to the sa session - just build a
# a transient model to operate on or render.
@@ -764,8 +766,12 @@ class WorkflowContentsManager(UsesAnnotations):
# Second pass to deal with connections between steps
self.__connect_workflow_steps(steps, steps_by_external_id, dry_run)
# Order the steps if possible
attach_ordered_steps(workflow, steps)
workflow.has_cycles = True
workflow.steps = steps
# we can't reorder subworkflows, as step connections would become invalid
if not is_subworkflow:
# Order the steps if possible
attach_ordered_steps(workflow)
return workflow, missing_tool_tups
@@ -857,7 +863,7 @@ class WorkflowContentsManager(UsesAnnotations):
"""
if len(workflow.steps) == 0:
raise exceptions.MessageException("Workflow cannot be run because it does not have any steps.")
if attach_ordered_steps(workflow, workflow.steps):
if attach_ordered_steps(workflow):
raise exceptions.MessageException("Workflow cannot be run because it contains cycles.")
trans.workflow_building_mode = workflow_building_modes.USE_HISTORY
module_injector = WorkflowModuleInjector(trans)
@@ -950,7 +956,7 @@ class WorkflowContentsManager(UsesAnnotations):
"""
if len(workflow.steps) == 0:
raise exceptions.MessageException("Workflow cannot be run because it does not have any steps.")
if attach_ordered_steps(workflow, workflow.steps):
if attach_ordered_steps(workflow):
raise exceptions.MessageException("Workflow cannot be run because it contains cycles.")
# Ensure that the user has a history
@@ -1652,6 +1658,7 @@ class WorkflowContentsManager(UsesAnnotations):
steps.append(step)
external_id = step_dict["id"]
steps_by_external_id[external_id] = step
step.order_index = external_id
if "workflow_outputs" in step_dict:
workflow_outputs = step_dict["workflow_outputs"]
found_output_names = set()
@@ -1718,7 +1725,11 @@ class WorkflowContentsManager(UsesAnnotations):
def __build_embedded_subworkflow(self, trans, data, workflow_state_resolution_options):
raw_workflow_description = self.ensure_raw_description(data)
subworkflow = self.build_workflow_from_raw_description(
trans, raw_workflow_description, workflow_state_resolution_options, hidden=True
trans,
raw_workflow_description,
workflow_state_resolution_options,
hidden=True,
is_subworkflow=True,
).workflow
return subworkflow
+2 -1
View File
@@ -52,8 +52,9 @@ def extract_workflow(
# Workflow to populate
workflow = model.Workflow()
workflow.name = workflow_name
workflow.steps = steps
# Order the steps if possible
attach_ordered_steps(workflow, steps)
attach_ordered_steps(workflow)
# And let's try to set up some reasonable locations on the canvas
# (these are pretty arbitrary values)
levorder = order_workflow_steps_with_levels(steps)
+4 -2
View File
@@ -10,11 +10,11 @@ from galaxy.util.topsort import (
)
def attach_ordered_steps(workflow, steps):
def attach_ordered_steps(workflow):
"""Attempt to topologically order steps and attach to workflow. If this
fails - the workflow contains cycles so it mark it as such.
"""
ordered_steps = order_workflow_steps(steps)
ordered_steps = order_workflow_steps(workflow.steps)
workflow.has_cycles = True
if ordered_steps:
workflow.has_cycles = False
@@ -30,6 +30,8 @@ def order_workflow_steps(steps):
"""
position_data_available = bool(steps)
for step in steps:
if step.subworkflow:
attach_ordered_steps(step.subworkflow)
if not step.position or "left" not in step.position or "top" not in step.position:
position_data_available = False
if position_data_available:
+59
View File
@@ -5059,6 +5059,65 @@ steps:
run_workflow_response = self.workflow_populator.invoke_workflow_raw(uploaded_workflow_id, workflow_request)
return run_workflow_response, history_id
def test_subworkflow_import_order_maintained(self):
summary = self._run_workflow(
"""
class: GalaxyWorkflow
inputs:
outer_input_1:
type: int
default: 1
position:
left: 0
top: 0
outer_input_2:
type: int
default: 2
position:
left: 100
top: 0
steps:
nested_workflow:
in:
inner_input_1: outer_input_1
inner_input_2: outer_input_2
run:
class: GalaxyWorkflow
inputs:
inner_input_1:
type: int
position:
left: 100
top: 0
inner_input_2:
type: int
position:
left: 0
top: 0
steps: []
outputs:
- label: nested_out_1
outputSource: inner_input_1/output
- label: nested_out_2
outputSource: inner_input_2/output
outputs:
- label: out_1
outputSource: nested_workflow/nested_out_1
- label: out_2
outputSource: nested_workflow/nested_out_2
""",
assert_ok=False,
wait=False,
)
self.workflow_populator.wait_for_invocation(summary.workflow_id, summary.invocation_id)
self.workflow_populator.wait_for_history_workflows(
summary.history_id, assert_ok=False, expected_invocation_count=2
)
invocation = self.workflow_populator.get_invocation(summary.invocation_id)
output_values = invocation["output_values"]
assert output_values["out_1"] == 1
assert output_values["out_2"] == 2
@skip_without_tool("random_lines1")
def test_run_replace_params_by_steps(self):
workflow_request, history_id, workflow_id, steps = self._setup_random_x2_workflow_steps(
+3 -3
View File
@@ -27,14 +27,14 @@ migrate_repository = repository.Repository(migrate_repository_directory)
def create_or_verify_database(url, engine_options=None):
"""
Check that the database is use-able, possibly creating it if empty (this is
Check that the database is useable, possibly creating it if empty (this is
the only time we automatically create tables, otherwise we force the
user to do it using the management script so they can create backups).
1) Empty database --> initialize with latest version and return
2) Database older than migration support --> fail and require manual update
3) Database at state where migrate support introduced --> add version control information but make no changes (might still require manual update)
4) Database versioned but out of date --> fail with informative message, user must run "sh manage_db.sh upgrade"
4) Database versioned but out of date --> fail with informative message, user must run "sh manage_toolshed_db.sh upgrade"
"""
engine_options = engine_options or {}
@@ -81,7 +81,7 @@ def create_or_verify_database(url, engine_options=None):
migrate_repository.versions.latest,
)
exception_msg += "Back up your database and then migrate the schema by running the following from your Galaxy installation directory:"
exception_msg += "\n\nsh manage_db.sh upgrade tool_shed\n"
exception_msg += "\n\nsh manage_toolshed_db.sh upgrade\n"
raise Exception(exception_msg)
else:
log.info("At database version %d" % db_schema.version)
+1 -1
View File
@@ -77,7 +77,7 @@ from markupsafe import escape
item_tag_names = []
for ta in item_tags:
item_tag_names.append(escape(ta.tag.name))
item_tag_names.append(escape(f"#{ta.value}" if ta.value else ta.tag.name))
%>
<div id="tags-${tagged_item_id}"></div>