mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
Merge pull request #2969 from guerler/unite_api
Unite workflow execution api endpoints
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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 ) ) );
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 ):
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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" )
|
||||
|
||||
@@ -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 } )
|
||||
|
||||
@@ -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
@@ -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 @@
|
||||
{"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,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
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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" )
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user