From 87d5063a0dff35d6cddda3f17a8cadb6b04ff5e9 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Mon, 21 Sep 2015 15:48:56 +0100 Subject: [PATCH] Implement min/max for multiple data input parameters. --- lib/galaxy/tools/parameters/basic.py | 44 +++++++++++++++++++--- test/api/test_tools.py | 13 +++++++ test/functional/tools/multi_data_param.xml | 2 +- 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/lib/galaxy/tools/parameters/basic.py b/lib/galaxy/tools/parameters/basic.py index b00cc86c828..d3afd35392a 100644 --- a/lib/galaxy/tools/parameters/basic.py +++ b/lib/galaxy/tools/parameters/basic.py @@ -1764,6 +1764,22 @@ class DataToolParameter( BaseDataToolParameter ): self.validators.append( validation.MetadataValidator() ) self._parse_formats( trans, tool, input_source ) self.multiple = input_source.get_bool('multiple', False) + self.min = input_source.get( 'min' ) + self.max = input_source.get( 'max' ) + if self.min: + try: + self.min = int( self.min ) + except: + raise ValueError( "An integer is required for min property." ) + if self.max: + try: + self.max = int( self.max ) + except: + raise ValueError( "An integer is required for max property." ) + if not self.multiple and (self.min is not None): + raise ValueError( "Cannot specify min property on single data parameter '%s'. Set multiple=\"true\" to enable this option." % self.name ) + if not self.multiple and (self.max is not None): + raise ValueError( "Cannot specify max property on single data parameter '%s'. Set multiple=\"true\" to enable this option." % self.name ) self.is_dynamic = True self._parse_options( input_source ) # Load conversions required for the dataset input @@ -2052,17 +2068,31 @@ class DataToolParameter( BaseDataToolParameter ): return "No dataset" def validate( self, value, history=None ): + dataset_count = 0 for validator in self.validators: if value and self.multiple: - if isinstance(value, list): - for v in value: - validator.validate( v, history ) - elif isinstance(value, galaxy.model.HistoryDatasetCollectionAssociation): - for v in value.collection.dataset_instances: + if not isinstance( value, list ): + value = [ value ] + for v in value: + if isinstance(v, galaxy.model.HistoryDatasetCollectionAssociation): + for dataset_instance in v.collection.dataset_instances: + dataset_count += 1 + validator.validate( dataset_instance, history ) + else: + dataset_count += 1 validator.validate( v, history ) else: + if value: + dataset_count += 1 validator.validate( value, history ) + if self.min is not None: + if self.min > dataset_count: + raise ValueError( "At least %d datasets are required." % self.min ) + if self.max is not None: + if self.max < dataset_count: + raise ValueError( "At most %d datasets are required." % self.max ) + def get_dependencies( self ): """ Get the *names* of the other params this param depends on. @@ -2124,6 +2154,10 @@ class DataToolParameter( BaseDataToolParameter ): d['extensions'] = extensions d['edam_formats'] = edam_formats d['multiple'] = self.multiple + if self.multiple: + # For consistency, should these just always be in the dict? + d['min'] = self.min + d['max'] = self.max d['options'] = {'hda': [], 'hdca': []} # return default content if context is not available diff --git a/test/api/test_tools.py b/test/api/test_tools.py index 62db749398f..74fa95d743c 100644 --- a/test/api/test_tools.py +++ b/test/api/test_tools.py @@ -62,6 +62,19 @@ class ToolsTestCase( api.ApiTestCase ): self._assert_has_keys( case2_inputs[ 0 ], 'name', 'type', 'label', 'help', 'argument' ) assert case2_inputs[ 0 ][ "name" ] == "seed" + @skip_without_tool( "multi_data_param" ) + def test_show_multi_data( self ): + tool_info = self._show_valid_tool( "multi_data_param" ) + + f1_info, f2_info = tool_info[ "inputs" ][ 0 ], tool_info[ "inputs" ][ 1 ] + self._assert_has_keys( f1_info, "min", "max" ) + assert f1_info["min"] == 1 + assert f1_info["max"] == 1235 + + self._assert_has_keys( f2_info, "min", "max" ) + assert f2_info["min"] is None + assert f2_info["max"] is None + def _show_valid_tool( self, tool_id ): tool_show_response = self._get( "tools/%s" % tool_id, data=dict( io_details=True ) ) self._assert_status_code_is( tool_show_response, 200 ) diff --git a/test/functional/tools/multi_data_param.xml b/test/functional/tools/multi_data_param.xml index 6fe5de3bc53..1fcec1b9bc6 100644 --- a/test/functional/tools/multi_data_param.xml +++ b/test/functional/tools/multi_data_param.xml @@ -6,7 +6,7 @@ cat ${" ".join(map(str, $f2))} >> $out2 - +