Skip to content

Commit

Permalink
Merge branch 'inject_connected_inputs' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
dannon committed Aug 3, 2016
2 parents 66d5560 + efc850c commit 24573f7
Show file tree
Hide file tree
Showing 16 changed files with 92 additions and 94 deletions.
22 changes: 12 additions & 10 deletions client/galaxy/scripts/mvc/tool/tool-form-composite.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ define([ 'utils/utils', 'utils/deferred', 'mvc/ui/ui-misc', 'mvc/form/form-view'
_refresh: function() {
var margin = _.reduce( this.$el.children(), function( memo, child ) {
return memo + $( child ).outerHeight();
}, 0 ) - this.$steps.height() + 30;
}, 0 ) - this.$steps.height() + 25;
this.$steps.css( 'height', $( window ).height() - margin );
},

Expand Down Expand Up @@ -56,7 +56,9 @@ define([ 'utils/utils', 'utils/deferred', 'mvc/ui/ui-misc', 'mvc/form/form-view'
errors : step.messages,
initial_errors : true,
cls : 'ui-portlet-narrow',
hide_operations : true
hide_operations : true,
needs_refresh : false,
always_refresh : step.step_type != 'tool'
}, step );
self.steps[ i ] = step;
self.links[ i ] = [];
Expand Down Expand Up @@ -167,7 +169,7 @@ define([ 'utils/utils', 'utils/deferred', 'mvc/ui/ui-misc', 'mvc/form/form-view'
this._renderHistory();
_.each ( this.steps, function( step, i ) { self._renderStep( step, i ) } );
this.deferred.execute( function() { self.execute_btn.unwait();
self.execute_btn.model.set( { wait_text: 'Sending...', percentage: -1 } ) } );
self.execute_btn.model.set( { wait_text: 'Sending...', percentage: -1 } ); } );
},

/** Render header */
Expand All @@ -193,7 +195,8 @@ define([ 'utils/utils', 'utils/deferred', 'mvc/ui/ui-misc', 'mvc/form/form-view'
this.$message.append( new Ui.Message( {
message : 'Some tools in this workflow may have changed since it was last saved or some errors were found. The workflow may still run, but any new options will have default values. Please review the messages below to make a decision about whether the changes will affect your analysis.',
status : 'warning',
persistent : true
persistent : true,
fade : false
} ).$el );
}
},
Expand All @@ -205,9 +208,7 @@ define([ 'utils/utils', 'utils/deferred', 'mvc/ui/ui-misc', 'mvc/form/form-view'
if ( !_.isEmpty( this.wp_inputs ) ) {
this.wp_form = new Form({ title: '<b>Workflow Parameters</b>', inputs: this.wp_inputs, cls: 'ui-portlet-narrow', onchange: function() {
_.each( self.wp_form.input_list, function( input_def, i ) {
_.each( input_def.links, function( step ) {
self._refreshStep( step );
});
_.each( input_def.links, function( step ) { self._refreshStep( step ) } );
});
}
});
Expand Down Expand Up @@ -266,17 +267,16 @@ define([ 'utils/utils', 'utils/deferred', 'mvc/ui/ui-misc', 'mvc/form/form-view'
}, '' ) ) )
);
}
self._append( self.$steps, form.$el );
} else {
_.each( step.inputs, function( input ) { input.flavor = 'module' } );
form = new Form( Utils.merge({
title : '<b>' + step.name + '</b>',
onchange : function() { _.each( self.links[ i ], function( link ) { self._refreshStep( link ) } ) }
}, step ) );
self._append( self.$steps, form.$el );
}
self.forms[ i ] = form;
self._refreshStep( step );
self._append( self.$steps, form.$el );
step.needs_refresh && self._refreshStep( step );
self._resolve( form.deferred, promise );
self.execute_btn.model.set( 'percentage', ( i + 1 ) * 100.0 / self.steps.length );
Galaxy.emit.debug( 'tool-form-composite::initialize()', i + ' : Workflow step state ready.', step );
Expand Down Expand Up @@ -327,6 +327,8 @@ define([ 'utils/utils', 'utils/deferred', 'mvc/ui/ui-misc', 'mvc/form/form-view'
}
});
form.trigger( 'change' );
} else {
step.needs_refresh = true;
}
},

Expand Down
5 changes: 3 additions & 2 deletions client/galaxy/scripts/mvc/ui/ui-misc.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ define(['utils/utils',
message : null,
status : 'info',
cls : '',
persistent : false
persistent : false,
fade : true
}).set( options );
this.listenTo( this.model, 'change', this.render, this );
this.render();
Expand All @@ -62,7 +63,7 @@ define(['utils/utils',
}
if ( this.model.get( 'message' ) ) {
this.$el.html( this.model.get( 'message' ) );
this.$el.fadeIn();
this.$el[ this.model.get( 'fade' ) ? 'fadeIn' : 'show' ]();
this.timeout && window.clearTimeout( this.timeout );
if ( !this.model.get( 'persistent' ) ) {
var self = this;
Expand Down
9 changes: 9 additions & 0 deletions lib/galaxy/model/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3309,6 +3309,15 @@ def type_id( cls ):
return (( type_coerce( cls.content_type, types.Unicode ) + u'-' +
type_coerce( cls.id, types.Unicode ) ).label( 'type_id' ))

def to_hda_representative( self, multiple=False ):
rval = []
for dataset in self.collection.dataset_elements:
rval.append( dataset.dataset_instance )
if multiple is False:
break
if len( rval ) > 0:
return rval if multiple else rval[ 0 ]

def to_dict( self, view='collection' ):
dict_value = dict(
hid=self.hid,
Expand Down
73 changes: 22 additions & 51 deletions lib/galaxy/tools/parameters/basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,16 +114,6 @@ def get_initial_value( self, trans, other_values ):
"""
return None

def get_initial_value_from_history_prevent_repeats( self, trans, other_values, already_used ):
"""
Get the starting value for the parameter, but if fetching from the history, try
to find a value that has not yet been used. already_used is a list of objects that
tools must manipulate (by adding to it) to store a memento that they can use to detect
if a value has already been chosen from the history. This is to support the capability to
choose each dataset once
"""
return self.get_initial_value( trans, other_values )

def get_required_enctype( self ):
"""
If this parameter needs the form to have a specific encoding
Expand Down Expand Up @@ -1202,10 +1192,12 @@ def get_column_list( self, trans, other_values ):
return []
column_list = None
for dataset in util.listify( dataset ):
# Use representative dataset if a dataset collection is parsed
if isinstance( dataset, trans.app.model.HistoryDatasetCollectionAssociation ):
dataset = dataset.to_hda_representative()
# Columns can only be identified if metadata is available
if not hasattr( dataset, 'metadata' ) or not hasattr( dataset.metadata, 'columns' ) or not dataset.metadata.columns:
return []

# Build up possible columns for this dataset
this_column_list = []
if self.numerical:
Expand All @@ -1216,7 +1208,6 @@ def get_column_list( self, trans, other_values ):
else:
for i in range( 0, dataset.metadata.columns ):
this_column_list.append( str( i + 1 ) )

# Take the intersection of these columns with the other columns.
if column_list is None:
column_list = this_column_list
Expand Down Expand Up @@ -1668,6 +1659,25 @@ def _parse_options( self, input_source ):
self.options_filter_attribute = options_elem.get( 'options_filter_attribute', None )
self.is_dynamic = self.options is not None

def get_initial_value( self, trans, other_values ):
if trans.workflow_building_mode is workflow_building_modes.ENABLED or trans.app.name == 'tool_shed':
return RuntimeValue()
if self.optional:
return None
history = trans.history
if history is not None:
dataset_matcher = DatasetMatcher( trans, self, None, other_values )
if isinstance( self, DataToolParameter ):
for hda in reversed( history.active_datasets_children_and_roles ):
match = dataset_matcher.hda_match( hda )
if match:
return match.hda
else:
dataset_collection_matcher = DatasetCollectionMatcher( dataset_matcher )
for hdca in reversed( history.active_dataset_collections ):
if dataset_collection_matcher.hdca_match( hdca, reduction=self.multiple ):
return hdca

def to_json( self, value, app ):
def single_to_json( value ):
src = None
Expand All @@ -1681,7 +1691,6 @@ def single_to_json( value ):
src = 'hda'
if src is not None:
return { 'id' : app.security.encode_id( value.id ), 'src' : src }

if value not in [ None, '', 'None' ]:
if isinstance( value, list ) and len( value ) > 0:
values = [ single_to_json( v ) for v in value ]
Expand Down Expand Up @@ -1830,44 +1839,6 @@ def dataset_collector( hdas, parent_hid ):
for item in dataset_collector( history.active_datasets_children_and_roles, None ):
yield item

def get_initial_value( self, trans, other_values ):
return self.get_initial_value_from_history_prevent_repeats(trans, other_values, None )

def get_initial_value_from_history_prevent_repeats( self, trans, other_values, already_used ):
"""
NOTE: This is wasteful since dynamic options and dataset collection
happens twice (here and when generating HTML).
"""
# Can't look at history in workflow mode. Tool shed has no histories.
if trans.workflow_building_mode is workflow_building_modes.ENABLED or trans.app.name == 'tool_shed':
return RuntimeValue()
history = self._get_history( trans )
dataset_matcher = DatasetMatcher( trans, self, None, other_values )
if self.optional:
return None
most_recent_dataset = []

def dataset_collector( datasets ):
for data in datasets:
if data.visible and dataset_matcher.hda_accessible( data, check_security=False ):
match = dataset_matcher.valid_hda_match( data, check_security=False )
if not match or dataset_matcher.filter( match.hda ):
continue
data = match.hda
most_recent_dataset.append(data)
# Also collect children via association object
dataset_collector( data.children )
dataset_collector( history.active_datasets_children_and_roles )
most_recent_dataset.reverse()
if already_used is not None:
for val in most_recent_dataset:
if val is not None and val not in already_used:
already_used.append(val)
return val
if len(most_recent_dataset) > 0:
return most_recent_dataset[0]
return ''

def from_json( self, value, trans, other_values={} ):
if trans.workflow_building_mode is workflow_building_modes.ENABLED:
return None
Expand Down
10 changes: 7 additions & 3 deletions lib/galaxy/tools/parameters/dynamic_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import os
import validation
from galaxy.util import string_as_bool
from galaxy.model import User
from galaxy.model import User, HistoryDatasetAssociation, HistoryDatasetCollectionAssociation
import galaxy.tools

log = logging.getLogger(__name__)
Expand Down Expand Up @@ -125,10 +125,12 @@ def compare_meta_value( file_value, dataset_value ):
return dataset_value in file_value.split( self.separator )
return file_value == dataset_value
ref = other_values.get( self.ref_name, None )
if isinstance( ref, HistoryDatasetCollectionAssociation ):
ref = ref.to_hda_representative( self.multiple )
is_data = isinstance( ref, galaxy.tools.wrappers.DatasetFilenameWrapper )
is_data_list = isinstance( ref, galaxy.tools.wrappers.DatasetListWrapper ) or isinstance( ref, list )
is_data_or_data_list = is_data or is_data_list
if not isinstance( ref, self.dynamic_option.tool_param.tool.app.model.HistoryDatasetAssociation ) and not is_data_or_data_list:
if not isinstance( ref, HistoryDatasetAssociation ) and not is_data_or_data_list:
return [] # not a valid dataset

if is_data_list:
Expand Down Expand Up @@ -398,7 +400,9 @@ def compare_value( option_value, filter_value ):
value = other_values.get( self.ref_name )
else:
data_ref = other_values.get( self.meta_ref )
if not isinstance( data_ref, self.dynamic_option.tool_param.tool.app.model.HistoryDatasetAssociation ) and not isinstance( data_ref, galaxy.tools.wrappers.DatasetFilenameWrapper ):
if isinstance( data_ref, HistoryDatasetCollectionAssociation ):
data_ref = data_ref.to_hda_representative()
if not isinstance( data_ref, HistoryDatasetAssociation ) and not isinstance( data_ref, galaxy.tools.wrappers.DatasetFilenameWrapper ):
return options # cannot modify options
value = data_ref.metadata.get( self.metadata_key, None )
return [ ( disp_name, optval, selected ) for disp_name, optval, selected in options if not compare_value( optval, value ) ]
Expand Down
2 changes: 1 addition & 1 deletion lib/galaxy/webapps/galaxy/controllers/workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -1135,7 +1135,7 @@ def run( self, trans, id, history_id=None, hide_fixed_params=False, **kwargs ):
trans.workflow_building_mode = workflow_building_modes.USE_HISTORY
for step in workflow.steps:
try:
module_injector.inject( step )
module_injector.inject( step, steps=workflow.steps )
except MissingToolException:
if step.tool_id not in missing_tools:
missing_tools.append(step.tool_id)
Expand Down
35 changes: 24 additions & 11 deletions lib/galaxy/workflow/modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from galaxy.tools.parameters.wrapped import make_dict_copy
from galaxy.tools import DefaultToolState
from galaxy.tools import ToolInputsNotReadyException
from galaxy.util import odict
from galaxy.util import odict, listify
from galaxy.util.bunch import Bunch
from galaxy.web.framework import formbuilder
from tool_shed.util import common_util
Expand Down Expand Up @@ -132,7 +132,7 @@ def check_and_update_state( self ):
"""
pass

def add_dummy_datasets( self, connections=None):
def add_dummy_datasets( self, connections=None, steps=None ):
# Replaced connected inputs with DummyDataset values.
pass

Expand Down Expand Up @@ -417,7 +417,7 @@ def check_and_update_state( self ):
"""
return None

def add_dummy_datasets( self, connections=None):
def add_dummy_datasets( self, connections=None, steps=None ):
# Replaced connected inputs with DummyDataset values.
return None

Expand Down Expand Up @@ -1139,22 +1139,35 @@ def _handle_post_job_actions( self, step, job, replacement_dict ):
if flush_required:
self.trans.sa_session.flush()

def add_dummy_datasets( self, connections=None):
def add_dummy_datasets( self, connections=None, steps=None ):
if connections:
# Store onnections by input name
input_connections_by_name = \
dict( ( conn.input_name, conn ) for conn in connections )
input_connections_by_name = dict( ( conn.input_name, conn ) for conn in connections )
else:
input_connections_by_name = {}

# Any connected input needs to have value RuntimeValue (these
# are not persisted so we need to do it every time)
def callback( input, prefixed_name, context, **kwargs ):
if isinstance( input, DataToolParameter ) or isinstance( input, DataCollectionToolParameter ):
if connections is None or prefixed_name in input_connections_by_name:
if self.trans.workflow_building_mode is workflow_building_modes.USE_HISTORY:
if connections is None or prefixed_name in input_connections_by_name:
if steps:
connection = input_connections_by_name[ prefixed_name ]
output_step = next( output_step for output_step in steps if connection.output_step_id == output_step.id )
if output_step.type.startswith( 'data' ):
output_inputs = output_step.module.get_runtime_inputs()
output_value = output_inputs[ 'input' ].get_initial_value( self.trans, context )
if isinstance( input, DataToolParameter ):
for v in listify( output_value ):
if isinstance( v, self.trans.app.model.HistoryDatasetCollectionAssociation ):
return v.to_hda_representative()
return output_value
return RuntimeValue()
else:
return input.get_initial_value( self.trans, context )
elif connections is None or prefixed_name in input_connections_by_name:
return RuntimeValue()
elif self.trans.workflow_building_mode is workflow_building_modes.USE_HISTORY:
return input.get_initial_value( self.trans, context )

visit_input_values( self.tool.inputs, self.state.inputs, callback )

Expand Down Expand Up @@ -1289,7 +1302,7 @@ def __init__( self, trans, allow_tool_state_corrections=False ):
self.trans = trans
self.allow_tool_state_corrections = allow_tool_state_corrections

def inject( self, step, step_args=None ):
def inject( self, step, step_args=None, steps=None ):
""" Pre-condition: `step` is an ORM object coming from the database, if
supplied `step_args` is the representation of the inputs for that step
supplied via web form.
Expand Down Expand Up @@ -1319,7 +1332,7 @@ def inject( self, step, step_args=None ):

# Any connected input needs to have value DummyDataset (these
# are not persisted so we need to do it every time)
module.add_dummy_datasets( connections=step.input_connections )
module.add_dummy_datasets( connections=step.input_connections, steps=steps )
state, step_errors = module.compute_runtime_state( self.trans, step_args )
step.state = state
if step.type == "subworkflow":
Expand Down

0 comments on commit 24573f7

Please sign in to comment.