1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/3e00d002e7ba/
Changeset: 3e00d002e7ba
User: jmchilton
Date: 2014-08-27 16:49:15
Summary: Reduce workflow step state and module population duplication.
Move all operations prior to workflow invocation (and a few other places state and modules
are used) relating to populating the non-persistent attributes of `WorkflowStep`s (e.g.
module, state, upgrade_messages, and input_connections_by_name) into a single function on
a new class.
This should fix a couple of small errors as well - input_connections_by_name was being
mis-calculated in a few places (though potentially never used down those roads) and some
error handling code in the workflow editor template was expecting step.module to be
populated with something (even if None) and it was not always.
Affected #: 4 files
diff -r 7c566a68d2d07375c53006191671dfed04332f55 -r
3e00d002e7ba1fdd9d914bcd68589aad5c1e21ff lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -26,7 +26,7 @@
from galaxy.web import error, url_for
from galaxy.web.form_builder import AddressField, CheckboxField, SelectField, TextArea,
TextField
from galaxy.web.form_builder import build_select_field, HistoryField, PasswordField,
WorkflowField, WorkflowMappingField
-from galaxy.workflow.modules import module_factory
+from galaxy.workflow.modules import module_factory, WorkflowModuleInjector,
MissingToolException
from galaxy.model.orm import eagerload, eagerload_all, desc
from galaxy.security.validate_user_input import validate_publicname
from galaxy.util.sanitize_html import sanitize_html
@@ -1625,30 +1625,13 @@
def get_stored_workflow_steps( self, trans, stored_workflow ):
""" Restores states for a stored workflow's steps.
"""
+ module_injector = WorkflowModuleInjector( trans )
for step in stored_workflow.latest_workflow.steps:
- step.upgrade_messages = {}
- if step.type == 'tool' or step.type is None:
- # Restore the tool state for the step
- module = module_factory.from_workflow_step( trans, step )
- if module:
- #Check if tool was upgraded
- step.upgrade_messages = module.check_and_update_state()
- # Any connected input needs to have value DummyDataset (these
- # are not persisted so we need to do it every time)
- module.add_dummy_datasets( connections=step.input_connections )
- # Store state with the step
- step.module = module
- step.state = module.state
- else:
- step.upgrade_messages = "Unknown Tool ID"
- step.module = None
- step.state = None
- else:
- ## Non-tool specific stuff?
- step.module = module_factory.from_workflow_step( trans, step )
- step.state = step.module.get_runtime_state()
- # Connections by input name
- step.input_connections_by_name = dict( ( conn.input_name, conn ) for conn in
step.input_connections )
+ try:
+ module_injector.inject( step )
+ except MissingToolException:
+ # Now upgrade_messages is a string instead of a dict, why?
+ step.upgrade_messages = "Unknown Tool ID"
def _import_shared_workflow( self, trans, stored):
""" """
diff -r 7c566a68d2d07375c53006191671dfed04332f55 -r
3e00d002e7ba1fdd9d914bcd68589aad5c1e21ff
lib/galaxy/webapps/galaxy/controllers/workflow.py
--- a/lib/galaxy/webapps/galaxy/controllers/workflow.py
+++ b/lib/galaxy/webapps/galaxy/controllers/workflow.py
@@ -24,6 +24,8 @@
from galaxy.web.framework import form
from galaxy.web.framework.helpers import grids, time_ago
from galaxy.web.framework.helpers import to_unicode
+from galaxy.workflow.modules import WorkflowModuleInjector
+from galaxy.workflow.modules import MissingToolException
from galaxy.workflow.modules import module_factory, is_tool_module_type
from galaxy.workflow.run import invoke
from galaxy.workflow.run import WorkflowRunConfig
@@ -1269,6 +1271,7 @@
error("That history does not exist.")
try: # use a try/finally block to restore the user's current history
default_target_history = trans.get_history()
+ module_injector = WorkflowModuleInjector( trans )
if kwargs:
# If kwargs were provided, the states for each step should have
# been POSTed
@@ -1276,45 +1279,15 @@
invocations = []
for (kwargs, multi_input_keys) in _expand_multiple_inputs(kwargs):
for step in workflow.steps:
- step.upgrade_messages = {}
- # Connections by input name
- input_connections_by_name = {}
- for conn in step.input_connections:
- input_name = conn.input_name
- if not input_name in input_connections_by_name:
- input_connections_by_name[input_name] = []
- input_connections_by_name[input_name].append(conn)
- step.input_connections_by_name = input_connections_by_name
# Extract just the arguments for this step by prefix
p = "%s|" % step.id
l = len(p)
step_args = dict( ( k[l:], v ) for ( k, v ) in kwargs.iteritems()
if k.startswith( p ) )
- step_errors = None
- if step.type == 'tool' or step.type is None:
- module = module_factory.from_workflow_step( trans, step )
- # Fix any missing parameters
- step.upgrade_messages = module.check_and_update_state()
- if step.upgrade_messages:
- has_upgrade_messages = True
- # Any connected input needs to have value DummyDataset
(these
- # are not persisted so we need to do it every time)
- module.add_dummy_datasets( connections=step.input_connections
)
- # Get the tool
- tool = module.tool
- # Get the state
- step.state = state = module.state
- # Get old errors
- old_errors = state.inputs.pop( "__errors__", {} )
- # Update the state
- step_errors = tool.update_state( trans, tool.inputs,
step.state.inputs, step_args,
- update_only=True,
old_errors=old_errors )
- else:
- # Fix this for multiple inputs
- module = step.module = module_factory.from_workflow_step(
trans, step )
- state = step.state = module.decode_runtime_state( trans,
step_args.pop( "tool_state" ) )
- step_errors = module.update_runtime_state( trans, state,
step_args )
+ step_errors = module_injector.inject( step, step_args )
+ if step.upgrade_messages:
+ has_upgrade_messages = True
if step_errors:
- errors[step.id] = state.inputs["__errors__"] =
step_errors
+ errors[step.id] = step.state.inputs["__errors__"] =
step_errors
if 'run_workflow' in kwargs and not errors:
new_history = None
if 'new_history' in kwargs:
@@ -1361,36 +1334,20 @@
# Prepare each step
missing_tools = []
for step in workflow.steps:
- step.upgrade_messages = {}
- # Contruct modules
+ try:
+ module_injector.inject( step )
+ except MissingToolException:
+ if step.tool_id not in missing_tools:
+ missing_tools.append(step.tool_id)
+ continue
+ if step.upgrade_messages:
+ has_upgrade_messages = True
if step.type == 'tool' or step.type is None:
- # Restore the tool state for the step
- step.module = module_factory.from_workflow_step( trans, step )
- if not step.module:
- if step.tool_id not in missing_tools:
- missing_tools.append(step.tool_id)
- continue
- step.upgrade_messages = step.module.check_and_update_state()
- if step.upgrade_messages:
- has_upgrade_messages = True
- if step.type == 'tool' and step.module.version_changes:
+ if step.module.version_changes:
step_version_changes.extend(step.module.version_changes)
- # Any connected input needs to have value DummyDataset (these
- # are not persisted so we need to do it every time)
- step.module.add_dummy_datasets(
connections=step.input_connections )
- # Store state with the step
- step.state = step.module.state
# Error dict
if step.tool_errors:
- # has_errors is never used.
- # has_errors = True
errors[step.id] = step.tool_errors
- else:
- ## Non-tool specific stuff?
- step.module = module_factory.from_workflow_step( trans, step )
- step.state = step.module.get_runtime_state()
- # Connections by input name
- step.input_connections_by_name = dict( ( conn.input_name, conn ) for
conn in step.input_connections )
if missing_tools:
stored.annotation = self.get_item_annotation_str( trans.sa_session,
trans.user, stored )
return trans.fill_template(
@@ -1464,32 +1421,17 @@
trans.sa_session.add(m)
# Prepare each step
trans.sa_session.flush()
+ module_injector = WorkflowModuleInjector( trans )
for step in workflow.steps:
step.upgrade_messages = {}
# Contruct modules
+ module_injector.inject( step )
+ if step.upgrade_messages:
+ has_upgrade_messages = True
if step.type == 'tool' or step.type is None:
- # Restore the tool state for the step
- step.module = module_factory.from_workflow_step( trans, step )
- # Fix any missing parameters
- step.upgrade_messages = step.module.check_and_update_state()
- if step.upgrade_messages:
- has_upgrade_messages = True
- # Any connected input needs to have value DummyDataset (these
- # are not persisted so we need to do it every time)
- step.module.add_dummy_datasets( connections=step.input_connections )
- # Store state with the step
- step.state = step.module.state
# Error dict
if step.tool_errors:
- # has_errors is never used
- # has_errors = True
errors[step.id] = step.tool_errors
- else:
- ## Non-tool specific stuff?
- step.module = module_factory.from_workflow_step( trans, step )
- step.state = step.module.get_runtime_state()
- # Connections by input name
- step.input_connections_by_name = dict( ( conn.input_name, conn ) for conn in
step.input_connections )
# Render the form
return trans.fill_template(
"workflow/tag_outputs.mako",
diff -r 7c566a68d2d07375c53006191671dfed04332f55 -r
3e00d002e7ba1fdd9d914bcd68589aad5c1e21ff lib/galaxy/workflow/modules.py
--- a/lib/galaxy/workflow/modules.py
+++ b/lib/galaxy/workflow/modules.py
@@ -559,3 +559,81 @@
tool=ToolModule,
)
module_factory = WorkflowModuleFactory( module_types )
+
+
+class MissingToolException( Exception ):
+ """ WorkflowModuleInjector will raise this if the tool corresponding
to the
+ module is missing. """
+
+
+class WorkflowModuleInjector(object):
+ """ Injects workflow step objects from the ORM with appropriate module
and
+ module generated/influenced state. """
+
+ def __init__( self, trans ):
+ self.trans = trans
+
+ def inject( self, step, step_args=None ):
+ """ Pre-condition: `step` is an ORM object coming from the
database, if
+ supplied `step_args` is the representation of the inputs for that step
+ supplied via web form.
+
+ Post-condition: The supplied `step` has new non-persistent attributes
+ useful during workflow invocation. These include 'upgrade_messages',
+ 'state', 'input_connections_by_name', and 'module'.
+
+ If step_args is provided from a web form this is applied to generate
+ 'state' else it is just obtained from the database.
+ """
+ trans = self.trans
+
+ step_errors = None
+
+ step.upgrade_messages = {}
+
+ # Make connection information available on each step by input name.
+ input_connections_by_name = {}
+ for conn in step.input_connections:
+ input_name = conn.input_name
+ if not input_name in input_connections_by_name:
+ input_connections_by_name[input_name] = []
+ input_connections_by_name[input_name].append(conn)
+ step.input_connections_by_name = input_connections_by_name
+
+ # Populate module.
+ module = step.module = module_factory.from_workflow_step( trans, step )
+
+ # Calculating step errors and state depends on whether step is a tool step or
not.
+ if step.type == 'tool' or step.type is None:
+ if not module:
+ step.module = None
+ step.state = None
+ raise MissingToolException()
+
+ # Fix any missing parameters
+ step.upgrade_messages = module.check_and_update_state()
+
+ # Any connected input needs to have value DummyDataset (these
+ # are not persisted so we need to do it every time)
+ module.add_dummy_datasets( connections=step.input_connections )
+
+ state = module.state
+ step.state = state
+ if step_args is not None:
+ # Get the tool
+ tool = module.tool
+ # Get old errors
+ old_errors = state.inputs.pop( "__errors__", {} )
+ # Update the state
+ step_errors = tool.update_state( trans, tool.inputs, step.state.inputs,
step_args,
+ update_only=True, old_errors=old_errors
)
+
+ else:
+ if step_args:
+ # Fix this for multiple inputs
+ state = step.state = module.decode_runtime_state( trans, step_args.pop(
"tool_state" ) )
+ step_errors = module.update_runtime_state( trans, state, step_args )
+ else:
+ step.state = step.module.get_runtime_state()
+
+ return step_errors
diff -r 7c566a68d2d07375c53006191671dfed04332f55 -r
3e00d002e7ba1fdd9d914bcd68589aad5c1e21ff lib/galaxy/workflow/run.py
--- a/lib/galaxy/workflow/run.py
+++ b/lib/galaxy/workflow/run.py
@@ -229,24 +229,10 @@
def _populate_state( self ):
# Build the state for each step
+ module_injector = modules.WorkflowModuleInjector( self.trans )
for step in self.workflow.steps:
- step_errors = None
- input_connections_by_name = {}
- for conn in step.input_connections:
- input_name = conn.input_name
- if not input_name in input_connections_by_name:
- input_connections_by_name[input_name] = []
- input_connections_by_name[input_name].append(conn)
- step.input_connections_by_name = input_connections_by_name
-
+ step_errors = module_injector.inject( step )
if step.type == 'tool' or step.type is None:
- step.module = modules.module_factory.from_workflow_step( self.trans, step
)
- # Check for missing parameters
- step.upgrade_messages = step.module.check_and_update_state()
- # Any connected input needs to have value DummyDataset (these
- # are not persisted so we need to do it every time)
- step.module.add_dummy_datasets( connections=step.input_connections )
- step.state = step.module.state
_update_step_parameters( step, self.param_map )
if step.tool_errors:
message = "Workflow cannot be run because of validation errors
in some steps: %s" % step_errors
@@ -254,9 +240,6 @@
if step.upgrade_messages:
message = "Workflow cannot be run because of step upgrade
messages: %s" % step.upgrade_messages
raise exceptions.MessageException( message )
- else:
- step.module = modules.module_factory.from_workflow_step( self.trans, step
)
- step.state = step.module.get_runtime_state()
def _update_step_parameters(step, normalized_param_map):
Repository URL:
https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from
bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.