Skip to content

Commit

Permalink
Merge pull request #1308 from jmchilton/multi_collection_types
Browse files Browse the repository at this point in the history
Allow input collections to specify multiple collection types.
  • Loading branch information
hexylena committed Jan 4, 2016
2 parents 4c0bb99 + 8af5671 commit 5a44104
Show file tree
Hide file tree
Showing 10 changed files with 77 additions and 44 deletions.
39 changes: 25 additions & 14 deletions client/galaxy/scripts/mvc/workflow/workflow-terminals.js
Expand Up @@ -396,11 +396,15 @@ define(['mvc/workflow/workflow-globals'], function( Globals ) {
this.multiple = false;
this.collection = true;
this.datatypes = input.extensions;
if( input.collection_type ) {
this.collectionType = new CollectionTypeDescription( input.collection_type );
var collectionTypes = [];
if( input.collection_types ) {
_.each(input.collection_types, function(collectionType) {
collectionTypes.push( new CollectionTypeDescription( collectionType ) );
});
} else {
this.collectionType = ANY_COLLECTION_TYPE_DESCRIPTION;
collectionTypes.push(ANY_COLLECTION_TYPE_DESCRIPTION);
}
this.collectionTypes = collectionTypes;
},
connect: function( connector ) {
BaseInputTerminal.prototype.connect.call( this, connector );
Expand All @@ -413,32 +417,39 @@ define(['mvc/workflow/workflow-globals'], function( Globals ) {
this.setMapOver( effectiveMapOver );
},
_effectiveMapOver: function( other ) {
var collectionType = this.collectionType;
var collectionTypes = this.collectionTypes;
var otherCollectionType = this._otherCollectionType( other );
if( ! collectionType.canMatch( otherCollectionType ) ) {
return otherCollectionType.effectiveMapOver( collectionType );
} else {
return NULL_COLLECTION_TYPE_DESCRIPTION;
var canMatch = _.some(collectionTypes, function( collectionType) { return collectionType.canMatch( otherCollectionType ); });

if( ! canMatch ) {
for( var collectionTypeIndex in collectionTypes ) {
var collectionType = collectionTypes[collectionTypeIndex];
var effectiveMapOver = otherCollectionType.effectiveMapOver( collectionType );
if( effectiveMapOver != NULL_COLLECTION_TYPE_DESCRIPTION ) {
return effectiveMapOver;
}
}
}
return NULL_COLLECTION_TYPE_DESCRIPTION;
},
_effectiveCollectionType: function( ) {
var collectionType = this.collectionType;
_effectiveCollectionTypes: function( ) {
var thisMapOver = this.mapOver();
return thisMapOver.append( collectionType );
return _.map(this.collectionTypes, function(t) { return thisMapOver.append(t); });
},
attachable: function ( other ) {
var otherCollectionType = this._otherCollectionType( other );
if( otherCollectionType.isCollection ) {
var effectiveCollectionType = this._effectiveCollectionType( );
var effectiveCollectionTypes = this._effectiveCollectionTypes( );
var thisMapOver = this.mapOver();
if( effectiveCollectionType.canMatch( otherCollectionType ) ) {
var canMatch = _.some(effectiveCollectionTypes, function( effectiveCollectionType) { return effectiveCollectionType.canMatch( otherCollectionType ); });
if( canMatch ) {
// Only way a direct match...
return this._producesAcceptableDatatype( other );
// Otherwise we need to mapOver
} else if( thisMapOver.isCollection ) {
// In this case, mapOver already set and we didn't match skipping...
return false;
} else if( otherCollectionType.canMapOver( this.collectionType ) ) {
} else if( _.some(this.collectionTypes, function(collectionType) { return otherCollectionType.canMapOver( collectionType ); }) ) {
var effectiveMapOver = this._effectiveMapOver( other );
if( ! effectiveMapOver.isCollection ) {
return false;
Expand Down
4 changes: 4 additions & 0 deletions lib/galaxy/dataset_collections/type_description.py
Expand Up @@ -102,6 +102,10 @@ def rank_collection_type( self ):
def rank_type_plugin( self ):
return self.collection_type_description_factory.type_registry.get( self.rank_collection_type() )

@property
def dimension( self ):
return len(self.collection_type.split(":")) + 1

def multiply( self, other_collection_type ):
collection_type = map_over_collection_type( self, other_collection_type )
return self.collection_type_description_factory.for_collection_type( collection_type )
Expand Down
9 changes: 6 additions & 3 deletions lib/galaxy/tools/parameters/basic.py
Expand Up @@ -2250,14 +2250,17 @@ def __init__( self, tool, input_source, trans=None ):
input_source = ensure_input_source( input_source )
super(DataCollectionToolParameter, self).__init__( tool, input_source, trans )
self._parse_formats( trans, tool, input_source )
self._collection_type = input_source.get("collection_type", None)
collection_types = input_source.get("collection_type", None)
if collection_types:
collection_types = [t.strip() for t in collection_types.split(",")]
self._collection_types = collection_types
self.multiple = False # Accessed on DataToolParameter a lot, may want in future
self.is_dynamic = True
self._parse_options( input_source ) # TODO: Review and test.

@property
def collection_type( self ):
return self._collection_type
def collection_types( self ):
return self._collection_types

def _history_query( self, trans ):
dataset_collection_type_descriptions = trans.app.dataset_collections_service.collection_type_descriptions
Expand Down
35 changes: 24 additions & 11 deletions lib/galaxy/tools/parameters/history_query.py
Expand Up @@ -8,31 +8,44 @@ class HistoryQuery( object ):
"""

def __init__( self, **kwargs ):
self.collection_type_description = kwargs.get( "collection_type_description", None )
self.collection_type_descriptions = kwargs.get( "collection_type_descriptions", None )

@staticmethod
def from_parameter( param, collection_type_descriptions ):
""" Take in a tool parameter element.
"""
collection_type = param.collection_type
if collection_type:
collection_type_description = collection_type_descriptions.for_collection_type( collection_type )
collection_types = param.collection_types
if collection_types:
collection_type_descriptions = [collection_type_descriptions.for_collection_type(t) for t in collection_types]
# Place higher dimension descriptions first so subcollection mapping
# (until we expose it to the user) will default to providing tool as much
# data as possible. So a list:list:paired mapped to a tool that takes
# list,paired,list:paired - will map over list:paired and create a flat list.
collection_type_descriptions = sorted(collection_type_descriptions, lambda t: t.dimension, reverse=True )
else:
collection_type_description = None
kwargs = dict( collection_type_description=collection_type_description )
collection_type_descriptions = None

kwargs = dict( collection_type_descriptions=collection_type_descriptions )
return HistoryQuery( **kwargs )

def direct_match( self, hdca ):
collection_type_description = self.collection_type_description
if collection_type_description and not collection_type_description.can_match_type( hdca.collection.collection_type ):
collection_type_descriptions = self.collection_type_descriptions
if collection_type_descriptions is not None:
for collection_type_description in collection_type_descriptions:
if collection_type_description.can_match_type( hdca.collection.collection_type ):
return True
return False

return True

def can_map_over( self, hdca ):
collection_type_description = self.collection_type_description
if not collection_type_description:
collection_type_descriptions = self.collection_type_descriptions
if collection_type_descriptions is None:
return False

hdca_collection_type = hdca.collection.collection_type
return collection_type_description.is_subcollection_of_type( hdca_collection_type )
for collection_type_description in collection_type_descriptions:
# See note about the way this is sorted above.
if collection_type_description.is_subcollection_of_type( hdca_collection_type ):
return collection_type_description
return False
7 changes: 4 additions & 3 deletions lib/galaxy/workflow/modules.py
Expand Up @@ -974,7 +974,7 @@ def callback( input, value, prefixed_name, prefixed_label ):
label=prefixed_label,
multiple=input.multiple,
input_type="dataset_collection",
collection_type=input.collection_type,
collection_types=input.collection_types,
extensions=input.extensions,
) )

Expand Down Expand Up @@ -1202,8 +1202,9 @@ def callback( input, value, prefixed_name, prefixed_label ):
if is_data_collection_param and not input.multiple:
data = progress.replacement_for_tool_input( step, input, prefixed_name )
history_query = input._history_query( self.trans )
if history_query.can_map_over( data ):
collections_to_match.add( prefixed_name, data, subcollection_type=input.collection_type )
subcollection_type_description = history_query.can_map_over( data )
if subcollection_type_description:
collections_to_match.add( prefixed_name, data, subcollection_type=subcollection_type_description.collection_type )

visit_input_values( tool.inputs, step.state.inputs, callback )
return collections_to_match
Expand Down
2 changes: 1 addition & 1 deletion static/maps/mvc/workflow/workflow-terminals.js.map

Large diffs are not rendered by default.

0 comments on commit 5a44104

Please sign in to comment.