details: http://www.bx.psu.edu/hg/galaxy/rev/a357369bd0a2 changeset: 3288:a357369bd0a2 user: James Taylor <james@jamestaylor.org> date: Wed Jan 27 16:51:24 2010 -0500 description: Better handling of missing tool parameters in workflows. Missing conditionals and repeats should be handled. Running workflows with missing params is now possible. Editing and running both display details of all parameter changes that were made diffstat: lib/galaxy/tools/__init__.py | 7 +++---- lib/galaxy/tools/parameters/grouping.py | 13 +++++++++---- lib/galaxy/web/controllers/workflow.py | 26 +++++++++++++++++++++----- templates/workflow/editor.mako | 8 ++++++-- templates/workflow/run.mako | 11 +++++++++++ 5 files changed, 50 insertions(+), 15 deletions(-) diffs (194 lines): diff -r 0126990119e9 -r a357369bd0a2 lib/galaxy/tools/__init__.py --- a/lib/galaxy/tools/__init__.py Wed Jan 27 16:33:49 2010 -0500 +++ b/lib/galaxy/tools/__init__.py Wed Jan 27 16:51:24 2010 -0500 @@ -1068,7 +1068,6 @@ def params_from_strings( self, params, app, ignore_errors=False ): return params_from_strings( self.inputs, params, app, ignore_errors ) - def check_and_update_param_values( self, values, trans ): """ @@ -1076,7 +1075,7 @@ values where neccesary. This could be called after loading values from a database in case new parameters have been added. """ - messages = [] + messages = {} self.check_and_update_param_values_helper( self.inputs, values, trans, messages ) return messages @@ -1088,8 +1087,8 @@ for input in inputs.itervalues(): # No value, insert the default if input.name not in values: - messages.append( prefix + input.label ) - values[input.name] = input.get_initial_value( trans, context ) + messages[ input.name ] = "No value found for '%s%s', used default" % ( prefix, input.label ) + values[ input.name ] = input.get_initial_value( trans, context ) # Value, visit recursively as usual else: if isinstance( input, Repeat ): diff -r 0126990119e9 -r a357369bd0a2 lib/galaxy/tools/parameters/grouping.py --- a/lib/galaxy/tools/parameters/grouping.py Wed Jan 27 16:33:49 2010 -0500 +++ b/lib/galaxy/tools/parameters/grouping.py Wed Jan 27 16:51:24 2010 -0500 @@ -47,6 +47,8 @@ return self.title else: return self.title + "s" + def label( self ): + return "Repeat (%s)" % self.title def value_to_basic( self, value, app ): rval = [] for d in value: @@ -333,6 +335,9 @@ self.cases = [] self.value_ref = None self.value_ref_in_group = True #When our test_param is not part of the conditional Group, this is False + @property + def label( self ): + return "Conditional (%s)" % self.name def get_current_case( self, value, trans ): # Convert value to user representation str_value = self.test_param.filter_value( value, trans ) @@ -354,10 +359,10 @@ rval[ self.test_param.name ] = self.test_param.value_from_basic( value[ self.test_param.name ], app, ignore_errors ) for input in self.cases[current_case].inputs.itervalues(): if ignore_errors and input.name not in value: - #two options here, either try to use unvalidated None or use initial==default value - #using unvalidated values here will cause, i.e., integer fields within groupings to be filled in workflow building mode like '<galaxy.tools.parameters.basic.UnvalidatedValue object at 0x981818c>' - #we will go with using the default value - rval[ input.name ] = input.get_initial_value( None, value ) #use default value + # If we do not have a value, and are ignoring errors, we simply + # do nothing. There will be no value for the parameter in the + # conditional's values dictionary. + pass else: rval[ input.name ] = input.value_from_basic( value[ input.name ], app, ignore_errors ) return rval diff -r 0126990119e9 -r a357369bd0a2 lib/galaxy/web/controllers/workflow.py --- a/lib/galaxy/web/controllers/workflow.py Wed Jan 27 16:33:49 2010 -0500 +++ b/lib/galaxy/web/controllers/workflow.py Wed Jan 27 16:51:24 2010 -0500 @@ -474,7 +474,9 @@ # Fix any missing parameters upgrade_message = module.check_and_update_state() if upgrade_message: - data['upgrade_messages'][step.order_index] = upgrade_message + # FIXME: Frontend should be able to handle workflow messages + # as a dictionary not just the values + data['upgrade_messages'][step.order_index] = upgrade_message.values() # Pack attributes into plain dictionary step_dict = { 'id': step.order_index, @@ -706,6 +708,8 @@ error( "Workflow cannot be run because of validation errors in some steps" ) # Build the state for each step errors = {} + has_upgrade_messages = False + has_errors = False if kwargs: # If kwargs were provided, the states for each step should have # been POSTed @@ -720,6 +724,10 @@ 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 ) @@ -761,18 +769,24 @@ workflow=stored, outputs=outputs ) else: + # Prepare each step for step in workflow.steps: + # Contruct modules if step.type == 'tool' or step.type is None: # Restore the tool state for the step - module = module_factory.from_workflow_step( trans, 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) - module.add_dummy_datasets( connections=step.input_connections ) + step.module.add_dummy_datasets( connections=step.input_connections ) # Store state with the step - step.module = module - step.state = module.state + step.state = step.module.state # Error dict if step.tool_errors: + has_errors = True errors[step.id] = step.tool_errors else: ## Non-tool specific stuff? @@ -785,6 +799,7 @@ "workflow/run.mako", steps=workflow.steps, workflow=stored, + has_upgrade_messages=has_upgrade_messages, errors=errors, incoming=kwargs ) @@ -978,3 +993,4 @@ cleanup( prefix, input.cases[current_case].inputs, group_values ) cleanup( "", inputs, values ) return associations + \ No newline at end of file diff -r 0126990119e9 -r a357369bd0a2 templates/workflow/editor.mako --- a/templates/workflow/editor.mako Wed Jan 27 16:33:49 2010 -0500 +++ b/templates/workflow/editor.mako Wed Jan 27 16:51:24 2010 -0500 @@ -90,11 +90,15 @@ // Determine if any parameters were 'upgraded' and provide message upgrade_message = "" $.each( data['upgrade_messages'], function( k, v ) { - upgrade_message += ( "<li>Step " + ( parseInt(k) + 1 ) + ": " + workflow.nodes[k].name + " -- " + v.join( ", " ) ); + upgrade_message += ( "<li>Step " + ( parseInt(k) + 1 ) + ": " + workflow.nodes[k].name + "<ul>"); + $.each( v, function( i, vv ) { + upgrade_message += "<li>" + vv +"</li>"; + }); + upgrade_message += "</ul></li>"; }); if ( upgrade_message ) { show_modal( "Workflow loaded with changes", - "Values were not found for the following parameters (possibly a result of tool upgrades), <br/> default values have been used. Please review the following parameters and then save.<ul>" + upgrade_message + "</ul>", + "Problems were encountered loading this workflow (possibly a result of tool upgrades). Please review the following parameters and then save.<ul>" + upgrade_message + "</ul>", { "Continue" : hide_modal } ); } else { hide_modal(); diff -r 0126990119e9 -r a357369bd0a2 templates/workflow/run.mako --- a/templates/workflow/run.mako Wed Jan 27 16:33:49 2010 -0500 +++ b/templates/workflow/run.mako Wed Jan 27 16:51:24 2010 -0500 @@ -104,6 +104,9 @@ ${param.value_to_display_text( value, app )} %endif </div> + %if step.upgrade_messages and param.name in step.upgrade_messages: + <div class="warningmark">${step.upgrade_messages[param.name]}</div> + %endif %if error_dict.has_key( param.name ): <div style="color: red; font-weight: bold; padding-top: 1px; padding-bottom: 3px;"> <div style="width: 300px;"><img style="vertical-align: middle;" src="${h.url_for('/static/style/error_small.png')}"> <span style="vertical-align: middle;">${error_dict[param.name]}</span></div> @@ -115,6 +118,14 @@ <h2>Running workflow "${workflow.name}"</h2> +%if has_upgrade_messages: +<div class="warningmessage"> + Problems were encourered when loading this workflow, likely due to tool + version changes. Missing parameter values have been replaced with default. + Please review the parameter values below. +</div> +%endif + <form id="tool_form" name="tool_form" method="POST"> ## <input type="hidden" name="workflow_name" value="${workflow.name | h}" /> %for i, step in enumerate( steps ):