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