Merge pull request #2969 from guerler/unite_api

Unite workflow execution api endpoints
This commit is contained in:
John Chilton
2016-10-05 08:47:04 -04:00
committed by GitHub
22 changed files with 501 additions and 369 deletions
@@ -77,7 +77,7 @@ define([ 'utils/utils', 'utils/deferred', 'mvc/ui/ui-misc', 'mvc/form/form-view'
_.each( this.steps, function( step, i ) {
_.each( step.output_connections, function( output_connection ) {
_.each( self.steps, function( sub_step, j ) {
sub_step.step_id === output_connection.input_step_id && self.links[ i ].push( sub_step );
sub_step.step_index === output_connection.input_step_index && self.links[ i ].push( sub_step );
});
});
});
@@ -88,7 +88,7 @@ define([ 'utils/utils', 'utils/deferred', 'mvc/ui/ui-misc', 'mvc/form/form-view'
_.each( self.steps, function( sub_step, j ) {
var connections_by_name = {};
_.each( step.output_connections, function( connection ) {
sub_step.step_id === connection.input_step_id && ( connections_by_name[ connection.input_name ] = connection );
sub_step.step_index === connection.input_step_index && ( connections_by_name[ connection.input_name ] = connection );
});
_.each( self.parms[ j ], function( input, name ) {
var connection = connections_by_name[ name ];
@@ -224,34 +224,31 @@ define([ 'utils/utils', 'utils/deferred', 'mvc/ui/ui-misc', 'mvc/form/form-view'
/** Render workflow parameters */
_renderHistory: function() {
this.history_form = null;
if ( !this.model.get( 'history_id' ) ) {
this.history_form = new Form({
cls : 'ui-portlet-narrow',
title : '<b>History Options</b>',
inputs : [{
type : 'conditional',
name : 'new_history',
test_param : {
name : 'check',
label : 'Send results to a new history',
type : 'boolean',
value : 'false',
help : ''
},
cases : [{
value : 'true',
inputs : [{
name : 'name',
label : 'History name',
type : 'text',
value : this.model.get( 'name' )
}]
this.history_form = new Form({
cls : 'ui-portlet-narrow',
title : '<b>History Options</b>',
inputs : [{
type : 'conditional',
name : 'new_history',
test_param : {
name : 'check',
label : 'Send results to a new history',
type : 'boolean',
value : 'false',
help : ''
},
cases : [{
value : 'true',
inputs : [{
name : 'name',
label : 'History name',
type : 'text',
value : this.model.get( 'name' )
}]
}]
});
this._append( this.$steps, this.history_form.$el );
}
}]
});
this._append( this.$steps, this.history_form.$el );
},
/** Render step */
@@ -355,17 +352,26 @@ define([ 'utils/utils', 'utils/deferred', 'mvc/ui/ui-misc', 'mvc/form/form-view'
/** Validate and submit workflow */
_submit: function() {
var self = this;
var history_form_data = this.history_form.data.create();
var job_def = {
new_history_name : this.history_form ? this.history_form.data.create()[ 'new_history|name' ] : {},
replacement_params : this.wp_form ? this.wp_form.data.create() : {},
inputs : {}
new_history_name : history_form_data[ 'new_history|name' ] ? history_form_data[ 'new_history|name' ] : null,
history_id : !history_form_data[ 'new_history|name' ] ? this.model.get( 'history_id' ) : null,
replacement_params : this.wp_form ? this.wp_form.data.create() : {},
parameters : {},
// Tool form will submit flat maps for each parameter
// (e.g. "repeat_0|cond|param": "foo" instead of nested
// data structures).
parameters_normalized : true,
// Tool form always wants a list of invocations back
// so that inputs can be batched.
batch : true
};
var validated = true;
for ( var i in this.forms ) {
var form = this.forms[ i ];
var job_inputs = form.data.create();
var step = self.steps[ i ];
var step_id = step.step_id;
var step_index = step.step_index;
form.trigger( 'reset' );
for ( var job_input_id in job_inputs ) {
var input_value = job_inputs[ job_input_id ];
@@ -382,8 +388,8 @@ define([ 'utils/utils', 'utils/deferred', 'mvc/ui/ui-misc', 'mvc/form/form-view'
form.highlight( input_id );
break;
}
job_def.inputs[ step_id ] = job_def.inputs[ step_id ] || {};
job_def.inputs[ step_id ][ job_input_id ] = job_inputs[ job_input_id ];
job_def.parameters[ step_index ] = job_def.parameters[ step_index ] || {};
job_def.parameters[ step_index ][ job_input_id ] = job_inputs[ job_input_id ];
}
}
if ( !validated ) {
@@ -397,31 +403,35 @@ define([ 'utils/utils', 'utils/deferred', 'mvc/ui/ui-misc', 'mvc/form/form-view'
Galaxy.emit.debug( 'tool-form-composite::submit()', 'Validation complete.', job_def );
Utils.request({
type : 'POST',
url : Galaxy.root + 'api_internal/workflows/' + this.model.id + '/run',
url : Galaxy.root + 'api/workflows/' + this.model.id + '/invocations',
data : job_def,
success : function( response ) {
Galaxy.emit.debug( 'tool-form-composite::submit', 'Submission successful.', response );
self.$el.empty().append( self._templateSuccess( response ) );
self.$el.children().hide();
self.$el.append( self._templateSuccess( response ) );
self._refreshHistory();
},
error : function( response ) {
Galaxy.emit.debug( 'tool-form-composite::submit', 'Submission failed.', response );
var input_found = false;
if ( response && response.err_data ) {
for ( var i in self.forms ) {
var form = self.forms[ i ];
var step_related_errors = response.err_data[ form.options.step_id ];
var step_related_errors = response.err_data[ form.options.step_index ];
if ( step_related_errors ) {
var error_messages = form.data.matchResponse( step_related_errors );
for ( var input_id in error_messages ) {
form.highlight( input_id, error_messages[ input_id ] );
input_found = true;
break;
}
}
}
} else {
}
if ( !input_found ) {
self.modal.show({
title : 'Job submission failed',
body : self._templateError( response && response.err_msg || job_def ),
title : 'Workflow submission failed',
body : self._templateError( job_def, response && response.err_msg ),
buttons : {
'Close' : function() {
self.modal.hide();
@@ -471,17 +481,19 @@ define([ 'utils/utils', 'utils/deferred', 'mvc/ui/ui-misc', 'mvc/form/form-view'
/** Templates */
_templateSuccess: function( response ) {
if ( response && response.length > 0 ) {
return $( '<div/>' ).addClass( 'donemessagelarge' ).append( $( '<p/>' ).html( 'Successfully invoked workflow <b>' + Utils.sanitize( this.model.get( 'name' ) ) + '</b>' + ( response.length > 1 ? ' <b>' + response.length + ' times</b>' : '' ) + '. Datasets will appear as jobs are created.' ) );
if ( $.isArray( response ) && response.length > 0 ) {
return $( '<div/>' ).addClass( 'donemessagelarge' )
.append( $( '<p/>' ).html( 'Successfully invoked workflow <b>' + Utils.sanitize( this.model.get( 'name' ) ) + '</b>' + ( response.length > 1 ? ' <b>' + response.length + ' times</b>' : '' ) + '.' ) )
.append( $( '<p/>' ).append( '<b/>' ).text( 'You can check the status of queued jobs and view the resulting data by refreshing the History pane. When the job has been run the status will change from \'running\' to \'finished\' if completed successfully or \'error\' if problems were encountered.' ) );
} else {
return this._templateError( response );
return this._templateError( response, 'Invalid success response. No invocations found.' );
}
},
_templateError: function( response ) {
_templateError: function( response, err_msg ) {
return $( '<div/>' ).addClass( 'errormessagelarge' )
.append( $( '<p/>' ).text( 'The server could not complete the request. Please contact the Galaxy Team if this error persists.' ) )
.append( $( '<pre/>' ).text( JSON.stringify( response, null, 4 ) ) );
.append( $( '<p/>' ).text( 'The server could not complete the request. Please contact the Galaxy Team if this error persists. ' + ( JSON.stringify( err_msg ) || '' ) ) )
.append( $( '<pre/>' ).text( JSON.stringify( response, null, 4 ) ) );
}
});
return {
+5 -5
View File
@@ -88,7 +88,7 @@ define([ 'utils/utils', 'mvc/ui/ui-misc', 'mvc/ui/ui-modal', 'mvc/tool/tool-form
var input_found = false;
if ( response && response.err_data ) {
var error_messages = self.form.data.matchResponse( response.err_data );
for (var input_id in error_messages) {
for ( var input_id in error_messages ) {
self.form.highlight( input_id, error_messages[ input_id ]);
input_found = true;
break;
@@ -97,7 +97,7 @@ define([ 'utils/utils', 'mvc/ui/ui-misc', 'mvc/ui/ui-modal', 'mvc/tool/tool-form
if ( !input_found ) {
self.modal.show({
title : 'Job submission failed',
body : ( response && response.err_msg ) || self._templateError( job_def ),
body : self._templateError( job_def, response && response.err_msg ),
buttons : { 'Close' : function() { self.modal.hide() } }
});
}
@@ -159,13 +159,13 @@ define([ 'utils/utils', 'mvc/ui/ui-misc', 'mvc/ui/ui-modal', 'mvc/tool/tool-form
$message.append( $( '<p/>' ).append( '<b/>' ).text( 'You can check the status of queued jobs and view the resulting data by refreshing the History pane. When the job has been run the status will change from \'running\' to \'finished\' if completed successfully or \'error\' if problems were encountered.' ) );
return $message;
} else {
return this._templateError( response );
return this._templateError( response, 'Invalid success response. No jobs found.' );
}
},
_templateError: function( response ) {
_templateError: function( response, err_msg ) {
return $( '<div/>' ).addClass( 'errormessagelarge' )
.append( $( '<p/>' ).text( 'The server could not complete the request. Please contact the Galaxy Team if this error persists.' ) )
.append( $( '<p/>' ).text( 'The server could not complete the request. Please contact the Galaxy Team if this error persists. ' + ( err_msg || '' ) ) )
.append( $( '<pre/>' ).text( JSON.stringify( response, null, 4 ) ) );
}
});
+7 -3
View File
@@ -368,6 +368,9 @@ class WorkflowContentsManager(UsesAnnotations):
workflow.annotation = self.get_item_annotation_str( trans.sa_session, trans.user, workflow )
raise exceptions.MessageException( 'Following tools missing: %s' % missing_tools )
workflow.annotation = self.get_item_annotation_str( trans.sa_session, trans.user, workflow )
step_order_indices = {}
for step in workflow.steps:
step_order_indices[ step.id ] = step.order_index
step_models = []
for i, step in enumerate( workflow.steps ):
step_model = None
@@ -388,11 +391,11 @@ class WorkflowContentsManager(UsesAnnotations):
'name' : step.module.name,
'inputs' : [ input.to_dict( trans ) for input in inputs.itervalues() ]
}
step_model[ 'step_id' ] = step.id
step_model[ 'step_type' ] = step.type
step_model[ 'step_index' ] = step.order_index
step_model[ 'output_connections' ] = [ {
'input_step_id' : oc.input_step_id,
'output_step_id' : oc.output_step_id,
'input_step_index' : step_order_indices.get( oc.input_step_id ),
'output_step_index' : step_order_indices.get( oc.output_step_id ),
'input_name' : oc.input_name,
'output_name' : oc.output_name
} for oc in step.output_connections ]
@@ -403,6 +406,7 @@ class WorkflowContentsManager(UsesAnnotations):
step_models.append( step_model )
return {
'id' : trans.app.security.encode_id( stored.id ),
'history_id' : trans.app.security.encode_id( trans.history.id ) if trans.history else None,
'name' : stored.name,
'steps' : step_models,
'step_version_changes' : step_version_changes,
+2 -1
View File
@@ -1156,7 +1156,8 @@ class Tool( object, Dictifiable ):
log.debug( 'Validated and populated state for tool request %s' % validation_timer )
# If there were errors, we stay on the same page and display them
if any( all_errors ):
raise exceptions.MessageException( ', '.join( [ msg for msg in all_errors[ 0 ].itervalues() ] ), err_data=all_errors[ 0 ] )
err_data = { key: value for d in all_errors for ( key, value ) in d.iteritems() }
raise exceptions.MessageException( ', '.join( [ msg for msg in err_data.itervalues() ] ), err_data=err_data )
else:
execution_tracker = execute_job( trans, self, all_params, history=request_context.history, rerun_remap_job_id=rerun_remap_job_id, collection_info=collection_info )
if execution_tracker.successful_jobs:
+2 -2
View File
@@ -1587,7 +1587,7 @@ class DataToolParameter( BaseDataToolParameter ):
if trans.workflow_building_mode is workflow_building_modes.ENABLED:
return None
if not value and not self.optional:
raise ValueError( "History does not include a dataset of the required format / build" )
raise ValueError( "Specify a dataset of the required format / build." )
if value in [ None, "None", '' ]:
return None
if isinstance( value, dict ) and 'values' in value:
@@ -1854,7 +1854,7 @@ class DataCollectionToolParameter( BaseDataToolParameter ):
if trans.workflow_building_mode is workflow_building_modes.ENABLED:
return None
if not value and not self.optional:
raise ValueError( "History does not include a dataset collection of the correct type or containing the correct types of datasets" )
raise ValueError( "Specify a dataset collection of the correct type." )
if value in [None, "None"]:
return None
if isinstance( value, dict ) and 'values' in value:
+53 -53
View File
@@ -9,59 +9,59 @@ log = logging.getLogger( __name__ )
def expand_workflow_inputs( inputs ):
"""
Expands incoming encoded multiple payloads, into the set of all individual payload combinations
>>> params, param_keys = expand_workflow_inputs( {'1': {'input': {'batch': True, 'product': True, 'values': [{'hid': '1'}, {'hid': '2'}] }}} )
>>> print sorted( [ "%s" % ( p[ '1' ][ 'input' ][ 'hid' ] ) for p in params ] )
['1', '2']
>>> params, param_keys = expand_workflow_inputs( {'1': {'input': {'batch': True, 'values': [{'hid': '1'}, {'hid': '2'}] }}} )
>>> print sorted( [ "%s" % ( p[ '1' ][ 'input' ][ 'hid' ] ) for p in params ] )
['1', '2']
>>> params, param_keys = expand_workflow_inputs( {'1': {'input': {'batch': True, 'values': [{'hid': '1'}, {'hid': '2'}] }}, '2': {'input': {'batch': True, 'values': [{'hid': '3'}, {'hid': '4'}] }}} )
>>> print sorted( [ "%s%s" % ( p[ '1' ][ 'input' ][ 'hid' ], p[ '2' ][ 'input' ][ 'hid' ] ) for p in params ] )
['13', '24']
>>> params, param_keys = expand_workflow_inputs( {'1': {'input': {'batch': True, 'product': True, 'values': [{'hid': '1'}, {'hid': '2'}] }}, '2': {'input': {'batch': True, 'values': [{'hid': '3'}, {'hid': '4'}, {'hid': '5'}] }}} )
>>> print sorted( [ "%s%s" % ( p[ '1' ][ 'input' ][ 'hid' ], p[ '2' ][ 'input' ][ 'hid' ] ) for p in params ] )
['13', '14', '15', '23', '24', '25']
>>> params, param_keys = expand_workflow_inputs( {'1': {'input': {'batch': True, 'product': True, 'values': [{'hid': '1'}, {'hid': '2'}] }}, '2': {'input': {'batch': True, 'product': True, 'values': [{'hid': '3'}, {'hid': '4'}, {'hid': '5'}] }}, '3': {'input': {'batch': True, 'product': True, 'values': [{'hid': '6'}, {'hid': '7'}, {'hid': '8'}] }}} )
>>> print sorted( [ "%s%s%s" % ( p[ '1' ][ 'input' ][ 'hid' ], p[ '2' ][ 'input' ][ 'hid' ], p[ '3' ][ 'input' ][ 'hid' ] ) for p in params ] )
['136', '137', '138', '146', '147', '148', '156', '157', '158', '236', '237', '238', '246', '247', '248', '256', '257', '258']
"""
linked_n = None
linked = []
product = []
linked_keys = []
product_keys = []
for step_id, step in inputs.items():
for key, value in step.items():
if isinstance( value, dict ) and 'batch' in value and value[ 'batch' ] is True and 'values' in value and isinstance( value[ 'values' ], list ):
nval = len( value[ 'values' ] )
if 'product' in value and value[ 'product' ] is True:
product.append( value[ 'values' ] )
product_keys.append( ( step_id, key ) )
else:
if linked_n is None:
linked_n = nval
elif linked_n != nval or nval is 0:
raise exceptions.RequestParameterInvalidException( 'Failed to match linked batch selections. Please select equal number of data files.' )
linked.append( value[ 'values' ] )
linked_keys.append( ( step_id, key ) )
params = []
params_keys = []
linked = linked or [ [ None ] ]
product = product or [ [ None ] ]
linked_keys = linked_keys or [ ( None, None ) ]
product_keys = product_keys or [ ( None, None ) ]
for linked_values, product_values in itertools.product( *[ zip( *linked ), itertools.product( *product ) ] ):
new_params = copy.deepcopy( inputs )
new_keys = []
for ( step_id, key ), value in zip( linked_keys, linked_values ) + zip( product_keys, product_values ):
if step_id is not None:
new_params[ step_id ][ key ] = value
new_keys.append( value[ 'hid' ] )
params_keys.append( new_keys )
params.append( new_params )
return params, params_keys
"""
Expands incoming encoded multiple payloads, into the set of all individual payload combinations
>>> params, param_keys = expand_workflow_inputs( {'1': {'input': {'batch': True, 'product': True, 'values': [{'hid': '1'}, {'hid': '2'}] }}} )
>>> print [ "%s" % ( p[ '1' ][ 'input' ][ 'hid' ] ) for p in params ]
['1', '2']
>>> params, param_keys = expand_workflow_inputs( {'1': {'input': {'batch': True, 'values': [{'hid': '1'}, {'hid': '2'}] }}} )
>>> print [ "%s" % ( p[ '1' ][ 'input' ][ 'hid' ] ) for p in params ]
['1', '2']
>>> params, param_keys = expand_workflow_inputs( {'1': {'input': {'batch': True, 'values': [{'hid': '1'}, {'hid': '2'}] }}, '2': {'input': {'batch': True, 'values': [{'hid': '3'}, {'hid': '4'}] }}} )
>>> print [ "%s%s" % ( p[ '1' ][ 'input' ][ 'hid' ], p[ '2' ][ 'input' ][ 'hid' ] ) for p in params ]
['13', '24']
>>> params, param_keys = expand_workflow_inputs( {'1': {'input': {'batch': True, 'product': True, 'values': [{'hid': '1'}, {'hid': '2'}] }}, '2': {'input': {'batch': True, 'values': [{'hid': '3'}, {'hid': '4'}, {'hid': '5'}] }}} )
>>> print [ "%s%s" % ( p[ '1' ][ 'input' ][ 'hid' ], p[ '2' ][ 'input' ][ 'hid' ] ) for p in params ]
['13', '23', '14', '24', '15', '25']
>>> params, param_keys = expand_workflow_inputs( {'1': {'input': {'batch': True, 'product': True, 'values': [{'hid': '1'}, {'hid': '2'}] }}, '2': {'input': {'batch': True, 'product': True, 'values': [{'hid': '3'}, {'hid': '4'}, {'hid': '5'}] }}, '3': {'input': {'batch': True, 'product': True, 'values': [{'hid': '6'}, {'hid': '7'}, {'hid': '8'}] }}} )
>>> print [ "%s%s%s" % ( p[ '1' ][ 'input' ][ 'hid' ], p[ '2' ][ 'input' ][ 'hid' ], p[ '3' ][ 'input' ][ 'hid' ] ) for p in params ]
['136', '137', '138', '146', '147', '148', '156', '157', '158', '236', '237', '238', '246', '247', '248', '256', '257', '258']
"""
linked_n = None
linked = []
product = []
linked_keys = []
product_keys = []
for step_id, step in sorted( inputs.items() ):
for key, value in sorted( step.items() ):
if isinstance( value, dict ) and 'batch' in value and value[ 'batch' ] is True and 'values' in value and isinstance( value[ 'values' ], list ):
nval = len( value[ 'values' ] )
if 'product' in value and value[ 'product' ] is True:
product.append( value[ 'values' ] )
product_keys.append( ( step_id, key ) )
else:
if linked_n is None:
linked_n = nval
elif linked_n != nval or nval is 0:
raise exceptions.RequestParameterInvalidException( 'Failed to match linked batch selections. Please select equal number of data files.' )
linked.append( value[ 'values' ] )
linked_keys.append( ( step_id, key ) )
params = []
params_keys = []
linked = linked or [ [ None ] ]
product = product or [ [ None ] ]
linked_keys = linked_keys or [ ( None, None ) ]
product_keys = product_keys or [ ( None, None ) ]
for linked_values, product_values in itertools.product( *[ zip( *linked ), itertools.product( *product ) ] ):
new_params = copy.deepcopy( inputs )
new_keys = []
for ( step_id, key ), value in zip( linked_keys, linked_values ) + zip( product_keys, product_values ):
if step_id is not None:
new_params[ step_id ][ key ] = value
new_keys.append( value[ 'hid' ] )
params_keys.append( new_keys )
params.append( new_params )
return params, params_keys
def expand_meta_parameters( trans, tool, incoming ):
+28 -80
View File
@@ -15,11 +15,9 @@ from galaxy.web import _future_expose_api as expose_api
from galaxy.web.base.controller import BaseAPIController, url_for, UsesStoredWorkflowMixin
from galaxy.web.base.controller import SharableMixin
from galaxy.workflow.extract import extract_workflow
from galaxy.workflow.run import invoke, queue_invoke, WorkflowRunConfig
from galaxy.workflow.run_request import build_workflow_run_config
from galaxy.workflow.modules import module_factory, WorkflowModuleInjector
from galaxy.tools.parameters.basic import workflow_building_modes
from galaxy.tools.parameters.meta import expand_workflow_inputs
from galaxy.workflow.run import invoke, queue_invoke
from galaxy.workflow.run_request import build_workflow_run_configs
from galaxy.workflow.modules import module_factory
log = logging.getLogger(__name__)
@@ -85,68 +83,6 @@ class WorkflowsAPIController(BaseAPIController, UsesStoredWorkflowMixin, UsesAnn
style = "instance"
return self.workflow_contents_manager.workflow_to_dict( trans, stored_workflow, style=style )
@expose_api
def run( self, trans, workflow_id, payload, **kwd ):
"""
POST /api_internal/workflows/{encoded_workflow_id}/run
Run a workflow with a dictionary of prefixed_name/value pairs e.g.
payload = { inputs: { step_0: { parameter_0|parameter_1 : value_0, ... }, ... } }
"""
workflow = self.__get_stored_accessible_workflow( trans, workflow_id ).latest_workflow
trans.workflow_building_mode = workflow_building_modes.USE_HISTORY
module_injector = WorkflowModuleInjector( trans )
params, param_keys = expand_workflow_inputs( payload.get( 'inputs', [] ) )
errors = {}
for workflow_args in params:
for step in workflow.steps:
step_args = workflow_args.get( str( step.id ), {} )
step_errors = module_injector.inject( step, step_args )
if step_errors:
errors[ step.id ] = step_errors
if errors:
log.exception( errors )
raise exceptions.MessageException( err_data=errors )
invocations = []
for index, workflow_args in enumerate( params ):
for step in workflow.steps:
step_args = workflow_args.get( str( step.id ), {} )
module_injector.inject( step, step_args )
new_history = None
if 'new_history_name' in payload:
if payload[ 'new_history_name' ]:
nh_name = payload[ 'new_history_name' ]
else:
nh_name = 'History from %s workflow' % workflow.name
if index in param_keys:
ids = param_keys[ index ]
nids = len( ids )
if nids == 1:
nh_name = '%s on %s' % ( nh_name, ids[ 0 ] )
elif nids > 1:
nh_name = '%s on %s and %s' % ( nh_name, ', '.join( ids[ 0:-1 ] ), ids[ -1 ] )
new_history = trans.app.model.History( user=trans.user, name=nh_name )
new_history.copy_tags_from( trans.user, trans.history )
trans.sa_session.add( new_history )
target_history = new_history
elif 'history_id' in payload:
target_history = histories.HistoryManager( trans.app ).get_owned( trans.security.decode_id( payload.get( 'history_id' ), trans.user, current_history=trans.history ) )
else:
target_history = trans.history
run_config = WorkflowRunConfig(
target_history=target_history,
replacement_dict=payload.get( 'replacement_params', {} ),
copy_inputs_to_history=new_history is not None )
invocation = queue_invoke(
trans=trans,
workflow=workflow,
workflow_run_config=run_config,
populate_state=False )
invocations.append({ 'history' : { 'id' : trans.app.security.encode_id( new_history.id ), 'name' : new_history.name } if new_history else None,
'scheduled' : invocation.state == trans.app.model.WorkflowInvocation.states.SCHEDULED })
trans.sa_session.flush()
return invocations
@expose_api
def create(self, trans, payload, **kwd):
"""
@@ -257,7 +193,9 @@ class WorkflowsAPIController(BaseAPIController, UsesStoredWorkflowMixin, UsesAnn
stored_workflow = self.__get_stored_accessible_workflow( trans, workflow_id )
workflow = stored_workflow.latest_workflow
run_config = build_workflow_run_config( trans, workflow, payload )
run_configs = build_workflow_run_configs( trans, workflow, payload )
assert len(run_configs) == 1
run_config = run_configs[0]
history = run_config.target_history
# invoke may throw MessageExceptions on tool erors, failure
@@ -499,21 +437,31 @@ class WorkflowsAPIController(BaseAPIController, UsesStoredWorkflowMixin, UsesAnn
# /usage is awkward in this context but is consistent with the rest of
# this module. Would prefer to redo it all to use /invocation(s).
# Get workflow + accessibility check.
stored_workflow = self.__get_stored_accessible_workflow( trans, workflow_id )
stored_workflow = self.__get_stored_accessible_workflow(trans, workflow_id)
workflow = stored_workflow.latest_workflow
run_configs = build_workflow_run_configs(trans, workflow, payload)
is_batch = payload.get('batch')
if not is_batch and len(run_configs) != 1:
raise exceptions.RequestParameterInvalidException("Must specify 'batch' to use batch parameters.")
run_config = build_workflow_run_config( trans, workflow, payload )
workflow_scheduler_id = payload.get( "scheduler", None )
# TODO: workflow scheduler hints
work_request_params = dict( scheduler=workflow_scheduler_id )
invocations = []
for run_config in run_configs:
workflow_scheduler_id = payload.get('scheduler', None)
# TODO: workflow scheduler hints
work_request_params = dict(scheduler=workflow_scheduler_id)
workflow_invocation = queue_invoke(
trans=trans,
workflow=workflow,
workflow_run_config=run_config,
request_params=work_request_params
)
invocation = self.encode_all_ids(trans, workflow_invocation.to_dict(), recursive=True)
invocations.append(invocation)
workflow_invocation = queue_invoke(
trans=trans,
workflow=workflow,
workflow_run_config=run_config,
request_params=work_request_params
)
return self.encode_all_ids( trans, workflow_invocation.to_dict(), recursive=True )
if is_batch:
return invocations
else:
return invocations[0]
@expose_api
def index_invocations(self, trans, workflow_id, **kwd):
-1
View File
@@ -277,7 +277,6 @@ def populate_api_routes( webapp, app ):
webapp.mapper.resource( 'genome', 'genomes', path_prefix='/api' )
webapp.mapper.resource( 'visualization', 'visualizations', path_prefix='/api' )
webapp.mapper.connect( '/api/workflows/build_module', action='build_module', controller="workflows" )
webapp.mapper.connect( '/api_internal/workflows/{workflow_id}/run', action='run', controller="workflows", conditions=dict( method=['POST'] ) )
webapp.mapper.resource( 'workflow', 'workflows', path_prefix='/api' )
webapp.mapper.resource_with_deleted( 'history', 'histories', path_prefix='/api' )
webapp.mapper.connect( '/api/histories/{history_id}/citations', action='citations', controller="histories" )
+2 -2
View File
@@ -1359,9 +1359,9 @@ def populate_module_and_state( trans, workflow, param_map, allow_tool_state_corr
step_errors = module_injector.inject( step, step_args=step_args )
if step.type == 'tool' or step.type is None:
if step_errors:
raise exceptions.MessageException( step_errors )
raise exceptions.MessageException( step_errors, err_data={ step.order_index: step_errors } )
if step.upgrade_messages:
if allow_tool_state_corrections:
log.debug( 'Workflow step "%i" had upgrade messages: %s', step.id, step.upgrade_messages )
else:
raise exceptions.MessageException( step.upgrade_messages )
raise exceptions.MessageException( step.upgrade_messages, err_data={ step.order_index: step.upgrade_messages } )
+1 -4
View File
@@ -110,10 +110,7 @@ def queue_invoke( trans, workflow, workflow_run_config, request_params={}, popul
modules.populate_module_and_state( trans, workflow, workflow_run_config.param_map, allow_tool_state_corrections=workflow_run_config.allow_tool_state_corrections )
workflow_invocation = workflow_run_config_to_request( trans, workflow_run_config, workflow )
workflow_invocation.workflow = workflow
return trans.app.workflow_scheduling_manager.queue(
workflow_invocation,
request_params
)
return trans.app.workflow_scheduling_manager.queue( workflow_invocation, request_params )
class WorkflowInvoker( object ):
+136 -133
View File
@@ -4,6 +4,7 @@ from galaxy import exceptions
from galaxy import model
from galaxy.managers import histories
from galaxy.tools.parameters.meta import expand_workflow_inputs
INPUT_STEP_TYPES = [ 'data_input', 'data_collection_input', 'parameter_input' ]
@@ -48,12 +49,11 @@ class WorkflowRunConfig( object ):
self.allow_tool_state_corrections = allow_tool_state_corrections
def normalize_inputs(steps, inputs, inputs_by):
def _normalize_inputs(steps, inputs, inputs_by):
normalized_inputs = {}
for step in steps:
if step.type not in INPUT_STEP_TYPES:
continue
possible_input_keys = []
for inputs_by_el in inputs_by.split("|"):
if inputs_by_el == "step_id":
@@ -71,17 +71,14 @@ def normalize_inputs(steps, inputs, inputs_by):
for possible_input_key in possible_input_keys:
if possible_input_key in inputs:
inputs_key = possible_input_key
if not inputs_key:
message = "Workflow cannot be run because an expected input step '%s' has no input dataset." % step.id
raise exceptions.MessageException( message )
normalized_inputs[ step.id ] = inputs[ inputs_key ]
return normalized_inputs
def normalize_step_parameters(steps, param_map, legacy=False):
def _normalize_step_parameters(steps, param_map, legacy=False, already_normalized=False):
""" Take a complex param_map that can reference parameters by
step_id in the new flexible way or in the old one-parameter
per tep fashion or by tool id and normalize the parameters so
@@ -89,7 +86,10 @@ def normalize_step_parameters(steps, param_map, legacy=False):
"""
normalized_param_map = {}
for step in steps:
param_dict = _step_parameters(step, param_map, legacy=legacy)
if already_normalized:
param_dict = param_map.get(str(step.order_index), {})
else:
param_dict = _step_parameters(step, param_map, legacy=legacy)
if param_dict:
normalized_param_map[step.id] = param_dict
return normalized_param_map
@@ -162,43 +162,41 @@ def _flatten_step_params( param_dict, prefix="" ):
return new_params
def build_workflow_run_config( trans, workflow, payload ):
app = trans.app
history_manager = histories.HistoryManager( app )
if "step_parameters" in payload and "parameters" in payload:
message = "Cannot specify both legacy parameters and step_parameters attributes."
raise exceptions.RequestParameterInvalidException( message )
if "inputs" in payload and "ds_map" in payload:
message = "Cannot specify both legacy ds_map and input attributes."
raise exceptions.RequestParameterInvalidException( message )
param_map = payload.get( 'parameters', {} )
legacy = payload.get("legacy", False)
param_map = normalize_step_parameters( workflow.steps, param_map, legacy=legacy )
inputs = payload.get( 'inputs', None )
inputs_by = payload.get( 'inputs_by', None )
# New default is to reference steps by index of workflow step
# which is intrinsic to the workflow and independent of the state
# of Galaxy at the time of workflow import.
default_inputs_by = 'step_index|step_uuid'
if inputs is None:
# Default to legacy behavior - read ds_map and reference steps
# by unencoded step id (a raw database id).
inputs = payload.get( 'ds_map', {} )
if legacy:
default_inputs_by = 'step_id|step_uuid'
inputs_by = inputs_by or default_inputs_by
def _get_target_history(trans, workflow, payload, param_keys=[], index=0):
history_name = payload.get('new_history_name', None)
history_id = payload.get('history_id', None)
history_param = payload.get('history', None)
if [ history_name, history_id, history_param ].count( None ) < 2:
raise exceptions.RequestParameterInvalidException("Specified workflow target history multiple ways - at most one of 'history', 'history_id', and 'new_history_name' may be specified.")
if history_param:
if history_param.startswith('hist_id='):
history_id = history_param[ 8: ]
else:
history_name = history_param
if history_id:
history_manager = histories.HistoryManager( trans.app )
target_history = history_manager.get_owned( trans.security.decode_id(history_id), trans.user, current_history=trans.history )
else:
inputs = inputs or {}
if history_name:
nh_name = history_name
else:
nh_name = 'History from %s workflow' % workflow.name
if len( param_keys ) <= index:
raise exceptions.MessageException("Incorrect expansion of workflow batch parameters.")
ids = param_keys[ index ]
nids = len( ids )
if nids == 1:
nh_name = '%s on %s' % ( nh_name, ids[ 0 ] )
elif nids > 1:
nh_name = '%s on %s and %s' % ( nh_name, ', '.join( ids[ 0:-1 ] ), ids[ -1 ] )
new_history = trans.app.model.History( user=trans.user, name=nh_name )
trans.sa_session.add( new_history )
target_history = new_history
return target_history
inputs_by = inputs_by or default_inputs_by
add_to_history = 'no_add_to_history' not in payload
history_param = payload.get('history', '')
def build_workflow_run_configs( trans, workflow, payload ):
app = trans.app
allow_tool_state_corrections = payload.get( 'allow_tool_state_corrections', False )
# Sanity checks.
@@ -207,104 +205,109 @@ def build_workflow_run_config( trans, workflow, payload ):
if workflow.has_cycles:
raise exceptions.MessageException( "Workflow cannot be run because it contains cycles" )
if workflow.has_errors:
message = "Workflow cannot be run because of validation errors in some steps"
raise exceptions.MessageException( message )
raise exceptions.MessageException( "Workflow cannot be run because of validation errors in some steps" )
# Get target history.
if history_param.startswith('hist_id='):
# Passing an existing history to use.
encoded_history_id = history_param[ 8: ]
history_id = __decode_id( trans, encoded_history_id, model_type="history" )
history = history_manager.get_owned( history_id, trans.user, current_history=trans.history )
else:
# Send workflow outputs to new history.
history = app.model.History(name=history_param, user=trans.user)
trans.sa_session.add(history)
trans.sa_session.flush()
if 'step_parameters' in payload and 'parameters' in payload:
raise exceptions.RequestParameterInvalidException( "Cannot specify both legacy parameters and step_parameters attributes." )
if 'inputs' in payload and 'ds_map' in payload:
raise exceptions.RequestParameterInvalidException( "Cannot specify both legacy ds_map and input attributes." )
normalized_inputs = normalize_inputs( workflow.steps, inputs, inputs_by )
steps_by_id = workflow.steps_by_id
add_to_history = 'no_add_to_history' not in payload
legacy = payload.get( 'legacy', False )
already_normalized = payload.get( 'parameters_normalized', False )
raw_parameters = payload.get( 'parameters', {} )
# Set workflow inputs.
for key, input_dict in normalized_inputs.iteritems():
step = steps_by_id[key]
if step.type == "parameter_input":
continue
if 'src' not in input_dict:
message = "Not input source type defined for input '%s'." % input_dict
raise exceptions.RequestParameterInvalidException( message )
if 'id' not in input_dict:
message = "Not input id defined for input '%s'." % input_dict
raise exceptions.RequestParameterInvalidException( message )
if 'content' in input_dict:
message = "Input cannot specify explicit 'content' attribute %s'." % input_dict
raise exceptions.RequestParameterInvalidException( message )
input_source = input_dict['src']
input_id = input_dict['id']
try:
if input_source == 'ldda':
ldda = trans.sa_session.query(app.model.LibraryDatasetDatasetAssociation).get(
trans.security.decode_id(input_id))
assert trans.user_is_admin() or trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), ldda.dataset )
content = ldda.to_history_dataset_association(history, add_to_history=add_to_history)
elif input_source == 'ld':
ldda = trans.sa_session.query(app.model.LibraryDataset).get(
trans.security.decode_id(input_id)).library_dataset_dataset_association
assert trans.user_is_admin() or trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), ldda.dataset )
content = ldda.to_history_dataset_association(history, add_to_history=add_to_history)
elif input_source == 'hda':
# Get dataset handle, add to dict and history if necessary
content = trans.sa_session.query(app.model.HistoryDatasetAssociation).get(
trans.security.decode_id(input_id))
assert trans.user_is_admin() or trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), content.dataset )
elif input_source == 'uuid':
dataset = trans.sa_session.query(app.model.Dataset).filter(app.model.Dataset.uuid == input_id).first()
if dataset is None:
# this will need to be changed later. If federation code is avalible, then a missing UUID
# could be found amoung fereration partners
message = "Input cannot find UUID: %s." % input_id
raise exceptions.RequestParameterInvalidException( message )
assert trans.user_is_admin() or trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), dataset )
content = history.add_dataset(dataset)
elif input_source == 'hdca':
content = app.dataset_collections_service.get_dataset_collection_instance(
trans,
'history',
input_id
)
else:
message = "Unknown workflow input source '%s' specified." % input_source
raise exceptions.RequestParameterInvalidException( message )
if add_to_history and content.history != history:
content = content.copy()
if isinstance( content, app.model.HistoryDatasetAssociation ):
history.add_dataset( content )
else:
history.add_dataset_collection( content )
input_dict['content'] = content
except AssertionError:
message = "Invalid workflow input '%s' specified" % input_id
raise exceptions.ItemAccessibilityException( message )
for key in set(normalized_inputs.keys()):
value = normalized_inputs[key]
if isinstance(value, dict) and 'content' in value:
normalized_inputs[key] = value['content']
run_configs = []
unexpanded_param_map = _normalize_step_parameters( workflow.steps, raw_parameters, legacy=legacy, already_normalized=already_normalized )
expanded_params, expanded_param_keys = expand_workflow_inputs( unexpanded_param_map )
for index, param_map in enumerate( expanded_params ):
history = _get_target_history(trans, workflow, payload, expanded_param_keys, index)
inputs = payload.get( 'inputs', None )
inputs_by = payload.get( 'inputs_by', None )
# New default is to reference steps by index of workflow step
# which is intrinsic to the workflow and independent of the state
# of Galaxy at the time of workflow import.
default_inputs_by = 'step_index|step_uuid'
if inputs is None:
# Default to legacy behavior - read ds_map and reference steps
# by unencoded step id (a raw database id).
inputs = payload.get( 'ds_map', {} )
if legacy:
default_inputs_by = 'step_id|step_uuid'
inputs_by = inputs_by or default_inputs_by
else:
normalized_inputs[key] = value
inputs = inputs or {}
inputs_by = inputs_by or default_inputs_by
if inputs or not already_normalized:
normalized_inputs = _normalize_inputs( workflow.steps, inputs, inputs_by )
else:
# Only allow dumping IDs directly into JSON database instead of properly recording the
# inputs with referential integrity if parameters are already normalized (coming from tool form).
normalized_inputs = {}
# Run each step, connecting outputs to inputs
replacement_dict = payload.get('replacement_params', {})
steps_by_id = workflow.steps_by_id
# Set workflow inputs.
for key, input_dict in normalized_inputs.iteritems():
step = steps_by_id[key]
if step.type == 'parameter_input':
continue
if 'src' not in input_dict:
raise exceptions.RequestParameterInvalidException( "Not input source type defined for input '%s'." % input_dict )
if 'id' not in input_dict:
raise exceptions.RequestParameterInvalidException( "Not input id defined for input '%s'." % input_dict )
if 'content' in input_dict:
raise exceptions.RequestParameterInvalidException( "Input cannot specify explicit 'content' attribute %s'." % input_dict )
input_source = input_dict[ 'src' ]
input_id = input_dict[ 'id' ]
try:
if input_source == 'ldda':
ldda = trans.sa_session.query( app.model.LibraryDatasetDatasetAssociation ).get( trans.security.decode_id( input_id ) )
assert trans.user_is_admin() or trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), ldda.dataset )
content = ldda.to_history_dataset_association( history, add_to_history=add_to_history )
elif input_source == 'ld':
ldda = trans.sa_session.query( app.model.LibraryDataset ).get( trans.security.decode_id( input_id ) ).library_dataset_dataset_association
assert trans.user_is_admin() or trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), ldda.dataset )
content = ldda.to_history_dataset_association( history, add_to_history=add_to_history )
elif input_source == 'hda':
# Get dataset handle, add to dict and history if necessary
content = trans.sa_session.query( app.model.HistoryDatasetAssociation ).get( trans.security.decode_id( input_id ) )
assert trans.user_is_admin() or trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), content.dataset )
elif input_source == 'uuid':
dataset = trans.sa_session.query( app.model.Dataset ).filter( app.model.Dataset.uuid == input_id ).first()
if dataset is None:
# this will need to be changed later. If federation code is avalible, then a missing UUID
# could be found amoung fereration partners
raise exceptions.RequestParameterInvalidException( "Input cannot find UUID: %s." % input_id )
assert trans.user_is_admin() or trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), dataset )
content = history.add_dataset( dataset )
elif input_source == 'hdca':
content = app.dataset_collections_service.get_dataset_collection_instance( trans, 'history', input_id )
else:
raise exceptions.RequestParameterInvalidException( "Unknown workflow input source '%s' specified." % input_source )
if add_to_history and content.history != history:
content = content.copy()
if isinstance( content, app.model.HistoryDatasetAssociation ):
history.add_dataset( content )
else:
history.add_dataset_collection( content )
input_dict[ 'content' ] = content
except AssertionError:
raise exceptions.ItemAccessibilityException( "Invalid workflow input '%s' specified" % input_id )
for key in set( normalized_inputs.keys() ):
value = normalized_inputs[ key ]
if isinstance( value, dict ) and 'content' in value:
normalized_inputs[ key ] = value[ 'content' ]
else:
normalized_inputs[ key ] = value
run_configs.append(WorkflowRunConfig(
target_history=history,
replacement_dict=payload.get( 'replacement_params', {} ),
inputs=normalized_inputs,
param_map=param_map,
allow_tool_state_corrections=allow_tool_state_corrections
))
run_config = WorkflowRunConfig(
target_history=history,
replacement_dict=replacement_dict,
inputs=normalized_inputs,
param_map=param_map,
allow_tool_state_corrections=allow_tool_state_corrections
)
return run_config
return run_configs
def workflow_run_config_to_request( trans, run_config, workflow ):
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"tool-form.js","sources":["../../../src/mvc/tool/tool-form.js"],"names":["define","Utils","Ui","Modal","ToolFormBase","View","Backbone","extend","initialize","options","self","this","modal","parent","Galaxy","form","merge","listen_to_history","always_refresh","customize","buttons","execute","execute_btn","Button","icon","tooltip","name","version","title","cls","floating","onclick","wait","portlet","disable","submit","unwait","enable","job_id","job_remap","inputs","label","type","display","ignore","value","help","deferred","setElement","$el","append","callback","job_def","tool_id","id","tool_version","data","create","trigger","validate","emit","debug","action","root","$f","$","attr","method","enctype","_","each","key","hide","appendTo","remove","request","url","success","response","children","_templateSuccess","currHistoryPanel","refreshContents","error","input_found","err_data","error_messages","matchResponse","input_id","highlight","show","body","err_msg","_templateError","Close","job_inputs","batch_n","batch_src","job_input_id","input_value","match","input_field","field_list","input_def","input_list","optional","batch","n","values","length","src","jobs","njobs","njobs_text","$message","addClass","text","outputs","output","hid","JSON","stringify"],"mappings":"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"}
{"version":3,"file":"tool-form.js","sources":["../../../src/mvc/tool/tool-form.js"],"names":["define","Utils","Ui","Modal","ToolFormBase","View","Backbone","extend","initialize","options","self","this","modal","parent","Galaxy","form","merge","listen_to_history","always_refresh","customize","buttons","execute","execute_btn","Button","icon","tooltip","name","version","title","cls","floating","onclick","wait","portlet","disable","submit","unwait","enable","job_id","job_remap","inputs","label","type","display","ignore","value","help","deferred","setElement","$el","append","callback","job_def","tool_id","id","tool_version","data","create","trigger","validate","emit","debug","action","root","$f","$","attr","method","enctype","_","each","key","hide","appendTo","remove","request","url","success","response","children","_templateSuccess","currHistoryPanel","refreshContents","error","input_found","err_data","error_messages","matchResponse","input_id","highlight","show","body","_templateError","err_msg","Close","job_inputs","batch_n","batch_src","job_input_id","input_value","match","input_field","field_list","input_def","input_list","optional","batch","n","values","length","src","jobs","njobs","njobs_text","$message","addClass","text","outputs","output","hid","JSON","stringify"],"mappings":"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"}
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
+1 -1
View File
@@ -1,2 +1,2 @@
define(["utils/utils","mvc/ui/ui-misc","mvc/ui/ui-modal","mvc/tool/tool-form-base"],function(a,b,c,d){var e=Backbone.View.extend({initialize:function(e){var f=this;this.modal=parent.Galaxy.modal||new c.View,this.form=new d(a.merge({listen_to_history:!0,always_refresh:!1,customize:function(a){a.buttons={execute:execute_btn=new b.Button({icon:"fa-check",tooltip:"Execute: "+a.name+" ("+a.version+")",title:"Execute",cls:"ui-button btn btn-primary",floating:"clear",onclick:function(){execute_btn.wait(),f.form.portlet.disable(),f.submit(a,function(){execute_btn.unwait(),f.form.portlet.enable()})}})},a.job_id&&a.job_remap&&(a.inputs.rerun_remap_job_id={label:"Resume dependencies from this job",name:"rerun_remap_job_id",type:"select",display:"radio",ignore:"__ignore__",value:"__ignore__",options:[["Yes",a.job_id],["No","__ignore__"]],help:"The previous run of this tool failed and other tools were waiting for it to finish successfully. Use this option to resume those tools using the new output(s) of this tool run."})}},e)),this.deferred=this.form.deferred,this.setElement("<div/>"),this.$el.append(this.form.$el)},submit:function(b,c){var d=this,e={tool_id:b.id,tool_version:b.version,inputs:this.form.data.create()};if(this.form.trigger("reset"),!d.validate(e))return Galaxy.emit.debug("tool-form::submit()","Submission canceled. Validation failed."),void(c&&c());if(b.action!==Galaxy.root+"tool_runner/index"){var f=$("<form/>").attr({action:b.action,method:b.method,enctype:b.enctype});return _.each(e.inputs,function(a,b){f.append($("<input/>").attr({name:b,value:a}))}),f.hide().appendTo("body").submit().remove(),void(c&&c())}Galaxy.emit.debug("tool-form::submit()","Validation complete.",e),a.request({type:"POST",url:Galaxy.root+"api/tools",data:e,success:function(a){c&&c(),d.$el.children().hide(),d.$el.append(d._templateSuccess(a)),parent.Galaxy&&parent.Galaxy.currHistoryPanel&&parent.Galaxy.currHistoryPanel.refreshContents()},error:function(a){c&&c(),Galaxy.emit.debug("tool-form::submit","Submission failed.",a);var b=!1;if(a&&a.err_data){var f=d.form.data.matchResponse(a.err_data);for(var g in f){d.form.highlight(g,f[g]),b=!0;break}}b||d.modal.show({title:"Job submission failed",body:a&&a.err_msg||d._templateError(e),buttons:{Close:function(){d.modal.hide()}}})}})},validate:function(a){var b=a.inputs,c=-1,d=null;for(var e in b){var f=b[e],g=this.form.data.match(e),h=this.form.field_list[g],i=this.form.input_list[g];if(g&&i&&h){if(!i.optional&&null==f)return this.form.highlight(g),!1;if(f&&f.batch){var j=f.values.length,k=j>0&&f.values[0]&&f.values[0].src;if(k)if(null===d)d=k;else if(d!==k)return this.form.highlight(g,"Please select either dataset or dataset list fields for all batch mode fields."),!1;if(-1===c)c=j;else if(c!==j)return this.form.highlight(g,"Please make sure that you select the same number of inputs for all batch mode fields. This field contains <b>"+j+"</b> selection(s) while a previous field contains <b>"+c+"</b>."),!1}}else Galaxy.emit.debug("tool-form::validate()","Retrieving input objects failed.")}return!0},_templateSuccess:function(a){if(a.jobs&&a.jobs.length>0){var b=a.jobs.length,c=1==b?"1 job has":b+" jobs have",d=$("<div/>").addClass("donemessagelarge").append($("<p/>").text(c+" been successfully added to the queue - resulting in the following datasets:"));return _.each(a.outputs,function(a){d.append($("<p/>").addClass("messagerow").append($("<b/>").text(a.hid+": "+a.name)))}),d.append($("<p/>").append("<b/>").text("You can check the status of queued jobs and view the resulting data by refreshing the History pane. When the job has been run the status will change from 'running' to 'finished' if completed successfully or 'error' if problems were encountered.")),d}return this._templateError(a)},_templateError:function(a){return $("<div/>").addClass("errormessagelarge").append($("<p/>").text("The server could not complete the request. Please contact the Galaxy Team if this error persists.")).append($("<pre/>").text(JSON.stringify(a,null,4)))}});return{View:e}});
define(["utils/utils","mvc/ui/ui-misc","mvc/ui/ui-modal","mvc/tool/tool-form-base"],function(a,b,c,d){var e=Backbone.View.extend({initialize:function(e){var f=this;this.modal=parent.Galaxy.modal||new c.View,this.form=new d(a.merge({listen_to_history:!0,always_refresh:!1,customize:function(a){a.buttons={execute:execute_btn=new b.Button({icon:"fa-check",tooltip:"Execute: "+a.name+" ("+a.version+")",title:"Execute",cls:"ui-button btn btn-primary",floating:"clear",onclick:function(){execute_btn.wait(),f.form.portlet.disable(),f.submit(a,function(){execute_btn.unwait(),f.form.portlet.enable()})}})},a.job_id&&a.job_remap&&(a.inputs.rerun_remap_job_id={label:"Resume dependencies from this job",name:"rerun_remap_job_id",type:"select",display:"radio",ignore:"__ignore__",value:"__ignore__",options:[["Yes",a.job_id],["No","__ignore__"]],help:"The previous run of this tool failed and other tools were waiting for it to finish successfully. Use this option to resume those tools using the new output(s) of this tool run."})}},e)),this.deferred=this.form.deferred,this.setElement("<div/>"),this.$el.append(this.form.$el)},submit:function(b,c){var d=this,e={tool_id:b.id,tool_version:b.version,inputs:this.form.data.create()};if(this.form.trigger("reset"),!d.validate(e))return Galaxy.emit.debug("tool-form::submit()","Submission canceled. Validation failed."),void(c&&c());if(b.action!==Galaxy.root+"tool_runner/index"){var f=$("<form/>").attr({action:b.action,method:b.method,enctype:b.enctype});return _.each(e.inputs,function(a,b){f.append($("<input/>").attr({name:b,value:a}))}),f.hide().appendTo("body").submit().remove(),void(c&&c())}Galaxy.emit.debug("tool-form::submit()","Validation complete.",e),a.request({type:"POST",url:Galaxy.root+"api/tools",data:e,success:function(a){c&&c(),d.$el.children().hide(),d.$el.append(d._templateSuccess(a)),parent.Galaxy&&parent.Galaxy.currHistoryPanel&&parent.Galaxy.currHistoryPanel.refreshContents()},error:function(a){c&&c(),Galaxy.emit.debug("tool-form::submit","Submission failed.",a);var b=!1;if(a&&a.err_data){var f=d.form.data.matchResponse(a.err_data);for(var g in f){d.form.highlight(g,f[g]),b=!0;break}}b||d.modal.show({title:"Job submission failed",body:d._templateError(e,a&&a.err_msg),buttons:{Close:function(){d.modal.hide()}}})}})},validate:function(a){var b=a.inputs,c=-1,d=null;for(var e in b){var f=b[e],g=this.form.data.match(e),h=this.form.field_list[g],i=this.form.input_list[g];if(g&&i&&h){if(!i.optional&&null==f)return this.form.highlight(g),!1;if(f&&f.batch){var j=f.values.length,k=j>0&&f.values[0]&&f.values[0].src;if(k)if(null===d)d=k;else if(d!==k)return this.form.highlight(g,"Please select either dataset or dataset list fields for all batch mode fields."),!1;if(-1===c)c=j;else if(c!==j)return this.form.highlight(g,"Please make sure that you select the same number of inputs for all batch mode fields. This field contains <b>"+j+"</b> selection(s) while a previous field contains <b>"+c+"</b>."),!1}}else Galaxy.emit.debug("tool-form::validate()","Retrieving input objects failed.")}return!0},_templateSuccess:function(a){if(a.jobs&&a.jobs.length>0){var b=a.jobs.length,c=1==b?"1 job has":b+" jobs have",d=$("<div/>").addClass("donemessagelarge").append($("<p/>").text(c+" been successfully added to the queue - resulting in the following datasets:"));return _.each(a.outputs,function(a){d.append($("<p/>").addClass("messagerow").append($("<b/>").text(a.hid+": "+a.name)))}),d.append($("<p/>").append("<b/>").text("You can check the status of queued jobs and view the resulting data by refreshing the History pane. When the job has been run the status will change from 'running' to 'finished' if completed successfully or 'error' if problems were encountered.")),d}return this._templateError(a,"Invalid success response. No jobs found.")},_templateError:function(a,b){return $("<div/>").addClass("errormessagelarge").append($("<p/>").text("The server could not complete the request. Please contact the Galaxy Team if this error persists. "+(b||""))).append($("<pre/>").text(JSON.stringify(a,null,4)))}});return{View:e}});
//# sourceMappingURL=../../../maps/mvc/tool/tool-form.js.map
+145
View File
@@ -0,0 +1,145 @@
{
"a_galaxy_workflow": "true",
"annotation": "",
"format-version": "0.1",
"name": "test",
"steps": {
"0": {
"annotation": "",
"content_id": null,
"id": 0,
"input_connections": {},
"inputs": [
{
"description": "",
"name": "Input Dataset"
}
],
"label": null,
"name": "Input dataset",
"outputs": [],
"position": {
"left": 200,
"top": 200
},
"tool_errors": null,
"tool_id": null,
"tool_state": "{\"name\": \"Input Dataset\"}",
"tool_version": null,
"type": "data_input",
"uuid": "ef60789e-60fd-4c5a-baa5-598aeac0b5dc",
"workflow_outputs": []
},
"1": {
"annotation": "",
"content_id": "addValue",
"id": 1,
"input_connections": {},
"inputs": [
{
"description": "runtime parameter for tool Add column",
"name": "input"
}
],
"label": null,
"name": "Add column",
"outputs": [
{
"name": "out_file1",
"type": "input"
}
],
"position": {
"left": 204,
"top": 319
},
"post_job_actions": {},
"tool_errors": null,
"tool_id": "addValue",
"tool_state": "{\"__page__\": 0, \"__rerun_remap_job_id__\": null, \"__job_resource\": \"{\\\"__current_case__\\\": 0, \\\"__job_resource__select\\\": \\\"no\\\"}\", \"exp\": \"\\\"1\\\"\", \"iterate\": \"\\\"no\\\"\", \"input\": \"{\\\"__class__\\\": \\\"RuntimeValue\\\"}\"}",
"tool_version": "1.0.0",
"type": "tool",
"uuid": "1daceb2a-719c-49a6-881c-5301076de918",
"workflow_outputs": []
},
"2": {
"annotation": "",
"content_id": "addValue",
"id": 2,
"input_connections": {
"input": {
"id": 0,
"output_name": "output"
}
},
"inputs": [
{
"description": "runtime parameter for tool Add column",
"name": "input"
}
],
"label": null,
"name": "Add column",
"outputs": [
{
"name": "out_file1",
"type": "input"
}
],
"position": {
"left": 418,
"top": 234
},
"post_job_actions": {},
"tool_errors": null,
"tool_id": "addValue",
"tool_state": "{\"__page__\": 0, \"__rerun_remap_job_id__\": null, \"__job_resource\": \"{\\\"__current_case__\\\": 0, \\\"__job_resource__select\\\": \\\"no\\\"}\", \"exp\": \"\\\"1\\\"\", \"iterate\": \"\\\"no\\\"\", \"input\": \"{\\\"__class__\\\": \\\"RuntimeValue\\\"}\"}",
"tool_version": "1.0.0",
"type": "tool",
"uuid": "f5349127-d008-44b2-a41e-af024de92d2e",
"workflow_outputs": []
},
"3": {
"annotation": "",
"content_id": "cat1",
"id": 3,
"input_connections": {
"input1": {
"id": 2,
"output_name": "out_file1"
},
"queries_0|input2": {
"id": 1,
"output_name": "out_file1"
}
},
"inputs": [
{
"description": "runtime parameter for tool Concatenate datasets",
"name": "input1"
}
],
"label": null,
"name": "Concatenate datasets",
"outputs": [
{
"name": "out_file1",
"type": "input"
}
],
"position": {
"left": 389.5,
"top": 396
},
"post_job_actions": {},
"tool_errors": null,
"tool_id": "cat1",
"tool_state": "{\"__job_resource\": \"{\\\"__current_case__\\\": 0, \\\"__job_resource__select\\\": \\\"no\\\"}\", \"__page__\": 0, \"__rerun_remap_job_id__\": null, \"input1\": \"{\\\"__class__\\\": \\\"RuntimeValue\\\"}\", \"queries\": \"[{\\\"input2\\\": {\\\"__class__\\\": \\\"RuntimeValue\\\"}, \\\"__index__\\\": 0}]\"}",
"tool_version": "1.0.0",
"type": "tool",
"uuid": "32205465-a47e-4d8a-aa45-2560b1a38f54",
"workflow_outputs": []
}
},
"uuid": "9f791470-2fca-4f63-aa18-72ae0211b077"
}
+24
View File
@@ -1412,6 +1412,30 @@ test_data:
self.__assert_lines_hid_line_count_is( history_id, 2, 4 )
self.__assert_lines_hid_line_count_is( history_id, 3, 3 )
@skip_without_tool( "cat1" )
@skip_without_tool( "addValue" )
def test_run_batch( self ):
workflow = self.workflow_populator.load_workflow_from_resource( "test_workflow_batch" )
workflow_id = self.workflow_populator.create_workflow( workflow )
history_id = self.dataset_populator.new_history()
hda1 = self.dataset_populator.new_dataset( history_id, content="1 2 3" )
hda2 = self.dataset_populator.new_dataset( history_id, content="4 5 6" )
workflow_request = {
"history_id" : history_id,
"batch" : True,
"parameters_normalized": True,
"parameters" : dumps( { "0": { "input": { "batch": True, "values": [ { "id" : hda1.get( "id" ), "hid": hda1.get( "hid" ), "src": "hda" }, { "id" : hda2.get( "id" ), "hid": hda2.get( "hid" ), "src": "hda" } ] } }, "1": { "input": { "batch": False, "values": [ { "id" : hda1.get( "id" ), "hid": hda1.get( "hid" ), "src": "hda" } ] }, "exp": "2" } } )
}
invocation_response = self._post( "workflows/%s/usage" % workflow_id, data=workflow_request )
self._assert_status_code_is( invocation_response, 200 )
time.sleep( 5 )
self.dataset_populator.wait_for_history( history_id, assert_ok=True )
r1 = "1 2 3\t1\n1 2 3\t2\n"
r2 = "4 5 6\t1\n1 2 3\t2\n"
t1 = self.dataset_populator.get_history_dataset_content( history_id, hid=5 )
t2 = self.dataset_populator.get_history_dataset_content( history_id, hid=8 )
assert ( r1 == t1 and r2 == t2 ) or ( r1 == t2 and r2 == t1 )
@skip_without_tool( "validation_default" )
def test_parameter_substitution_sanitization( self ):
substitions = dict( input1="\" ; echo \"moo" )
+4 -4
View File
@@ -1,8 +1,8 @@
from .workflow_support import MockTrans
from galaxy import model
from galaxy.workflow.run_request import normalize_step_parameters
from galaxy.workflow.run_request import normalize_inputs
from galaxy.workflow.run_request import _normalize_step_parameters
from galaxy.workflow.run_request import _normalize_inputs
STEP_ID_OFFSET = 4 # Offset a little so ids and order index are different.
@@ -78,7 +78,7 @@ def __normalize_parameters_against_fixture( params ):
__workflow_fixure( trans )
workflow = __workflow_fixure( trans )
normalized_params = normalize_step_parameters( workflow.steps, params, legacy=True )
normalized_params = _normalize_step_parameters( workflow.steps, params, legacy=True )
return normalized_params
@@ -89,7 +89,7 @@ def __normalize_inputs_against_fixture( inputs, inputs_by ):
__workflow_fixure( trans )
workflow = __workflow_fixure( trans )
normalized_inputs = normalize_inputs( workflow.steps, inputs, inputs_by )
normalized_inputs = _normalize_inputs( workflow.steps, inputs, inputs_by )
return normalized_inputs