Merge pull request #3593 from guerler/unify_name_label

Introduce label and annotation attributes to subworkflows, fix annotation display, unify module form update handler
This commit is contained in:
John Chilton
2017-02-21 08:03:54 -05:00
committed by GitHub
25 changed files with 273 additions and 284 deletions
@@ -40,7 +40,7 @@ define( [ 'utils/utils', 'utils/deferred', 'mvc/ui/ui-misc', 'mvc/form/form-view
var self = this;
this.model.set( options );
this.model.set({
title : '<b>' + options.name + '</b> ' + options.description + ' (Galaxy Version ' + options.version + ')',
title : options.title || '<b>' + options.name + '</b> ' + options.description + ' (Galaxy Version ' + options.version + ')',
operations : !this.model.get( 'hide_operations' ) && this._operations(),
onchange : function() {
self.deferred.reset();
@@ -39,12 +39,18 @@ define([ 'utils/utils', 'utils/deferred', 'mvc/ui/ui-misc', 'mvc/form/form-view'
_.each( this.model.get( 'steps' ), function( step, i ) {
Galaxy.emit.debug( 'tool-form-composite::initialize()', i + ' : Preparing workflow step.' );
var icon = WorkflowIcons[ step.step_type ];
var title = parseInt( i + 1 ) + ': ' + ( step.step_label || step.step_name );
if ( step.annotation ) {
title += ' - ' + step.annotation;
}
if ( step.step_version ) {
title += ' (Galaxy Version ' + step.step_version + ')';
}
step = Utils.merge( {
index : i,
name : step.name,
title : _.escape( title ),
icon : icon || '',
help : null,
description : step.annotation && ' - ' + step.annotation || step.description,
citations : null,
collapsible : true,
collapsed : i > 0 && !self._isDataStep( step ),
@@ -300,7 +306,6 @@ define([ 'utils/utils', 'utils/deferred', 'mvc/ui/ui-misc', 'mvc/form/form-view'
var is_simple_input = ([ 'data_input', 'data_collection_input' ]).indexOf( step.step_type ) != -1;
_.each( step.inputs, function( input ) { input.flavor = 'module'; input.hide_label = is_simple_input; } );
form = new Form( Utils.merge({
title : '<b>' + step.name + '</b>',
onchange : function() { _.each( self.links[ step.index ], function( link ) { self._refreshStep( link ) } ) },
inputs : step.inputs && step.inputs.length > 0 ? step.inputs : [ { type: 'hidden', name: 'No options available.', ignore: null } ]
}, step ) );
@@ -38,6 +38,7 @@ define( [ 'utils/utils', 'mvc/tool/tool-form-base' ],
var current_state = {
tool_id : options.id,
tool_version : options.version,
type : 'tool',
inputs : $.extend( true, {}, form.data.create() )
}
Galaxy.emit.debug( 'tool-form-workflow::postchange()', 'Sending current state.', current_state );
@@ -46,8 +47,8 @@ define( [ 'utils/utils', 'mvc/tool/tool-form-base' ],
url : Galaxy.root + 'api/workflows/build_module',
data : current_state,
success : function( data ) {
form.update( data.tool_model );
form.errors( data.tool_model );
form.update( data.config_form );
form.errors( data.config_form );
// This hasn't modified the workflow, just returned
// module information for the tool to update the workflow
// state stored on the client with. User needs to save
@@ -670,54 +670,50 @@ define([
content.datatypes = this.datatypes;
form = new ToolForm.View( content );
} else {
if ( content.inputs && content.inputs.length > 0 ) {
content.inputs.unshift({
type : 'text',
name : '__label',
label : 'Label',
value : node.label,
help : 'Add a step label.',
onchange: function( new_label ) {
var duplicate = false;
for ( var i in self.workflow.nodes ) {
var n = self.workflow.nodes[ i ];
if ( n.label && n.label == new_label && n.id != node.id ) {
duplicate = true;
break;
}
content.inputs.unshift({
type : 'text',
name : '__label',
label : 'Label',
value : node.label,
help : 'Add a step label.',
onchange: function( new_label ) {
var duplicate = false;
for ( var i in self.workflow.nodes ) {
var n = self.workflow.nodes[ i ];
if ( n.label && n.label == new_label && n.id != node.id ) {
duplicate = true;
break;
}
var input_id = form.data.match( '__label' );
var input_element = form.element_list[ input_id ];
input_element.model.set( 'error_text', duplicate && 'Duplicate label. Please fix this before saving the workflow.' );
form.trigger( 'change' );
}
var input_id = form.data.match( '__label' );
var input_element = form.element_list[ input_id ];
input_element.model.set( 'error_text', duplicate && 'Duplicate label. Please fix this before saving the workflow.' );
form.trigger( 'change' );
}
});
content.inputs.push({
type : 'text',
name : '__annotation',
label : 'Annotation',
value : node.annotation,
area : true,
help : 'Add an annotation or notes to this step. Annotations are available when a workflow is viewed.'
});
content.onchange = function() {
Utils.request({
type : 'POST',
url : Galaxy.root + 'api/workflows/build_module',
data : {
id : node.id,
type : node.type,
content_id : node.content_id,
inputs : form.data.create()
},
success : function( data ) {
node.update_field_data( data );
}
});
content.inputs.push({
type : 'text',
name : '__annotation',
label : 'Annotation',
value : node.annotation,
area : true,
help : 'Add an annotation or notes to this step. Annotations are available when a workflow is viewed.'
});
content.onchange = function() {
Utils.request({
type : 'POST',
url : Galaxy.root + 'api/workflows/build_module',
data : {
id : node.id,
type : node.type,
inputs : form.data.create()
},
success : function( data ) {
node.update_field_data( data );
}
});
};
} else {
content.message = 'No inputs available for this module.';
content.message_status = 'info';
}
};
form = new Form( content );
}
$el.append( form.$el );
+8 -11
View File
@@ -370,10 +370,6 @@ class WorkflowContentsManager(UsesAnnotations):
step_models = []
for i, step in enumerate( workflow.steps ):
step_model = None
def step_title(step, default_name):
return "%d: %s" % (step.order_index + 1, step.label or default_name)
if step.type == 'tool':
incoming = {}
tool = trans.app.toolbox.get_tool( step.tool_id )
@@ -385,14 +381,15 @@ class WorkflowContentsManager(UsesAnnotations):
'output_name' : pja.output_name,
'action_arguments' : pja.action_arguments
} for pja in step.post_job_actions ]
step_model["name"] = step_title(step, step_model.get("name"))
else:
inputs = step.module.get_runtime_inputs( connections=step.output_connections )
step_model = {
'name' : step_title(step, step.module.name),
'inputs' : [ input.to_dict( trans ) for input in inputs.itervalues() ]
}
step_model[ 'step_type' ] = step.type
step_model[ 'step_label' ] = step.label
step_model[ 'step_name' ] = step.module.get_name()
step_model[ 'step_version' ] = step.module.get_version()
step_model[ 'step_index' ] = step.order_index
step_model[ 'output_connections' ] = [ {
'input_step_index' : step_order_indices.get( oc.input_step_id ),
@@ -452,6 +449,7 @@ class WorkflowContentsManager(UsesAnnotations):
step_dict = {
'id': step.order_index,
'type': module.type,
'label': module.label,
'content_id': module.get_content_id(),
'name': module.get_name(),
'tool_state': module.get_state(),
@@ -463,7 +461,6 @@ class WorkflowContentsManager(UsesAnnotations):
'annotation': annotation_str,
'post_job_actions': {},
'uuid': str(step.uuid) if step.uuid else None,
'label': step.label or None,
'workflow_outputs': []
}
# Connections
@@ -615,7 +612,7 @@ class WorkflowContentsManager(UsesAnnotations):
# Data inputs
input_dicts = []
step_state = module.state.inputs
step_state = module.state.inputs or {}
if "name" in step_state:
name = step_state.get( "name" )
input_dicts.append( { "name": name, "description": annotation_str } )
@@ -711,9 +708,9 @@ class WorkflowContentsManager(UsesAnnotations):
inputs = {}
for step in workflow.input_steps:
step_type = step.type
step_name = step.name
if step_name:
label = step_name
step_label = step.label or step.tool_inputs.get( 'name' )
if step_label:
label = step_label
elif step_type == "data_input":
label = "Input Dataset"
elif step_type == "data_collection_input":
-9
View File
@@ -34,7 +34,6 @@ from galaxy.util import (directory_hash_id, Params, ready_name_for_url,
from galaxy.util.bunch import Bunch
from galaxy.util.dictifiable import Dictifiable
from galaxy.util.hash_util import new_secure_hash
from galaxy.util.json import safe_loads
from galaxy.util.multi_byte import is_multi_byte
from galaxy.util.sanitize_html import sanitize_html
from galaxy.web.form_builder import (AddressField, CheckboxField, HistoryField,
@@ -3759,14 +3758,6 @@ class WorkflowStep( object ):
content_id = None
return content_id
@property
def name( self ):
state = self.tool_inputs
if state:
state = safe_loads( state )
identifier = state.get( 'name' )
return safe_loads( identifier )
@property
def input_connections_by_name(self):
if self._input_connections_by_name is None:
+3 -78
View File
@@ -46,6 +46,7 @@ from galaxy.tools.parameters import (
params_from_strings,
params_to_incoming,
params_to_strings,
populate_state,
visit_input_values
)
from galaxy.tools.parameters import output_collect
@@ -1238,7 +1239,7 @@ class Tool( object, Dictifiable ):
else:
# Update state for all inputs on the current page taking new
# values from `incoming`.
self.populate_state( request_context, self.inputs, expanded_incoming, params, errors )
populate_state( request_context, self.inputs, expanded_incoming, params, errors )
# If the tool provides a `validate_input` hook, call it.
validate_input = self.get_hook( 'validate_input' )
@@ -1834,7 +1835,7 @@ class Tool( object, Dictifiable ):
# create tool state
state_inputs = {}
state_errors = {}
self.populate_state( request_context, self.inputs, params.__dict__, state_inputs, state_errors )
populate_state( request_context, self.inputs, params.__dict__, state_inputs, state_errors )
# create tool model
tool_model = self.to_dict( request_context )
@@ -1877,82 +1878,6 @@ class Tool( object, Dictifiable ):
})
return tool_model
# populates state from incoming parameters
def populate_state( self, request_context, inputs, incoming, state, errors={}, prefix='', context=None ):
context = ExpressionContext( state, context )
for input in inputs.values():
state[ input.name ] = input.get_initial_value( request_context, context )
key = prefix + input.name
group_state = state[ input.name ]
group_prefix = '%s|' % ( key )
if input.type == 'repeat':
rep_index = 0
del group_state[:]
while True:
rep_prefix = '%s_%d' % ( key, rep_index )
if not any( incoming_key.startswith( rep_prefix ) for incoming_key in incoming.keys() ) and rep_index >= input.min:
break
if rep_index < input.max:
new_state = { '__index__' : rep_index }
group_state.append( new_state )
self.populate_state( request_context, input.inputs, incoming, new_state, errors, prefix=rep_prefix + '|', context=context )
rep_index += 1
elif input.type == 'conditional':
if input.value_ref and not input.value_ref_in_group:
test_param_key = prefix + input.test_param.name
else:
test_param_key = group_prefix + input.test_param.name
test_param_value = incoming.get( test_param_key, group_state.get( input.test_param.name ) )
value, error = check_param( request_context, input.test_param, test_param_value, context )
if error:
errors[ test_param_key ] = error
else:
try:
current_case = input.get_current_case( value )
group_state = state[ input.name ] = {}
self.populate_state( request_context, input.cases[ current_case ].inputs, incoming, group_state, errors, prefix=group_prefix, context=context )
group_state[ '__current_case__' ] = current_case
except Exception:
errors[ test_param_key ] = 'The selected case is unavailable/invalid.'
pass
group_state[ input.test_param.name ] = value
elif input.type == 'section':
self.populate_state( request_context, input.inputs, incoming, group_state, errors, prefix=group_prefix, context=context )
elif input.type == 'upload_dataset':
d_type = input.get_datatype( request_context, context=context )
writable_files = d_type.writable_files
while len( group_state ) > len( writable_files ):
del group_state[ -1 ]
while len( writable_files ) > len( group_state ):
new_state = { '__index__' : len( group_state ) }
for upload_item in input.inputs.values():
new_state[ upload_item.name ] = upload_item.get_initial_value( request_context, context )
group_state.append( new_state )
for i, rep_state in enumerate( group_state ):
rep_index = rep_state[ '__index__' ]
rep_prefix = '%s_%d|' % ( key, rep_index )
self.populate_state( request_context, input.inputs, incoming, rep_state, errors, prefix=rep_prefix, context=context )
else:
param_value = self._get_incoming_value( incoming, key, state.get( input.name ) )
value, error = check_param( request_context, input, param_value, context )
if error:
errors[ key ] = error
state[ input.name ] = value
def _get_incoming_value( self, incoming, key, default ):
"""
Fetch value from incoming dict directly or check special nginx upload
created variants of this key.
"""
if '__' + key + '__is_composite' in incoming:
composite_keys = incoming[ '__' + key + '__keys' ].split()
value = dict()
for composite_key in composite_keys:
value[ composite_key ] = incoming[ key + '_' + composite_key ]
return value
else:
return incoming.get( key, default )
def _get_job_remap( self, job):
if job:
if job.state == job.states.ERROR:
+118
View File
@@ -214,3 +214,121 @@ def update_param( prefixed_name, input_values, new_value ):
update_param( match.group( 1 ), input_values[ key ], new_value )
elif prefixed_name == key:
input_values[ key ] = new_value
def populate_state( request_context, inputs, incoming, state, errors={}, prefix='', context=None, check=True ):
"""
Populates nested state dict from incoming parameter values.
>>> from xml.etree.ElementTree import XML
>>> from galaxy.util.bunch import Bunch
>>> from galaxy.util.odict import odict
>>> from galaxy.tools.parameters.basic import TextToolParameter, BooleanToolParameter
>>> from galaxy.tools.parameters.grouping import Repeat
>>> trans = Bunch( workflow_building_mode=False )
>>> a = TextToolParameter( None, XML( '<param name="a"/>' ) )
>>> b = Repeat()
>>> b.min = 0
>>> b.max = 1
>>> c = TextToolParameter( None, XML( '<param name="c"/>' ) )
>>> d = Repeat()
>>> d.min = 0
>>> d.max = 1
>>> e = TextToolParameter( None, XML( '<param name="e"/>' ) )
>>> f = Conditional()
>>> g = BooleanToolParameter( None, XML( '<param name="g"/>' ) )
>>> h = TextToolParameter( None, XML( '<param name="h"/>' ) )
>>> i = TextToolParameter( None, XML( '<param name="i"/>' ) )
>>> b.name = 'b'
>>> b.inputs = odict([ ('c', c), ('d', d) ])
>>> d.name = 'd'
>>> d.inputs = odict([ ('e', e), ('f', f) ])
>>> f.test_param = g
>>> f.name = 'f'
>>> f.cases = [ Bunch( value='true', inputs= { 'h': h } ), Bunch( value='false', inputs= { 'i': i } ) ]
>>> inputs = odict([('a',a),('b',b)])
>>> flat = odict([ ('a', 1 ), ( 'b_0|c', 2 ), ( 'b_0|d_0|e', 3 ), ( 'b_0|d_0|f|h', 4 ), ( 'b_0|d_0|f|g', True ) ])
>>> state = odict()
>>> populate_state( trans, inputs, flat, state, check=False )
>>> print state[ 'a' ]
1
>>> print state[ 'b' ][ 0 ][ 'c' ]
2
>>> print state[ 'b' ][ 0 ][ 'd' ][ 0 ][ 'e' ]
3
>>> print state[ 'b' ][ 0 ][ 'd' ][ 0 ][ 'f' ][ 'h' ]
4
"""
context = ExpressionContext( state, context )
for input in inputs.values():
state[ input.name ] = input.get_initial_value( request_context, context )
key = prefix + input.name
group_state = state[ input.name ]
group_prefix = '%s|' % ( key )
if input.type == 'repeat':
rep_index = 0
del group_state[:]
while True:
rep_prefix = '%s_%d' % ( key, rep_index )
if not any( incoming_key.startswith( rep_prefix ) for incoming_key in incoming.keys() ) and rep_index >= input.min:
break
if rep_index < input.max:
new_state = { '__index__' : rep_index }
group_state.append( new_state )
populate_state( request_context, input.inputs, incoming, new_state, errors, prefix=rep_prefix + '|', context=context )
rep_index += 1
elif input.type == 'conditional':
if input.value_ref and not input.value_ref_in_group:
test_param_key = prefix + input.test_param.name
else:
test_param_key = group_prefix + input.test_param.name
test_param_value = incoming.get( test_param_key, group_state.get( input.test_param.name ) )
value, error = check_param( request_context, input.test_param, test_param_value, context ) if check else [ test_param_value, None ]
if error:
errors[ test_param_key ] = error
else:
try:
current_case = input.get_current_case( value )
group_state = state[ input.name ] = {}
populate_state( request_context, input.cases[ current_case ].inputs, incoming, group_state, errors, prefix=group_prefix, context=context )
group_state[ '__current_case__' ] = current_case
except Exception:
errors[ test_param_key ] = 'The selected case is unavailable/invalid.'
pass
group_state[ input.test_param.name ] = value
elif input.type == 'section':
populate_state( request_context, input.inputs, incoming, group_state, errors, prefix=group_prefix, context=context )
elif input.type == 'upload_dataset':
d_type = input.get_datatype( request_context, context=context )
writable_files = d_type.writable_files
while len( group_state ) > len( writable_files ):
del group_state[ -1 ]
while len( writable_files ) > len( group_state ):
new_state = { '__index__' : len( group_state ) }
for upload_item in input.inputs.values():
new_state[ upload_item.name ] = upload_item.get_initial_value( request_context, context )
group_state.append( new_state )
for i, rep_state in enumerate( group_state ):
rep_index = rep_state[ '__index__' ]
rep_prefix = '%s_%d|' % ( key, rep_index )
populate_state( request_context, input.inputs, incoming, rep_state, errors, prefix=rep_prefix, context=context )
else:
param_value = _get_incoming_value( incoming, key, state.get( input.name ) )
value, error = check_param( request_context, input, param_value, context ) if check else [ param_value, None ]
if error:
errors[ key ] = error
state[ input.name ] = value
def _get_incoming_value( incoming, key, default ):
"""
Fetch value from incoming dict directly or check special nginx upload
created variants of this key.
"""
if '__' + key + '__is_composite' in incoming:
composite_keys = incoming[ '__' + key + '__keys' ].split()
value = dict()
for composite_key in composite_keys:
value[ composite_key ] = incoming[ key + '_' + composite_key ]
return value
else:
return incoming.get( key, default )
@@ -19,6 +19,7 @@ from galaxy import web
from galaxy.exceptions import ObjectNotFound
from galaxy.managers import folders, roles
from galaxy.tools.actions import upload_common
from galaxy.tools.parameters import populate_state
from galaxy.util.streamball import StreamBall
from galaxy.web import _future_expose_api as expose_api
from galaxy.web import _future_expose_api_anonymous as expose_api_anonymous
@@ -451,7 +452,7 @@ class LibraryDatasetsController( BaseAPIController, UsesVisualizationMixin ):
tool_id = 'upload1'
tool = trans.app.toolbox.get_tool( tool_id )
state = tool.new_state( trans )
tool.populate_state( trans, tool.inputs, kwd, state.inputs )
populate_state( trans, tool.inputs, kwd, state.inputs )
tool_params = state.inputs
dataset_upload_inputs = []
for input in tool.inputs.itervalues():
+15 -40
View File
@@ -18,6 +18,7 @@ from galaxy.managers import (
workflows
)
from galaxy.model.item_attrs import UsesAnnotations
from galaxy.tools.parameters import populate_state
from galaxy.util.sanitize_html import sanitize_html
from galaxy.web import _future_expose_api as expose_api
from galaxy.web.base.controller import (
@@ -358,48 +359,22 @@ class WorkflowsAPIController(BaseAPIController, UsesStoredWorkflowMixin, UsesAnn
def build_module( self, trans, payload={} ):
"""
POST /api/workflows/build_module
Builds module details including a tool model for the workflow editor.
Builds module models for the workflow editor.
"""
type = payload.get( 'type' )
tool_id = payload.get( 'tool_id' )
content_id = payload.get( 'content_id' )
inputs = payload.get( 'inputs', {} )
annotation = inputs.get( '__annotation', '' )
label = inputs.get( '__label', '' )
if tool_id:
tool_version = payload.get( 'tool_version' )
tool = self._get_tool( tool_id, tool_version=tool_version, user=trans.user )
module = module_factory.from_dict( trans, {
'type' : 'tool',
'tool_id' : tool.id,
'tool_state' : None
} )
tool_model = module.tool.to_json( trans, inputs, workflow_building_mode=True )
module.recover_state( tool_model[ 'state_inputs' ] )
return {
'tool_model' : tool_model,
'tool_state' : module.get_state(),
'data_inputs' : module.get_data_inputs(),
'data_outputs' : module.get_data_outputs(),
'config_form' : module.get_config_form(),
'annotation' : annotation,
'post_job_actions' : module.get_post_job_actions(inputs)
}
else:
module = module_factory.from_dict( trans, {
'type' : type,
'label' : label,
'content_id' : content_id
} )
module.recover_state( inputs )
return {
'label' : module.label,
'tool_state' : module.get_state(),
'data_inputs' : module.get_data_inputs(),
'data_outputs' : module.get_data_outputs(),
'config_form' : module.get_config_form(),
'annotation' : annotation
}
module = module_factory.from_dict( trans, payload )
module_state = {}
populate_state( trans, module.get_inputs(), inputs, module_state, check=False )
module.recover_state( module_state )
return {
'label' : inputs.get( '__label', '' ),
'annotation' : inputs.get( '__annotation', '' ),
'tool_state' : module.get_state(),
'data_inputs' : module.get_data_inputs(),
'data_outputs' : module.get_data_outputs(),
'config_form' : module.get_config_form(),
'post_job_actions' : module.get_post_job_actions( inputs )
}
#
# -- Helper methods --
@@ -19,6 +19,7 @@ from sqlalchemy.orm import eagerload_all
from galaxy import util, web
from galaxy.security import Action
from galaxy.tools.actions import upload_common
from galaxy.tools.parameters import populate_state
from galaxy.util import inflector, unicodify, FILENAME_VALID_CHARS
from galaxy.util.streamball import StreamBall
from galaxy.web.base.controller import BaseUIController, UsesFormDefinitionsMixin, UsesExtendedMetadataMixin, UsesLibraryMixinItems
@@ -1044,7 +1045,7 @@ class LibraryCommon( BaseUIController, UsesFormDefinitionsMixin, UsesExtendedMet
tool_id = 'upload1'
tool = trans.app.toolbox.get_tool( tool_id )
state = tool.new_state( trans )
tool.populate_state( trans, tool.inputs, kwd, state.inputs )
populate_state( trans, tool.inputs, kwd, state.inputs )
tool_params = state.inputs
dataset_upload_inputs = []
for input_name, input in tool.inputs.iteritems():
+57 -64
View File
@@ -81,6 +81,9 @@ class WorkflowModule( object ):
def get_name( self ):
return self.name
def get_version( self ):
return None
def get_content_id( self ):
""" If this component has an identifier external to the step (such
as a tool or another workflow) return the identifier for that content.
@@ -114,7 +117,7 @@ class WorkflowModule( object ):
if inputs:
self.state.decode( state, Bunch( inputs=inputs ), self.trans.app )
else:
self.state.inputs = safe_loads( state )
self.state.inputs = safe_loads( state ) or {}
def get_errors( self ):
""" This returns a step related error message as string or None """
@@ -131,6 +134,9 @@ class WorkflowModule( object ):
def get_data_outputs( self ):
return []
def get_post_job_actions( self, incoming ):
return []
def check_and_update_state( self ):
"""
If the state is not in sync with the current implementation of the
@@ -227,17 +233,18 @@ class SubWorkflowModule( WorkflowModule ):
# - Second pass actually turn RuntimeInputs into inputs if possible.
type = "subworkflow"
name = "Subworkflow"
default_name = "Subworkflow"
@classmethod
def from_dict( Class, trans, d, **kwds ):
module = Class( trans )
if "subworkflow" in d:
module.subworkflow = d["subworkflow"]
module.subworkflow = d[ "subworkflow" ]
elif "content_id" in d:
content_id = d["content_id"]
module.subworkflow = SubWorkflowModule.subworkflow_from_content_id( trans, content_id )
module.label = d.get( "label", None ) or None
from galaxy.managers.workflows import WorkflowsManager
module.subworkflow = WorkflowsManager( trans.app ).get_owned_workflow( trans, d[ "content_id" ] )
else:
raise Exception( "Step associated subworkflow could not be found." )
module.label = d.get( "label" )
return module
@classmethod
@@ -252,7 +259,7 @@ class SubWorkflowModule( WorkflowModule ):
step.subworkflow = self.subworkflow
def get_name( self ):
if hasattr( self, 'subworkflow' ) and hasattr( self.subworkflow, 'name' ):
if hasattr( self.subworkflow, 'name' ):
return self.subworkflow.name
return self.name
@@ -264,43 +271,45 @@ class SubWorkflowModule( WorkflowModule ):
"data_collection_input": "dataset_collection",
}
inputs = []
for step in self.subworkflow.input_steps:
name = step.label
if name is None:
step_module = module_factory.from_workflow_step( self.trans, step )
name = step_module.state.inputs.get( "name" )
if not name:
raise Exception( "Failed to find name for workflow module." )
step_type = step.type
assert step_type in step_to_input_type
input = dict(
input_subworkflow_step_id=step.order_index,
name=name,
label=name,
multiple=False,
extensions="input",
input_type=step_to_input_type[step_type],
)
inputs.append(input)
if hasattr( self.subworkflow, 'input_steps' ):
for step in self.subworkflow.input_steps:
name = step.label
if name is None:
step_module = module_factory.from_workflow_step( self.trans, step )
name = step_module.state.inputs.get( "name" )
if not name:
raise Exception( "Failed to find name for workflow module." )
step_type = step.type
assert step_type in step_to_input_type
input = dict(
input_subworkflow_step_id=step.order_index,
name=name,
label=name,
multiple=False,
extensions="input",
input_type=step_to_input_type[step_type],
)
inputs.append(input)
return inputs
def get_data_outputs( self ):
outputs = []
for workflow_output in self.subworkflow.workflow_outputs:
output_step = workflow_output.workflow_step
label = workflow_output.label
if label is None:
label = "%s:%s" % (output_step.order_index, workflow_output.output_name)
output = dict(
name=label,
label=label,
extensions=['input'], # TODO
)
outputs.append(output)
if hasattr( self.subworkflow, 'workflow_outputs' ):
for workflow_output in self.subworkflow.workflow_outputs:
output_step = workflow_output.workflow_step
label = workflow_output.label
if label is None:
label = "%s:%s" % (output_step.order_index, workflow_output.output_name)
output = dict(
name=label,
label=label,
extensions=['input'], # TODO
)
outputs.append(output)
return outputs
def get_content_id( self ):
return self.trans.security.encode_id(self.subworkflow.id)
return self.trans.security.encode_id( self.subworkflow.id )
def execute( self, trans, progress, invocation, step ):
""" Execute the given workflow step in the given workflow invocation.
@@ -316,7 +325,6 @@ class SubWorkflowModule( WorkflowModule ):
workflow_output_label = workflow_output.label
replacement = subworkflow_progress.get_replacement_workflow_output( workflow_output )
outputs[ workflow_output_label ] = replacement
progress.set_step_outputs( step, outputs )
return None
@@ -325,13 +333,6 @@ class SubWorkflowModule( WorkflowModule ):
state.inputs = dict( )
return state
@classmethod
def subworkflow_from_content_id(clazz, trans, content_id):
from galaxy.managers.workflows import WorkflowsManager
workflow_manager = WorkflowsManager(trans.app)
subworkflow = workflow_manager.get_owned_workflow( trans, content_id )
return subworkflow
class InputModule( WorkflowModule ):
@@ -404,10 +405,10 @@ class InputDataModule( InputModule ):
class InputDataCollectionModule( InputModule ):
default_name = "Input Dataset Collection"
default_collection_type = "list"
type = "data_collection_input"
name = "Input dataset collection"
default_name = "Input Dataset Collection"
default_collection_type = "list"
collection_type = default_collection_type
def get_inputs( self ):
@@ -442,17 +443,15 @@ class InputDataCollectionModule( InputModule ):
class InputParameterModule( WorkflowModule ):
default_name = "input_parameter"
type = "parameter_input"
name = "Input parameter"
default_parameter_type = "text"
default_optional = False
type = "parameter_input"
name = default_name
parameter_type = default_parameter_type
optional = default_optional
def get_inputs( self ):
# TODO: Use an external xml or yaml file to load the parameter definition
name = self.state.inputs.get( "name", self.default_name )
parameter_type = self.state.inputs.get( "parameter_type", self.default_parameter_type )
optional = self.state.inputs.get( "optional", self.default_optional )
input_parameter_type = SelectToolParameter( None, XML(
@@ -465,12 +464,10 @@ class InputParameterModule( WorkflowModule ):
<option value="color">Color</option>
</param>
''' % parameter_type ) )
return odict([( "name", TextToolParameter( None, Element( "param", name="name", label="Name", type="text", value=name ) ) ),
( "parameter_type", input_parameter_type ),
return odict([( "parameter_type", input_parameter_type ),
( "optional", BooleanToolParameter( None, Element( "param", name="optional", label="Optional", type="boolean", value=optional )))])
def get_runtime_inputs( self, **kwds ):
label = self.state.inputs.get( "name", self.default_name )
parameter_type = self.state.inputs.get("parameter_type", self.default_parameter_type)
optional = self.state.inputs.get("optional", self.default_optional)
if parameter_type not in ["text", "boolean", "integer", "float", "color"]:
@@ -481,7 +478,7 @@ class InputParameterModule( WorkflowModule ):
parameter_kwds["value"] = str(0)
# TODO: Use a dict-based description from YAML tool source
element = Element("param", name="input", label=label, type=parameter_type, optional=str(optional), **parameter_kwds )
element = Element("param", name="input", label=self.label, type=parameter_type, optional=str(optional), **parameter_kwds )
input = parameter_class( None, element )
return dict( input=input )
@@ -505,11 +502,6 @@ class PauseModule( WorkflowModule ):
"""
type = "pause"
name = "Pause for dataset review"
default_name = "Pause for Dataset Review"
def get_inputs( self ):
name = self.state.inputs.get( "name", self.default_name )
return dict( name=TextToolParameter( None, Element( "param", name="name", type="text", value=name ) ) )
def get_data_inputs( self ):
input = dict(
@@ -559,6 +551,7 @@ class PauseModule( WorkflowModule ):
class ToolModule( WorkflowModule ):
type = "tool"
name = "Tool"
def __init__( self, trans, tool_id, tool_version=None, exact_tools=False, **kwds ):
super( ToolModule, self ).__init__( trans, content_id=tool_id, **kwds )
@@ -588,8 +581,8 @@ class ToolModule( WorkflowModule ):
message = ""
if tool_id != module.tool_id:
message += "The tool (id '%s') specified in this step is not available. Using the tool with id %s instead." % (tool_id, module.tool_id)
if d.get('tool_version', 'Unspecified') != module.get_tool_version():
message += "%s: using version '%s' instead of version '%s' specified in this workflow." % ( tool_id, module.get_tool_version(), d.get( 'tool_version', 'Unspecified' ) )
if d.get('tool_version', 'Unspecified') != module.get_version():
message += "%s: using version '%s' instead of version '%s' specified in this workflow." % ( tool_id, module.get_version(), d.get( 'tool_version', 'Unspecified' ) )
if message:
log.debug( message )
module.version_changes.append( message )
@@ -629,7 +622,7 @@ class ToolModule( WorkflowModule ):
def save_to_step( self, step ):
super( ToolModule, self ).save_to_step( step )
step.tool_id = self.tool_id
step.tool_version = self.get_tool_version()
step.tool_version = self.get_version()
for k, v in self.post_job_actions.iteritems():
pja = self.__to_pja( k, v, step )
self.trans.sa_session.add( pja )
@@ -642,7 +635,7 @@ class ToolModule( WorkflowModule ):
def get_content_id( self ):
return self.tool_id
def get_tool_version( self ):
def get_version( self ):
return self.tool.version if self.tool else self.tool_version
def get_tooltip( self, static_path='' ):
+2 -16
View File
@@ -63,10 +63,9 @@ def _normalize_inputs(steps, inputs, inputs_by):
elif inputs_by_el == "step_uuid":
possible_input_keys.append(str( step.uuid ))
elif inputs_by_el == "name":
possible_input_keys.append( step.name )
possible_input_keys.append( step.label or step.tool_inputs.get( 'name' ) )
else:
message = "Workflow cannot be run because unexpected inputs_by value specified."
raise exceptions.MessageException( message )
raise exceptions.MessageException( "Workflow cannot be run because unexpected inputs_by value specified." )
inputs_key = None
for possible_input_key in possible_input_keys:
if possible_input_key in inputs:
@@ -369,13 +368,11 @@ def workflow_run_config_to_request( trans, run_config, workflow ):
def workflow_request_to_run_config( work_request_context, workflow_invocation ):
param_types = model.WorkflowRequestInputParameter.types
history = workflow_invocation.history
replacement_dict = {}
inputs = {}
param_map = {}
copy_inputs_to_history = None
for parameter in workflow_invocation.input_parameters:
parameter_type = parameter.type
@@ -384,25 +381,14 @@ def workflow_request_to_run_config( work_request_context, workflow_invocation ):
elif parameter_type == param_types.META_PARAMETERS:
if parameter.name == "copy_inputs_to_history":
copy_inputs_to_history = (parameter.value == "true")
# for parameter in workflow_invocation.step_parameters:
# step_id = parameter.workflow_step_id
# if step_id not in param_map:
# param_map[ step_id ] = {}
# param_map[ step_id ][ parameter.name ] = parameter.value
for input_association in workflow_invocation.input_datasets:
inputs[ input_association.workflow_step_id ] = input_association.dataset
for input_association in workflow_invocation.input_dataset_collections:
inputs[ input_association.workflow_step_id ] = input_association.dataset_collection
for input_association in workflow_invocation.input_step_parameters:
inputs[ input_association.workflow_step_id ] = input_association.parameter_value
if copy_inputs_to_history is None:
raise exceptions.InconsistentDatabase("Failed to find copy_inputs_to_history parameter loading workflow_invocation from database.")
workflow_run_config = WorkflowRunConfig(
target_history=history,
replacement_dict=replacement_dict,
+1 -1
View File
@@ -233,7 +233,7 @@ def get_workflow_data_outputs( step, module, steps ):
found = False
for workflow_step in steps:
for wfsc in workflow_step.input_connections:
if step.name == wfsc.output_step.name:
if step.label == wfsc.output_step.label:
data_outputs_dict[ 'name' ] = wfsc.output_name
found = True
break
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long