Commits

Daniel Blankenberg committed a4113cc

Fixes for Tool.check_and_update_param_values_helper() to check that the type of value provided is valid for the input parameter currently declared. Fixes an issue where rurun would select the wrong input dataset.

Comments (0)

Files changed (6)

lib/galaxy/tools/__init__.py

         return params_to_strings( self.inputs, params, app )
     def params_from_strings( self, params, app, ignore_errors=False ):
         return params_from_strings( self.inputs, params, app, ignore_errors )
-    def check_and_update_param_values( self, values, trans ):
+    def check_and_update_param_values( self, values, trans, update_values=True ):
         """
         Check that all parameters have values, and fill in with default
         values where necessary. This could be called after loading values
         from a database in case new parameters have been added. 
         """
         messages = {}
-        self.check_and_update_param_values_helper( self.inputs, values, trans, messages )
+        self.check_and_update_param_values_helper( self.inputs, values, trans, messages, update_values=update_values )
         return messages
-    def check_and_update_param_values_helper( self, inputs, values, trans, messages, context=None, prefix="" ):
+    def check_and_update_param_values_helper( self, inputs, values, trans, messages, context=None, prefix="", update_values=True ):
         """
         Recursive helper for `check_and_update_param_values_helper`
         """
                     # Regular tool parameter, no recursion needed
                     try:
                         #this will fail when a parameter's type has changed to a non-compatible one: e.g. conditional group changed to dataset input
-                        input.value_from_basic( values[ input.name ], trans.app, ignore_errors=False )
+                        input.value_from_basic( input.value_to_basic( values[ input.name ], trans.app ), trans.app, ignore_errors=False )
                     except:
                         messages[ input.name ] = "Value no longer valid for '%s%s', replaced with default" % ( prefix, input.label )
-                        values[ input.name ] = input.get_initial_value( trans, context )
+                        if update_values:
+                            values[ input.name ] = input.get_initial_value( trans, context )
     def handle_unvalidated_param_values( self, input_values, app ):
         """
         Find any instances of `UnvalidatedValue` within input_values and

lib/galaxy/tools/parameters/basic.py

             return { "__class__": "RuntimeValue" }
         return value
     def value_from_basic( self, value, app, ignore_errors=False ):
-        if isinstance( value, dict ) and value["__class__"] == "UnvalidatedValue":
+        if isinstance( value, dict ) and value.get( "__class__", None ) == "UnvalidatedValue":
             return UnvalidatedValue( value["value"] )
-        return super( SelectToolParameter, self ).value_from_basic( value, app )
+        return super( SelectToolParameter, self ).value_from_basic( value, app, ignore_errors=ignore_errors )
     def need_late_validation( self, trans, context ):
         """
         Determine whether we need to wait to validate this parameters value
                 if not isinstance( value, list ):
                     value = value.split( '\n' )
                 for column in value:
-                    for column2 in column.split( ',' ):
+                    for column2 in str( column ).split( ',' ):
                         column2 = column2.strip()
                         if column2:
                             column_list.append( column2 )
         elif isinstance( value, list) and len(value) > 0 and isinstance( value[0], DummyDataset):
             return None
         elif isinstance( value, list ):
-            return ",".join( [ val if isinstance( val, basestring ) else str(val.id) for val in value] )
-        return value.id
+            return ",".join( [ str( self.to_string( val, app ) ) for val in value ] )
+        try:
+            return value.id
+        except:
+            return str( value )
 
     def to_python( self, value, app ):
         # Both of these values indicate that no dataset is selected.  However, 'None' 

lib/galaxy/tools/parameters/grouping.py

         return rval
     def value_from_basic( self, value, app, ignore_errors=False ):
         rval = []
-        for i, d in enumerate( value ):
-            rval_dict = {}
-            # If the special __index__ key is not set, create it (for backward
-            # compatibility)
-            rval_dict['__index__'] = d.get( '__index__', i )
-            # Restore child inputs
-            for input in self.inputs.itervalues():
-                if ignore_errors and input.name not in d:
-                    # If we do not have a value, and are ignoring errors, we simply
-                    # do nothing. There will be no value for the parameter in the
-                    # conditional's values dictionary.     
-                    pass
-                else:
-                    rval_dict[ input.name ] = input.value_from_basic( d[input.name], app, ignore_errors )
-            rval.append( rval_dict )
+        try:
+            for i, d in enumerate( value ):
+                rval_dict = {}
+                # If the special __index__ key is not set, create it (for backward
+                # compatibility)
+                rval_dict['__index__'] = d.get( '__index__', i )
+                # Restore child inputs
+                for input in self.inputs.itervalues():
+                    if ignore_errors and input.name not in d:
+                        # If we do not have a value, and are ignoring errors, we simply
+                        # do nothing. There will be no value for the parameter in the
+                        # conditional's values dictionary.     
+                        pass
+                    else:
+                        rval_dict[ input.name ] = input.value_from_basic( d[input.name], app, ignore_errors )
+                rval.append( rval_dict )
+        except Exception, e:
+            if not ignore_errors:
+                raise e
         return rval 
     def visit_inputs( self, prefix, value, callback ):
         for i, d in enumerate( value ):
         return rval
     def value_from_basic( self, value, app, ignore_errors=False ):
         rval = dict()
-        current_case = rval['__current_case__'] = value['__current_case__']
-        # Test param
-        if ignore_errors and self.test_param.name not in value:
-            # If ignoring errors, do nothing. However this is potentially very
-            # problematic since if we are missing the value of test param,
-            # the entire conditional is wrong.
-            pass
-        else:
-            rval[ self.test_param.name ] = self.test_param.value_from_basic( value[ self.test_param.name ], app, ignore_errors )
-        # Inputs associated with current case
-        for input in self.cases[current_case].inputs.itervalues():
-            if ignore_errors and input.name not in value:
-                # If we do not have a value, and are ignoring errors, we simply
-                # do nothing. There will be no value for the parameter in the
-                # conditional's values dictionary.                 
+        try:
+            current_case = rval['__current_case__'] = value['__current_case__']
+            # Test param
+            if ignore_errors and self.test_param.name not in value:
+                # If ignoring errors, do nothing. However this is potentially very
+                # problematic since if we are missing the value of test param,
+                # the entire conditional is wrong.
                 pass
             else:
-                rval[ input.name ] = input.value_from_basic( value[ input.name ], app, ignore_errors )
+                rval[ self.test_param.name ] = self.test_param.value_from_basic( value[ self.test_param.name ], app, ignore_errors )
+            # Inputs associated with current case
+            for input in self.cases[current_case].inputs.itervalues():
+                if ignore_errors and input.name not in value:
+                    # If we do not have a value, and are ignoring errors, we simply
+                    # do nothing. There will be no value for the parameter in the
+                    # conditional's values dictionary.                 
+                    pass
+                else:
+                    rval[ input.name ] = input.value_from_basic( value[ input.name ], app, ignore_errors )
+        except Exception, e:
+            if not ignore_errors:
+                raise e
         return rval
     def visit_inputs( self, prefix, value, callback ):
         current_case = value['__current_case__']

lib/galaxy/tools/parameters/validation.py

     def from_element( cls, param, elem ):
         return cls( message=elem.get( 'message', None ), check=elem.get( 'check', "" ), skip=elem.get( 'skip', "" ) )
     def validate( self, value, history=None ):
-        if value and value.missing_meta( check = self.check, skip = self.skip ):
-            if self.message is None:
-                self.message = "Metadata missing, click the pencil icon in the history item to edit / save the metadata attributes"
-            raise ValueError( self.message )
+        if value:
+            if not isinstance( value, model.DatasetInstance ):
+                raise ValueError( 'A non-dataset value was provided.' )
+            if value.missing_meta( check = self.check, skip = self.skip ):
+                if self.message is None:
+                    self.message = "Metadata missing, click the pencil icon in the history item to edit / save the metadata attributes"
+                raise ValueError( self.message )
 
 class UnspecifiedBuildValidator( Validator ):
     """

lib/galaxy/util/hash_util.py

 
 def hmac_new( key, value ):
     return hmac.new( key, value, sha ).hexdigest()
+
+def is_hashable( value ):
+    try:
+        hash( value )
+    except:
+        return False
+    return True

lib/galaxy/webapps/galaxy/controllers/tool_runner.py

 
 from galaxy.web.base.controller import *
 from galaxy.util.bunch import Bunch
+from galaxy.util.hash_util import is_hashable
 from galaxy.tools import DefaultToolState
 from galaxy.tools.parameters.basic import UnvalidatedValue
 from galaxy.tools.parameters import params_to_incoming
             params_objects = job.get_param_values( trans.app, ignore_errors = True )
         except:
             raise Exception( "Failed to get parameters for dataset id %d " % data.id )
-        upgrade_messages = tool.check_and_update_param_values( params_objects, trans )
+        upgrade_messages = tool.check_and_update_param_values( params_objects, trans, update_values=False )
         # Need to remap dataset parameters. Job parameters point to original 
         # dataset used; parameter should be the analygous dataset in the 
         # current history.
                 if isinstance(value,list):
                     values = []
                     for val in value:
-                        if val in history.datasets:
-                            values.append( val )
-                        elif val in hda_source_dict:
-                            values.append( hda_source_dict[ val ])
+                        if is_hashable( val ):
+                            if val in history.datasets:
+                                values.append( val )
+                            elif val in hda_source_dict:
+                                values.append( hda_source_dict[ val ])
                     return values
-                if value not in history.datasets and value in hda_source_dict:
+                if is_hashable( value ) and value not in history.datasets and value in hda_source_dict:
                     return hda_source_dict[ value ]
         visit_input_values( tool.inputs, params_objects, rerun_callback )
         # Create a fake tool_state for the tool, with the parameters values