From f05c9518be52ecaa9cb13885aeec3f57054e976a Mon Sep 17 00:00:00 2001 From: guerler Date: Fri, 15 Jan 2016 18:38:38 -0500 Subject: [PATCH 01/33] Remove unvalidated values --- lib/galaxy/tools/parameters/basic.py | 47 ++++--------------- .../tools/parameters/dynamic_options.py | 2 +- 2 files changed, 11 insertions(+), 38 deletions(-) diff --git a/lib/galaxy/tools/parameters/basic.py b/lib/galaxy/tools/parameters/basic.py index 2822a185d803..5043adbf9774 100644 --- a/lib/galaxy/tools/parameters/basic.py +++ b/lib/galaxy/tools/parameters/basic.py @@ -885,12 +885,8 @@ def get_options( self, trans, other_values ): return self.static_options def get_legal_values( self, trans, other_values ): - def _get_UnvalidatedValue_value( value ): - if isinstance( value, UnvalidatedValue ): - return value.value - return value if self.options: - return map( _get_UnvalidatedValue_value, set( v for _, v, _ in self.options.get_options( trans, other_values ) ) ) + return set( v for _, v, _ in self.options.get_options( trans, other_values ) ) elif self.dynamic_options: try: call_other_values = self._get_dynamic_options_call_other_values( trans, other_values ) @@ -906,8 +902,6 @@ def get_html_field( self, trans=None, value=None, context={} ): # specifying the value as text for now. options = list(self.get_options( trans, context )) if len(list(options)) == 0 and (trans is None or trans.workflow_building_mode): - if isinstance( value, UnvalidatedValue ): - value = value.value if self.multiple: if value is None: value = "" @@ -919,13 +913,8 @@ def get_html_field( self, trans=None, value=None, context={} ): if value is not None: if not isinstance( value, list ): value = [ value ] - # We could have an unvalidated value here when e.g. running a workflow. - value = [ val.value if isinstance( val, UnvalidatedValue ) else val for val in value ] field = form_builder.SelectField( self.name, self.multiple, self.display, self.refresh_on_change, refresh_on_change_values=self.refresh_on_change_values ) for text, optval, selected in options: - if isinstance( optval, UnvalidatedValue ): - optval = optval.value - text = "%s (unvalidated)" % text if value: selected = ( optval in value ) field.add_option( text, optval, selected ) @@ -947,7 +936,7 @@ def from_html( self, value, trans=None, context={} ): # in interpreting values but also is needed because many browsers # use \r\n to separate lines. value = value.split() - return UnvalidatedValue( value ) + return value if not legal_values and self.optional: return None if not legal_values: @@ -1000,9 +989,7 @@ def to_param_dict_string( self, value, other_values={}, value_map=DEFAULT_VALUE_ return value def value_to_basic( self, value, app ): - if isinstance( value, UnvalidatedValue ): - return { "__class__": "UnvalidatedValue", "value": value.value } - elif isinstance( value, RuntimeValue ): + if isinstance( value, RuntimeValue ): # Need to handle runtime value's ourself since delegating to the # parent method causes the value to be turned into a string, which # breaks multiple selection @@ -1010,14 +997,15 @@ def value_to_basic( self, value, app ): return value def value_from_basic( self, value, app, ignore_errors=False ): + # Backward compatibility for unvalidated values already stored in databases if isinstance( value, dict ) and value.get( "__class__", None ) == "UnvalidatedValue": - return UnvalidatedValue( value["value"] ) + return value[ "value" ] return super( SelectToolParameter, self ).value_from_basic( value, app, ignore_errors=ignore_errors ) def get_initial_value( self, trans, context, history=None ): options = list( self.get_options( trans, context ) ) if len(options) == 0 and (trans is None or trans.workflow_building_mode): - return UnvalidatedValue( None ) + return None value = [ optval for _, optval, selected in options if selected ] if len( value ) == 0: if not self.optional and not self.multiple and options: @@ -1031,11 +1019,6 @@ def get_initial_value( self, trans, context, history=None ): return value def value_to_display_text( self, value, app ): - if isinstance( value, UnvalidatedValue ): - suffix = "\n(value not yet validated)" - value = value.value - else: - suffix = "" if not isinstance( value, list ): value = [ value ] # FIXME: Currently only translating values back to labels if they @@ -1048,7 +1031,7 @@ def value_to_display_text( self, value, app ): for t, v, s in options: if v in value: rval.append( t ) - return "\n".join( rval ) + suffix + return "\n".join( rval ) def get_dependencies( self ): """ @@ -1547,8 +1530,6 @@ def get_html_field( self, trans=None, value=None, other_values={} ): # specifying the value as text for now. options = self.get_options( trans, value, other_values ) if len(list(options)) == 0 and (trans is None or trans.workflow_building_mode): - if isinstance( value, UnvalidatedValue ): - value = value.value if self.multiple: if value is None: value = "" @@ -1567,7 +1548,7 @@ def from_html( self, value, trans=None, other_values={} ): value = None else: value = value.split( "\n" ) - return UnvalidatedValue( value ) + return value if not value and not self.optional: raise ValueError( "An invalid option was selected for %s, 'None', please verify" % (self.name) ) if not value: @@ -1634,7 +1615,7 @@ def recurse_options( initial_values, options ): # More working around dynamic options for workflow options = self.get_options( trans=trans, other_values=context ) if len(list(options)) == 0 and (trans is None or trans.workflow_building_mode): - return UnvalidatedValue( None ) + return None initial_values = [] recurse_options( initial_values, options ) if len( initial_values ) == 0: @@ -1650,12 +1631,6 @@ def get_option_display( value, options ): if rval: return rval return None # not found - - if isinstance( value, UnvalidatedValue ): - suffix = "\n(value not yet validated)" - value = value.value - else: - suffix = "" if not value: value = [] elif not isinstance( value, list ): @@ -1674,7 +1649,7 @@ def get_option_display( value, options ): rval = [] for val in value: rval.append( get_option_display( val, self.options ) or val ) - return "\n".join( map( str, rval ) ) + suffix + return "\n".join( map( str, rval ) ) def get_dependencies( self ): """ @@ -2656,7 +2631,6 @@ def _allow_workflow_parameters_in_context(trans): drill_down=DrillDownSelectToolParameter ) - class UnvalidatedValue( object ): """ Wrapper to mark a value that has not been validated @@ -2667,7 +2641,6 @@ def __init__( self, value ): def __str__( self ): return str( self.value ) - class RuntimeValue( object ): """ Wrapper to note a value that is not yet set, but will be required at diff --git a/lib/galaxy/tools/parameters/dynamic_options.py b/lib/galaxy/tools/parameters/dynamic_options.py index e6cb93350fd5..e33cec7780f7 100644 --- a/lib/galaxy/tools/parameters/dynamic_options.py +++ b/lib/galaxy/tools/parameters/dynamic_options.py @@ -148,7 +148,7 @@ def compare_meta_value( file_value, dataset_value ): meta_value = ref.metadata.get( self.key, None ) if meta_value is None: # assert meta_value is not None, "Required metadata value '%s' not found in referenced dataset" % self.key - return [ ( disp_name, basic.UnvalidatedValue( optval ), selected ) for disp_name, optval, selected in options ] + return [ ( disp_name, optval, selected ) for disp_name, optval, selected in options ] if self.column is not None: rval = [] From 89ba002475695d09542dbe85886c6d69e6f54307 Mon Sep 17 00:00:00 2001 From: guerler Date: Sat, 16 Jan 2016 16:27:07 -0500 Subject: [PATCH 02/33] Remove late validation handling --- lib/galaxy/tools/__init__.py | 80 +++---------------------- lib/galaxy/tools/evaluation.py | 9 ++- lib/galaxy/tools/parameters/__init__.py | 29 +++++---- lib/galaxy/tools/parameters/basic.py | 34 ++++++----- 4 files changed, 50 insertions(+), 102 deletions(-) diff --git a/lib/galaxy/tools/__init__.py b/lib/galaxy/tools/__init__.py index 06035765aa03..0fb65d78e703 100755 --- a/lib/galaxy/tools/__init__.py +++ b/lib/galaxy/tools/__init__.py @@ -1741,58 +1741,6 @@ def check_and_update_param_values_helper( self, inputs, values, trans, messages, 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 - validate them (by calling `ToolParameter.from_html` and - `ToolParameter.validate`). - """ - # No validation is done when check_values is False - if not self.check_values: - return - self.handle_unvalidated_param_values_helper( self.inputs, input_values, app ) - - def handle_unvalidated_param_values_helper( self, inputs, input_values, app, context=None, prefix="" ): - """ - Recursive helper for `handle_unvalidated_param_values` - """ - context = ExpressionContext( input_values, context ) - for input in inputs.itervalues(): - if isinstance( input, Repeat ): - for i, d in enumerate( input_values[ input.name ] ): - rep_prefix = prefix + "%s %d > " % ( input.title, i + 1 ) - self.handle_unvalidated_param_values_helper( input.inputs, d, app, context, rep_prefix ) - elif isinstance( input, Conditional ): - values = input_values[ input.name ] - current = values["__current_case__"] - # NOTE: The test param doesn't need to be checked since - # there would be no way to tell what case to use at - # workflow build time. However I'm not sure if we are - # actually preventing such a case explicately. - self.handle_unvalidated_param_values_helper( input.cases[current].inputs, values, app, context, prefix ) - else: - # Regular tool parameter - value = input_values[ input.name ] - if isinstance( value, UnvalidatedValue ): - try: - # Convert from html representation - if value.value is None: - # If value.value is None, it could not have been - # submited via html form and therefore .from_html - # can't be guaranteed to work - value = None - else: - value = input.from_html( value.value, None, context ) - # Do any further validation on the value - input.validate( value, None ) - except Exception, e: - # Wrap an re-raise any generated error so we can - # generate a more informative message - message = "Failed runtime validation of %s%s (%s)" \ - % ( prefix, input.label, e ) - raise LateValidationError( message ) - input_values[ input.name ] = value - def handle_job_failure_exception( self, e ): """ Called by job.fail when an exception is generated to allow generation @@ -2152,12 +2100,6 @@ def to_json(self, trans, kwd={}, job=None, workflow_mode=False): # convert value to jsonifiable value def jsonify(v): - if isinstance(v, UnvalidatedValue): - v = v.value - while isinstance( v, UnvalidatedValue ): - v = v.value - return v - # check if value is numeric isnumber = False try: @@ -2219,29 +2161,21 @@ def sanitize(dict, key='value'): dict[key] = value # check the current state of a value and update it if necessary - def check_state(trans, input, value, context): + def check_state( trans, input, value, context ): error = 'State validation failed.' - - # handle unvalidated values - if isinstance(value, galaxy.tools.parameters.basic.DummyDataset): + if isinstance( value, galaxy.tools.parameters.basic.DummyDataset ): return [ None, None ] - elif isinstance(value, galaxy.tools.parameters.basic.RuntimeValue): + elif isinstance( value, galaxy.tools.parameters.basic.RuntimeValue ): return [ { '__class__' : 'RuntimeValue' }, None ] elif isinstance( value, dict ): - if value.get('__class__') == 'RuntimeValue': + if value.get( '__class__' ) == 'RuntimeValue': return [ value, None ] - - # validate value content try: - # resolves the inconsistent definition of boolean parameters (see base.py) without modifying shared code - if input.type == 'boolean' and isinstance(value, basestring): - value, error = [string_as_bool(value), None] - else: - value, error = check_param(trans, input, value, context, history=history, workflow_building_mode=workflow_mode) + value, error = check_param( trans, input, value, context, history=history, boolean_fix=True, workflow_building_mode=workflow_mode ) except Exception, err: - log.error('Checking parameter %s failed. %s', input.name, str(err)) + log.error( 'Checking parameter %s failed. %s', input.name, str( err ) ) pass - return [value, error] + return [ value, error ] # populates state with incoming url parameters def populate_state(trans, inputs, state, errors, incoming, prefix="", context=None ): diff --git a/lib/galaxy/tools/evaluation.py b/lib/galaxy/tools/evaluation.py index 3b53819c95e5..2e6633f4110d 100644 --- a/lib/galaxy/tools/evaluation.py +++ b/lib/galaxy/tools/evaluation.py @@ -21,7 +21,7 @@ DataCollectionToolParameter, SelectToolParameter, ) -from galaxy.tools.parameters import wrapped_json +from galaxy.tools.parameters import wrapped_json, visit_input_values from galaxy.tools.parameters.grouping import Conditional, Repeat, Section from galaxy.tools import global_tool_errors from galaxy.jobs.datasets import dataset_path_rewrites @@ -52,8 +52,11 @@ def set_compute_environment( self, compute_environment, get_special=None ): job = self.job incoming = dict( [ ( p.name, p.value ) for p in job.parameters ] ) incoming = self.tool.params_from_strings( incoming, self.app ) - # Do any validation that could not be done at job creation - self.tool.handle_unvalidated_param_values( incoming, self.app ) + def validate_inputs( input, value, prefixed_name, prefixed_label, context ): + value = input.from_html( value, None, context ) + input.validate( value, None ) + visit_input_values ( self.tool.inputs, incoming, validate_inputs, details=True ) + # Restore input / output data lists inp_data = dict( [ ( da.name, da.dataset ) for da in job.input_datasets ] ) out_data = dict( [ ( da.name, da.dataset ) for da in job.output_datasets ] ) diff --git a/lib/galaxy/tools/parameters/__init__.py b/lib/galaxy/tools/parameters/__init__.py index 67e5bf6f060f..bbfaf26a6a7b 100644 --- a/lib/galaxy/tools/parameters/__init__.py +++ b/lib/galaxy/tools/parameters/__init__.py @@ -5,11 +5,12 @@ from basic import DataCollectionToolParameter, DataToolParameter, SelectToolParameter from grouping import Conditional, Repeat, Section, UploadDataset from galaxy.util.json import dumps, json_fix, loads +from galaxy.util.expressions import ExpressionContext REPLACE_ON_TRUTHY = object() -def visit_input_values( inputs, input_values, callback, name_prefix="", label_prefix="", no_replacement_value=REPLACE_ON_TRUTHY ): +def visit_input_values( inputs, input_values, callback, name_prefix="", label_prefix="", no_replacement_value=REPLACE_ON_TRUTHY, context=None, details=False ): """ Given a tools parameter definition (`inputs`) and a specific set of parameter `values`, call `callback` for each non-grouping parameter, @@ -22,30 +23,35 @@ def visit_input_values( inputs, input_values, callback, name_prefix="", label_pr Repeat and Group. This tracks labels and those do not. It would be nice to unify all the places that recursively visit inputs. """ + context = ExpressionContext( input_values, context ) for input in inputs.itervalues(): if isinstance( input, Repeat ) or isinstance( input, UploadDataset ): for i, d in enumerate( input_values[ input.name ] ): index = d['__index__'] new_name_prefix = name_prefix + "%s_%d|" % ( input.name, index ) new_label_prefix = label_prefix + "%s %d > " % ( input.title, i + 1 ) - visit_input_values( input.inputs, d, callback, new_name_prefix, new_label_prefix, no_replacement_value=no_replacement_value ) + visit_input_values( input.inputs, d, callback, new_name_prefix, new_label_prefix, no_replacement_value=no_replacement_value, context=context, details=details ) elif isinstance( input, Conditional ): values = input_values[ input.name ] current = values["__current_case__"] label_prefix = label_prefix new_name_prefix = name_prefix + input.name + "|" - visit_input_values( input.cases[current].inputs, values, callback, new_name_prefix, label_prefix, no_replacement_value=no_replacement_value ) + visit_input_values( input.cases[current].inputs, values, callback, new_name_prefix, label_prefix, no_replacement_value=no_replacement_value, context=context, details=details ) elif isinstance( input, Section ): values = input_values[ input.name ] label_prefix = label_prefix new_name_prefix = name_prefix + input.name + "|" - visit_input_values( input.inputs, values, callback, new_name_prefix, label_prefix, no_replacement_value=no_replacement_value ) + visit_input_values( input.inputs, values, callback, new_name_prefix, label_prefix, no_replacement_value=no_replacement_value, context=context, details=details ) else: - new_value = callback( input, - input_values[input.name], - prefixed_name=name_prefix + input.name, - prefixed_label=label_prefix + input.label ) - + args = { + 'input' : input, + 'value' : input_values[input.name], + 'prefixed_name' : name_prefix + input.name, + 'prefixed_label' : label_prefix + input.label + } + if details: + args[ 'context' ] = context + new_value = callback( **args ) if no_replacement_value is REPLACE_ON_TRUTHY: replace = bool(new_value) else: @@ -54,7 +60,7 @@ def visit_input_values( inputs, input_values, callback, name_prefix="", label_pr input_values[input.name] = new_value -def check_param( trans, param, incoming_value, param_values, source='html', history=None, workflow_building_mode=False ): +def check_param( trans, param, incoming_value, param_values, source='html', boolean_fix=False, history=None, workflow_building_mode=False ): """ Check the value of a single parameter `param`. The value in `incoming_value` is converted from its HTML encoding and validated. @@ -65,6 +71,9 @@ def check_param( trans, param, incoming_value, param_values, source='html', hist value = incoming_value error = None try: + # resolves the inconsistent definition of boolean parameters (see base.py) without modifying shared code + if boolean_fix and param.type == 'boolean' and isinstance( value, basestring ): + return [ string_as_bool( value ), None ] if history is None: history = trans.history if value is not None or isinstance( param, DataToolParameter ) or isinstance( param, DataCollectionToolParameter ): diff --git a/lib/galaxy/tools/parameters/basic.py b/lib/galaxy/tools/parameters/basic.py index 5043adbf9774..f92e283c20e3 100644 --- a/lib/galaxy/tools/parameters/basic.py +++ b/lib/galaxy/tools/parameters/basic.py @@ -1962,7 +1962,9 @@ def dataset_collector( datasets ): return most_recent_dataset[0] return '' - def from_html( self, value, trans, other_values={} ): + def from_html( self, value, trans, other_values={}, app=None ): + if app is None: + app = trans.app # Can't look at history in workflow mode, skip validation and such, # although, this should never be called in workflow mode right? if trans.workflow_building_mode: @@ -1979,44 +1981,44 @@ def from_html( self, value, trans, other_values={} ): for single_value in value: if isinstance( single_value, dict ) and 'src' in single_value and 'id' in single_value: if single_value['src'] == 'hda': - rval.append(trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( trans.app.security.decode_id(single_value['id']) )) + rval.append(app.sa_session.query( app.model.HistoryDatasetAssociation ).get( app.security.decode_id(single_value['id']) )) elif single_value['src'] == 'hdca': found_hdca = True - decoded_id = trans.app.security.decode_id( single_value[ 'id' ] ) - rval.append( trans.sa_session.query( trans.app.model.HistoryDatasetCollectionAssociation ).get( decoded_id ) ) + decoded_id = app.security.decode_id( single_value[ 'id' ] ) + rval.append( app.sa_session.query( app.model.HistoryDatasetCollectionAssociation ).get( decoded_id ) ) else: raise ValueError("Unknown input source %s passed to job submission API." % single_value['src']) - elif isinstance( single_value, trans.app.model.HistoryDatasetCollectionAssociation ): + elif isinstance( single_value, app.model.HistoryDatasetCollectionAssociation ): rval.append( single_value ) - elif isinstance( single_value, trans.app.model.HistoryDatasetAssociation ): + elif isinstance( single_value, app.model.HistoryDatasetAssociation ): rval.append( single_value ) else: - rval.append( trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( single_value ) ) + rval.append( app.sa_session.query( app.model.HistoryDatasetAssociation ).get( single_value ) ) if found_hdca: for val in rval: - if not isinstance( val, trans.app.model.HistoryDatasetCollectionAssociation ): + if not isinstance( val, app.model.HistoryDatasetCollectionAssociation ): raise ValueError( "If collections are supplied to multiple data input parameter, only collections may be used." ) - elif isinstance( value, trans.app.model.HistoryDatasetAssociation ): + elif isinstance( value, app.model.HistoryDatasetAssociation ): rval = value elif isinstance( value, dict ) and 'src' in value and 'id' in value: if value['src'] == 'hda': - rval = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( trans.app.security.decode_id(value['id']) ) + rval = trans.sa_session.query( app.model.HistoryDatasetAssociation ).get( app.security.decode_id(value['id']) ) elif value['src'] == 'hdca': - decoded_id = trans.app.security.decode_id( value[ 'id' ] ) - rval = trans.sa_session.query( trans.app.model.HistoryDatasetCollectionAssociation ).get( decoded_id ) + decoded_id = app.security.decode_id( value[ 'id' ] ) + rval = app.sa_session.query( app.model.HistoryDatasetCollectionAssociation ).get( decoded_id ) else: raise ValueError("Unknown input source %s passed to job submission API." % value['src']) elif str( value ).startswith( "__collection_reduce__|" ): encoded_ids = [ v[ len( "__collection_reduce__|" ): ] for v in str( value ).split(",") ] - decoded_ids = map( trans.app.security.decode_id, encoded_ids ) + decoded_ids = map( app.security.decode_id, encoded_ids ) rval = [] for decoded_id in decoded_ids: - hdca = trans.sa_session.query( trans.app.model.HistoryDatasetCollectionAssociation ).get( decoded_id ) + hdca = app.sa_session.query( app.model.HistoryDatasetCollectionAssociation ).get( decoded_id ) rval.append( hdca ) - elif isinstance( value, trans.app.model.HistoryDatasetCollectionAssociation ): + elif isinstance( value, app.model.HistoryDatasetCollectionAssociation ): rval = value else: - rval = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( value ) + rval = app.sa_session.query( app.model.HistoryDatasetAssociation ).get( value ) if isinstance( rval, list ): values = rval else: From 49026134443e49c81d5b071817bb7a018357f945 Mon Sep 17 00:00:00 2001 From: guerler Date: Thu, 21 Jan 2016 20:45:22 -0500 Subject: [PATCH 03/33] Use bunch instead of trans --- lib/galaxy/tools/evaluation.py | 4 - lib/galaxy/tools/parameters/__init__.py | 11 +- lib/galaxy/tools/parameters/basic.py | 180 +++++++++--------------- lib/galaxy/util/dbkeys.py | 6 +- 4 files changed, 75 insertions(+), 126 deletions(-) diff --git a/lib/galaxy/tools/evaluation.py b/lib/galaxy/tools/evaluation.py index 2e6633f4110d..bfad5ed5d43d 100644 --- a/lib/galaxy/tools/evaluation.py +++ b/lib/galaxy/tools/evaluation.py @@ -52,10 +52,6 @@ def set_compute_environment( self, compute_environment, get_special=None ): job = self.job incoming = dict( [ ( p.name, p.value ) for p in job.parameters ] ) incoming = self.tool.params_from_strings( incoming, self.app ) - def validate_inputs( input, value, prefixed_name, prefixed_label, context ): - value = input.from_html( value, None, context ) - input.validate( value, None ) - visit_input_values ( self.tool.inputs, incoming, validate_inputs, details=True ) # Restore input / output data lists inp_data = dict( [ ( da.name, da.dataset ) for da in job.input_datasets ] ) diff --git a/lib/galaxy/tools/parameters/__init__.py b/lib/galaxy/tools/parameters/__init__.py index bbfaf26a6a7b..fec62c68063a 100644 --- a/lib/galaxy/tools/parameters/__init__.py +++ b/lib/galaxy/tools/parameters/__init__.py @@ -6,6 +6,7 @@ from grouping import Conditional, Repeat, Section, UploadDataset from galaxy.util.json import dumps, json_fix, loads from galaxy.util.expressions import ExpressionContext +from galaxy.util.bunch import Bunch REPLACE_ON_TRUTHY = object() @@ -68,6 +69,12 @@ def check_param( trans, param, incoming_value, param_values, source='html', bool previous parameters (this may actually be an ExpressionContext when dealing with grouping scenarios). """ + request_context = Bunch( + user = trans.user, + history = trans.history, + user_ftp_dir = trans.user_ftp_dir, + workflow_building_mode = workflow_building_mode + ) value = incoming_value error = None try: @@ -79,9 +86,9 @@ def check_param( trans, param, incoming_value, param_values, source='html', bool if value is not None or isinstance( param, DataToolParameter ) or isinstance( param, DataCollectionToolParameter ): # Convert value from HTML representation if source == 'html': - value = param.from_html( value, trans, param_values ) + value = param.from_html( value, request_context, param_values ) else: - value = param.from_json( value, trans, param_values ) + value = param.from_json( value, request_context, param_values ) # Allow the value to be converted if necessary filtered_value = param.filter_value( value, trans, param_values ) # Then do any further validation on the value diff --git a/lib/galaxy/tools/parameters/basic.py b/lib/galaxy/tools/parameters/basic.py index f92e283c20e3..bddc085d009e 100644 --- a/lib/galaxy/tools/parameters/basic.py +++ b/lib/galaxy/tools/parameters/basic.py @@ -51,6 +51,7 @@ class ToolParameter( object, Dictifiable ): def __init__( self, tool, input_source, context=None ): input_source = ensure_input_source(input_source) + self.app = tool.app self.tool = tool self.refresh_on_change = False self.refresh_on_change_values = [] @@ -97,7 +98,7 @@ def get_label( self ): def get_html_field( self, trans=None, value=None, other_values={} ): raise TypeError( "Abstract Method" ) - def get_html( self, trans=None, value=None, other_values={}): + def get_html( self, trans=None, value=None, other_values={} ): """ Returns the html widget corresponding to the parameter. Optionally attempt to retain the current value specific by 'value' @@ -355,15 +356,15 @@ def get_html_field( self, trans=None, value=None, other_values={} ): value = str( value ) return super( IntegerToolParameter, self ).get_html_field( trans=trans, value=value, other_values=other_values ) - def from_html( self, value, trans=None, other_values={} ): + def from_html( self, value, trans, other_values={} ): try: return int( value ) except: - if contains_workflow_parameter(value) and _allow_workflow_parameters_in_context(trans): + if contains_workflow_parameter( value ) and trans.workflow_building_mode: return value if not value and self.optional: return "" - if _allow_workflow_parameters_in_context(trans): + if trans.workflow_building_mode: raise ValueError( "An integer or workflow parameter e.g. ${name} is required" ) else: raise ValueError( "An integer is required" ) @@ -434,15 +435,15 @@ def get_html_field( self, trans=None, value=None, other_values={} ): value = str( value ) return super( FloatToolParameter, self ).get_html_field( trans=trans, value=value, other_values=other_values ) - def from_html( self, value, trans=None, other_values={} ): + def from_html( self, value, trans, other_values={} ): try: return float( value ) except: - if contains_workflow_parameter(value) and _allow_workflow_parameters_in_context(trans): + if contains_workflow_parameter( value ) and trans.workflow_building_mode: return value if not value and self.optional: return "" - if _allow_workflow_parameters_in_context(trans): + if trans and trans.workflow_building_mode: raise ValueError( "A real number or workflow parameter e.g. ${name} is required" ) else: raise ValueError( "A real number is required" ) @@ -559,7 +560,7 @@ def from_html( self, value, trans=None, other_values={} ): # Middleware or proxies may encode files in special ways (TODO: this # should be pluggable) if type( value ) == dict: - upload_store = self.tool.app.config.nginx_upload_store + upload_store = self.app.config.nginx_upload_store assert upload_store, \ "Request appears to have been processed by nginx_upload_module \ but Galaxy is not configured to recognize it" @@ -634,7 +635,7 @@ def get_html_field( self, trans=None, value=None, other_values={} ): user_ftp_dir = None else: user_ftp_dir = trans.user_ftp_dir - return form_builder.FTPFileField( self.name, user_ftp_dir, trans.app.config.ftp_upload_site, value=value ) + return form_builder.FTPFileField( self.name, user_ftp_dir, self.app.config.ftp_upload_site, value=value ) def to_param_dict_string( self, value, other_values={} ): if value is '': @@ -646,7 +647,7 @@ def to_param_dict_string( self, value, other_values={} ): return lst[ 0 ] def from_html( self, value, trans=None, other_values={} ): - return self.to_python( value, trans.app, validate=True ) + return self.to_python( value, self.app, validate=True ) def to_string( self, value, app ): return self.to_python( value, app ) @@ -742,7 +743,7 @@ def get_initial_value( self, trans, context, history=None ): def get_html_field( self, trans=None, value=None, other_values={} ): return form_builder.HiddenField( self.name, self._get_value() ) - def from_html( self, value=None, trans=None, context={} ): + def from_html( self, value=None, trans=None, other_values={} ): return self._get_value() def _get_value( self ): @@ -901,7 +902,7 @@ def get_html_field( self, trans=None, value=None, context={} ): # Dynamic options are not yet supported in workflow, allow # specifying the value as text for now. options = list(self.get_options( trans, context )) - if len(list(options)) == 0 and (trans is None or trans.workflow_building_mode): + if len(list(options)) == 0 and trans.workflow_building_mode: if self.multiple: if value is None: value = "" @@ -920,9 +921,9 @@ def get_html_field( self, trans=None, value=None, context={} ): field.add_option( text, optval, selected ) return field - def from_html( self, value, trans=None, context={} ): - legal_values = self.get_legal_values( trans, context ) - if len(list(legal_values)) == 0 and (trans is None or trans.workflow_building_mode): + def from_html( self, value, trans, other_values={} ): + legal_values = self.get_legal_values( trans, other_values ) + if len(list(legal_values)) == 0 and trans.workflow_building_mode: if self.multiple: # While it is generally allowed that a select value can be '', # we do not allow this to be the case in a dynamically @@ -1004,7 +1005,7 @@ def value_from_basic( self, value, app, ignore_errors=False ): def get_initial_value( self, trans, context, history=None ): options = list( self.get_options( trans, context ) ) - if len(options) == 0 and (trans is None or trans.workflow_building_mode): + if len(options) == 0 and trans.workflow_building_mode: return None value = [ optval for _, optval, selected in options if selected ] if len( value ) == 0: @@ -1150,7 +1151,7 @@ def _get_dbkey_names( self, trans=None ): if not self.tool: # Hack for unit tests, since we have no tool return util.read_dbnames( None ) - return self.tool.app.genome_builds.get_genome_build_names( trans=trans ) + return self.app.genome_builds.get_genome_build_names( trans=trans ) class ColumnListParameter( SelectToolParameter ): @@ -1196,7 +1197,7 @@ def __init__( self, tool, input_source ): self.is_dynamic = True self.usecolnames = input_source.get_bool( "use_header_names", False ) - def from_html( self, value, trans=None, context={} ): + def from_html( self, value, trans, other_values={} ): """ Label convention prepends column number with a 'c', but tool uses the integer. This removes the 'c' when entered into a workflow. @@ -1220,7 +1221,7 @@ def from_html( self, value, trans=None, context={} ): value = ColumnListParameter._strip_c( value ) else: value = None - return super( ColumnListParameter, self ).from_html( value, trans, context ) + return super( ColumnListParameter, self ).from_html( value, trans, other_values ) @staticmethod def _strip_c(column): @@ -1529,7 +1530,7 @@ def get_html_field( self, trans=None, value=None, other_values={} ): # Dynamic options are not yet supported in workflow, allow # specifying the value as text for now. options = self.get_options( trans, value, other_values ) - if len(list(options)) == 0 and (trans is None or trans.workflow_building_mode): + if len(list(options)) == 0 and trans.workflow_building_mode: if self.multiple: if value is None: value = "" @@ -1540,9 +1541,9 @@ def get_html_field( self, trans=None, value=None, other_values={} ): return form_builder.TextField( self.name, value=(value or "") ) return form_builder.DrillDownField( self.name, self.multiple, self.display, self.refresh_on_change, options, value, refresh_on_change_values=self.refresh_on_change_values ) - def from_html( self, value, trans=None, other_values={} ): + def from_html( self, value, trans, other_values={} ): legal_values = self.get_legal_values( trans, other_values ) - if len(list(legal_values)) == 0 and (trans is None or trans.workflow_building_mode): + if len( list( legal_values ) ) == 0 and trans.workflow_building_mode: if self.multiple: if value == '': # No option selected value = None @@ -1554,14 +1555,14 @@ def from_html( self, value, trans=None, other_values={} ): if not value: return None if not isinstance( value, list ): - value = [value] + value = [ value ] if not( self.repeat ) and len( value ) > 1: assert self.multiple, "Multiple values provided but parameter %s is not expecting multiple values" % self.name rval = [] assert legal_values, "Parameter %s requires a value, but has no legal values defined" % self.name for val in value: if val not in legal_values: - raise ValueError( "An invalid option was selected for %s, %r, please verify" % (self.name, val)) + raise ValueError( "An invalid option was selected for %s, %r, please verify" % ( self.name, val ) ) rval.append( val ) return rval @@ -1614,7 +1615,7 @@ def recurse_options( initial_values, options ): recurse_options( initial_values, option['options'] ) # More working around dynamic options for workflow options = self.get_options( trans=trans, other_values=context ) - if len(list(options)) == 0 and (trans is None or trans.workflow_building_mode): + if len(list(options)) == 0 and trans.workflow_building_mode: return None initial_values = [] recurse_options( initial_values, options ) @@ -1709,7 +1710,7 @@ def _datatypes_registery( self, trans, tool ): if trans: # Must account for "Input Dataset" types, which while not a tool still need access to the real registry. # A handle to the transaction (and thus app) will be given by the module. - datatypes_registry = trans.app.datatypes_registry + datatypes_registry = self.app.datatypes_registry else: # This occurs for things such as unit tests import galaxy.datatypes.registry @@ -1867,7 +1868,7 @@ def value_modifier(value): name = history_dataset_collection.name hid = str( history_dataset_collection.hid ) hidden_text = "" # TODO - id = value_modifier( dataset_matcher.trans.security.encode_id( history_dataset_collection.id ) ) + id = value_modifier( self.app.security.encode_id( history_dataset_collection.id ) ) selected = value and history_dataset_collection in value text = "%s:%s %s" % ( hid, hidden_text, name ) field.add_option( text, id, selected ) @@ -1933,7 +1934,7 @@ def get_initial_value_from_history_prevent_repeats( self, trans, context, alread happens twice (here and when generating HTML). """ # Can't look at history in workflow mode. Tool shed has no histories. - if trans is None or trans.workflow_building_mode or trans.webapp.name == 'tool_shed': + if trans.workflow_building_mode or trans.webapp.name == 'tool_shed': return DummyDataset() history = self._get_history( trans, history ) dataset_matcher = DatasetMatcher( trans, self, None, context ) @@ -1962,16 +1963,14 @@ def dataset_collector( datasets ): return most_recent_dataset[0] return '' - def from_html( self, value, trans, other_values={}, app=None ): - if app is None: - app = trans.app + def from_html( self, value, trans, other_values={} ): # Can't look at history in workflow mode, skip validation and such, # although, this should never be called in workflow mode right? if trans.workflow_building_mode: return None if not value and not self.optional: raise ValueError( "History does not include a dataset of the required format / build" ) - if value in [None, "None", '']: + if value in [ None, "None", '' ]: return None if isinstance( value, str ) and value.find( "," ) > 0: value = [ int( value_part ) for value_part in value.split( "," ) ] @@ -1981,44 +1980,44 @@ def from_html( self, value, trans, other_values={}, app=None ): for single_value in value: if isinstance( single_value, dict ) and 'src' in single_value and 'id' in single_value: if single_value['src'] == 'hda': - rval.append(app.sa_session.query( app.model.HistoryDatasetAssociation ).get( app.security.decode_id(single_value['id']) )) + rval.append( self.app.model.context.query( self.app.model.HistoryDatasetAssociation ).get( self.app.security.decode_id(single_value['id']) )) elif single_value['src'] == 'hdca': found_hdca = True - decoded_id = app.security.decode_id( single_value[ 'id' ] ) - rval.append( app.sa_session.query( app.model.HistoryDatasetCollectionAssociation ).get( decoded_id ) ) + decoded_id = self.app.security.decode_id( single_value[ 'id' ] ) + rval.append( self.app.model.context.query( self.app.model.HistoryDatasetCollectionAssociation ).get( decoded_id ) ) else: raise ValueError("Unknown input source %s passed to job submission API." % single_value['src']) - elif isinstance( single_value, app.model.HistoryDatasetCollectionAssociation ): + elif isinstance( single_value, self.app.model.HistoryDatasetCollectionAssociation ): rval.append( single_value ) - elif isinstance( single_value, app.model.HistoryDatasetAssociation ): + elif isinstance( single_value, self.app.model.HistoryDatasetAssociation ): rval.append( single_value ) else: - rval.append( app.sa_session.query( app.model.HistoryDatasetAssociation ).get( single_value ) ) + rval.append( self.app.model.context.query( self.app.model.HistoryDatasetAssociation ).get( single_value ) ) if found_hdca: for val in rval: - if not isinstance( val, app.model.HistoryDatasetCollectionAssociation ): + if not isinstance( val, self.app.model.HistoryDatasetCollectionAssociation ): raise ValueError( "If collections are supplied to multiple data input parameter, only collections may be used." ) - elif isinstance( value, app.model.HistoryDatasetAssociation ): + elif isinstance( value, self.app.model.HistoryDatasetAssociation ): rval = value elif isinstance( value, dict ) and 'src' in value and 'id' in value: if value['src'] == 'hda': - rval = trans.sa_session.query( app.model.HistoryDatasetAssociation ).get( app.security.decode_id(value['id']) ) + rval = self.app.model.context.query( self.app.model.HistoryDatasetAssociation ).get( self.app.security.decode_id(value['id']) ) elif value['src'] == 'hdca': - decoded_id = app.security.decode_id( value[ 'id' ] ) - rval = app.sa_session.query( app.model.HistoryDatasetCollectionAssociation ).get( decoded_id ) + decoded_id = self.app.security.decode_id( value[ 'id' ] ) + rval = self.app.model.context.query( self.app.model.HistoryDatasetCollectionAssociation ).get( decoded_id ) else: raise ValueError("Unknown input source %s passed to job submission API." % value['src']) elif str( value ).startswith( "__collection_reduce__|" ): encoded_ids = [ v[ len( "__collection_reduce__|" ): ] for v in str( value ).split(",") ] - decoded_ids = map( app.security.decode_id, encoded_ids ) + decoded_ids = map( self.app.security.decode_id, encoded_ids ) rval = [] for decoded_id in decoded_ids: - hdca = app.sa_session.query( app.model.HistoryDatasetCollectionAssociation ).get( decoded_id ) + hdca = self.app.model.context.query( self.app.model.HistoryDatasetCollectionAssociation ).get( decoded_id ) rval.append( hdca ) - elif isinstance( value, app.model.HistoryDatasetCollectionAssociation ): + elif isinstance( value, self.app.model.HistoryDatasetCollectionAssociation ): rval = value else: - rval = app.sa_session.query( app.model.HistoryDatasetAssociation ).get( value ) + rval = self.app.model.context.query( self.app.model.HistoryDatasetAssociation ).get( value ) if isinstance( rval, list ): values = rval else: @@ -2204,7 +2203,7 @@ def to_dict( self, trans, view='collection', value_mapper=None, other_values={} if match: m = match.hda d['options']['hda'].append({ - 'id' : trans.security.encode_id( m.id ), + 'id' : self.app.security.encode_id( m.id ), 'hid' : m.hid, 'name' : m.name if m.visible else '(hidden) %s' % m.name, 'src' : 'hda' @@ -2215,7 +2214,7 @@ def to_dict( self, trans, view='collection', value_mapper=None, other_values={} for hdca in history.active_dataset_collections: if dataset_collection_matcher.hdca_match( hdca, reduction=multiple ): d['options']['hdca'].append({ - 'id' : trans.security.encode_id( hdca.id ), + 'id' : self.app.security.encode_id( hdca.id ), 'hid' : hdca.hid, 'name' : hdca.name, 'src' : 'hdca' @@ -2250,7 +2249,7 @@ 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 + dataset_collection_type_descriptions = self.app.dataset_collections_service.collection_type_descriptions return history_query.HistoryQuery.from_parameter( self, dataset_collection_type_descriptions ) def get_html_field( self, trans=None, value=None, other_values={} ): @@ -2273,7 +2272,7 @@ def get_html_field( self, trans=None, value=None, other_values={} ): return self._switch_fields( fields, default_field=default_field ) def match_collections( self, trans, history, dataset_matcher ): - dataset_collections = trans.app.dataset_collections_service.history_dataset_collections( history, self._history_query( trans ) ) + dataset_collections = self.app.dataset_collections_service.history_dataset_collections( history, self._history_query( trans ) ) dataset_collection_matcher = DatasetCollectionMatcher( dataset_matcher ) for dataset_collection_instance in dataset_collections: @@ -2317,8 +2316,8 @@ def _get_select_dataset_collection_field( self, trans, history, multiple=False, name = history_dataset_collection.name hid = str( history_dataset_collection.hid ) hidden_text = "" # TODO - subcollection_type = self._history_query( trans ).can_map_over( history_dataset_collection ).collection_type - id = "%s|%s" % ( dataset_matcher.trans.security.encode_id( history_dataset_collection.id ), subcollection_type ) + subcollection_type = self._history_query( trans ).collection_type_description.collection_type + id = "%s|%s" % ( self.app.security.encode_id( history_dataset_collection.id ), subcollection_type ) text = "%s:%s %s" % ( hid, hidden_text, name ) field.add_option( text, id, False ) @@ -2332,30 +2331,30 @@ def from_html( self, value, trans, other_values={} ): return None if isinstance( value, str ) and value.find( "," ) > 0: value = [ int( value_part ) for value_part in value.split( "," ) ] - elif isinstance( value, trans.app.model.HistoryDatasetCollectionAssociation ): + elif isinstance( value, self.app.model.HistoryDatasetCollectionAssociation ): rval = value - elif isinstance( value, trans.app.model.DatasetCollectionElement ): + elif isinstance( value, self.app.model.DatasetCollectionElement ): # When mapping over nested collection - this paramter will recieve # a DatasetCollectionElement instead of a # HistoryDatasetCollectionAssociation. rval = value elif isinstance( value, dict ) and 'src' in value and 'id' in value: if value['src'] == 'hdca': - rval = trans.sa_session.query( trans.app.model.HistoryDatasetCollectionAssociation ).get( trans.app.security.decode_id(value['id']) ) + rval = self.app.model.context.query( self.app.model.HistoryDatasetCollectionAssociation ).get( self.app.security.decode_id(value['id']) ) elif isinstance( value, list ): if len( value ) > 0: value = value[0] if isinstance( value, dict ) and 'src' in value and 'id' in value: if value['src'] == 'hdca': - rval = trans.sa_session.query( trans.app.model.HistoryDatasetCollectionAssociation ).get( trans.app.security.decode_id(value['id']) ) + rval = self.app.model.context.query( self.app.model.HistoryDatasetCollectionAssociation ).get( self.app.security.decode_id(value['id']) ) elif isinstance( value, basestring ): if value.startswith( "dce:" ): - rval = trans.sa_session.query( trans.app.model.DatasetCollectionElement ).get( value[ len( "dce:"): ] ) + rval = self.app.model.context.query( self.app.model.DatasetCollectionElement ).get( value[ len( "dce:"): ] ) elif value.startswith( "hdca:" ): - rval = trans.sa_session.query( trans.app.model.HistoryDatasetCollectionAssociation ).get( value[ len( "hdca:"): ] ) + rval = self.app.model.context.query( self.app.model.HistoryDatasetCollectionAssociation ).get( value[ len( "hdca:"): ] ) else: - rval = trans.sa_session.query( trans.app.model.HistoryDatasetCollectionAssociation ).get( value ) - if rval and isinstance( rval, trans.app.model.HistoryDatasetCollectionAssociation ): + rval = self.app.model.context.query( self.app.model.HistoryDatasetCollectionAssociation ).get( value ) + if rval and isinstance( rval, self.app.model.HistoryDatasetCollectionAssociation ): if rval.deleted: raise ValueError( "The previously selected dataset collection has been deleted" ) # TODO: Handle error states, implement error states ... @@ -2424,7 +2423,7 @@ def to_dict( self, trans, view='collection', value_mapper=None, other_values=Non # append directly matched collections for hdca in self.match_collections( trans, history, dataset_matcher ): d['options']['hdca'].append({ - 'id': trans.security.encode_id( hdca.id ), + 'id': self.app.security.encode_id( hdca.id ), 'hid': hdca.hid, 'name': hdca.name, 'src': 'hdca' @@ -2434,7 +2433,7 @@ def to_dict( self, trans, view='collection', value_mapper=None, other_values=Non for hdca in self.match_multirun_collections( trans, history, dataset_matcher ): subcollection_type = self._history_query( trans ).can_map_over( hdca ).collection_type d['options']['hdca'].append({ - 'id': trans.security.encode_id( hdca.id ), + 'id': self.app.security.encode_id( hdca.id ), 'hid': hdca.hid, 'name': hdca.name, 'src': 'hdca', @@ -2483,7 +2482,7 @@ def get_initial_value( self, trans, context, history=None ): return None def from_html( self, value, trans, other_values={} ): - return self.to_python( value, trans.app, other_values=other_values, validate=True ) + return self.to_python( value, self.app, other_values=other_values, validate=True ) def to_param_dict_string( self, value, other_values={} ): if value is None: @@ -2560,59 +2559,6 @@ def to_dict( self, trans, view='collection', value_mapper=None, other_values=Non d['multiple'] = self.multiple return d - -def _allow_workflow_parameters_in_context(trans): - return trans is None or trans.workflow_building_mode - - -# class RawToolParameter( ToolParameter ): -# """ -# Completely nondescript parameter, HTML representation is provided as text -# contents. -# -# >>> p = RawToolParameter( None, XML( -# ... ''' -# ... -# ... Some random stuff]]> -# ... -# ... ''' ) ) -# >>> print p.name -# blah -# >>> print p.get_html().strip() -# Some random stuff -# """ -# def __init__( self, tool, elem ): -# ToolParameter.__init__( self, tool, elem ) -# self.template = string.Template( elem.text ) -# def get_html( self, prefix="" ): -# context = dict( self.__dict__ ) -# context.update( dict( prefix=prefix ) ) -# return self.template.substitute( context ) - -# class HistoryIDParameter( ToolParameter ): -# """ -# Parameter that takes a name value, makes history.id available. -# -# FIXME: This is a hack (esp. if hidden params are a hack) but in order to -# have the history accessable at the job level, it is necessary -# I also probably wrote this docstring test thing wrong. -# -# >>> from galaxy.model import History -# >>> from galaxy.util.bunch import Bunch -# >>> hist = History( id=1 ) -# >>> p = HistoryIDParameter( None, XML( '' ) ) -# >>> print p.name -# blah -# >>> html_string = '' % hist.id -# >>> assert p.get_html( trans=Bunch( history=hist ) ) == html_string -# """ -# def __init__( self, tool, elem ): -# ToolParameter.__init__( self, tool, elem ) -# def get_html( self, trans, value=None, other_values={} ): -# assert trans.history is not None, "HistoryIDParameter requires a history" -# self.html = form_builder.HiddenField( self.name, trans.history.id ).get_html() -# return self.html - parameter_types = dict( text=TextToolParameter, integer=IntegerToolParameter, diff --git a/lib/galaxy/util/dbkeys.py b/lib/galaxy/util/dbkeys.py index 216e7cb6d388..8aa66bbf8c7f 100644 --- a/lib/galaxy/util/dbkeys.py +++ b/lib/galaxy/util/dbkeys.py @@ -33,7 +33,7 @@ def get_genome_build_names( self, trans=None ): # It does allow one-off, history specific dbkeys to be created by a user. But we are not filtering, # so a len file will be listed twice (as the build name and again as dataset name), # if custom dbkey creation/conversion occurred within the current history. - datasets = trans.sa_session.query( self._app.model.HistoryDatasetAssociation ) \ + datasets = self._app.model.context.query( self._app.model.HistoryDatasetAssociation ) \ .filter_by( deleted=False, history_id=trans.history.id, extension="len" ) for dataset in datasets: rval.append( ( dataset.dbkey, "%s (%s) [History]" % ( dataset.name, dataset.dbkey ) ) ) @@ -72,11 +72,11 @@ def get_chrom_info( self, dbkey, trans=None, custom_build_hack_get_len_from_fast # fasta-to-len converter. if 'fasta' in custom_build_dict and custom_build_hack_get_len_from_fasta_conversion: # Build is defined by fasta; get len file, which is obtained from converting fasta. - build_fasta_dataset = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( custom_build_dict[ 'fasta' ] ) + build_fasta_dataset = self._app.model.context.query( self._app.model.HistoryDatasetAssociation ).get( custom_build_dict[ 'fasta' ] ) chrom_info = build_fasta_dataset.get_converted_dataset( trans, 'len' ).file_name elif 'len' in custom_build_dict: # Build is defined by len file, so use it. - chrom_info = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( custom_build_dict[ 'len' ] ).file_name + chrom_info = self._app.model.context.query( self._app.model.HistoryDatasetAssociation ).get( custom_build_dict[ 'len' ] ).file_name # Check Data table if not chrom_info: dbkey_table = self._app.tool_data_tables.get( self._data_table_name, None ) From 12f2571d975ca89548259e1322882e87dbb5b17e Mon Sep 17 00:00:00 2001 From: guerler Date: Fri, 22 Jan 2016 15:09:55 -0500 Subject: [PATCH 04/33] Use self.app in tools --- lib/galaxy/tools/__init__.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/galaxy/tools/__init__.py b/lib/galaxy/tools/__init__.py index 0fb65d78e703..6ef7eafadb77 100755 --- a/lib/galaxy/tools/__init__.py +++ b/lib/galaxy/tools/__init__.py @@ -1734,7 +1734,7 @@ def check_and_update_param_values_helper( self, inputs, values, trans, messages, ck_param = False # this will fail when a parameter's type has changed to a non-compatible one: e.g. conditional group changed to dataset input if ck_param: - input.value_from_basic( input.value_to_basic( value, trans.app ), trans.app, ignore_errors=False ) + input.value_from_basic( input.value_to_basic( value, self.app ), self.app, ignore_errors=False ) except: log.info("Parameter validation failed.", exc_info=True) messages[ input.name ] = "Value no longer valid for '%s%s', replacing with default" % ( prefix, input.label ) @@ -2058,7 +2058,7 @@ def to_dict( self, trans, link_details=False, io_details=False ): # Add input and output details. if io_details: tool_dict[ 'inputs' ] = [ input.to_dict( trans ) for input in self.inputs.values() ] - tool_dict[ 'outputs' ] = [ output.to_dict( app=trans.app ) for output in self.outputs.values() ] + tool_dict[ 'outputs' ] = [ output.to_dict( app=self.app ) for output in self.outputs.values() ] tool_dict[ 'panel_section_id' ], tool_dict[ 'panel_section_name' ] = self.get_panel_section() @@ -2087,11 +2087,11 @@ def to_json(self, trans, kwd={}, job=None, workflow_mode=False): tool_message = '' if job: try: - job_params = job.get_param_values( trans.app, ignore_errors=True ) + job_params = job.get_param_values( self.app, ignore_errors=True ) self.check_and_update_param_values( job_params, trans, update_values=False ) self._map_source_to_history( trans, self.inputs, job_params, history ) tool_message = self._compare_tool_version(trans, job) - params_to_incoming( kwd, self.inputs, job_params, trans.app, to_html=False ) + params_to_incoming( kwd, self.inputs, job_params, self.app, to_html=False ) except Exception, e: raise exceptions.MessageException( str( e ) ) @@ -2109,17 +2109,17 @@ def jsonify(v): pass # fix hda parsing - if isinstance(v, trans.app.model.HistoryDatasetAssociation): + if isinstance(v, self.app.model.HistoryDatasetAssociation): return { 'id' : trans.security.encode_id(v.id), 'src' : 'hda' } - elif isinstance(v, trans.app.model.HistoryDatasetCollectionAssociation): + elif isinstance(v, self.app.model.HistoryDatasetCollectionAssociation): return { 'id' : trans.security.encode_id(v.id), 'src' : 'hdca' } - elif isinstance(v, trans.app.model.LibraryDatasetDatasetAssociation): + elif isinstance(v, self.app.model.LibraryDatasetDatasetAssociation): return { 'id' : trans.security.encode_id(v.id), 'name': v.name, @@ -2244,7 +2244,7 @@ def iterate(group_inputs, inputs, state_inputs, other_values=None): test_param = tool_dict['test_param'] test_param['default_value'] = jsonify(input.test_param.get_initial_value(trans, other_values, history=history)) test_param['value'] = jsonify(group_state.get(test_param['name'], test_param['default_value'])) - test_param['text_value'] = input.test_param.value_to_display_text(test_param['value'], trans.app) + test_param['text_value'] = input.test_param.value_to_display_text(test_param['value'], self.app) for i in range(len( tool_dict['cases'] ) ): current_state = {} if i == group_state.get('__current_case__', None): @@ -2274,7 +2274,7 @@ def iterate(group_inputs, inputs, state_inputs, other_values=None): tool_dict['value'] = state_inputs.get(input.name, tool_dict['default_value']) # add text value - tool_dict[ 'text_value' ] = input.value_to_display_text( tool_dict[ 'value' ], trans.app ) + tool_dict[ 'text_value' ] = input.value_to_display_text( tool_dict[ 'value' ], self.app ) # sanitize values sanitize(tool_dict, 'value') @@ -2353,14 +2353,14 @@ def sanitize_state(state): # add toolshed url sharable_url = None if self.tool_shed_repository: - sharable_url = self.tool_shed_repository.get_sharable_url( trans.app ) + sharable_url = self.tool_shed_repository.get_sharable_url( self.app ) # add additional properties tool_model.update({ 'id' : self.id, 'help' : tool_help, 'citations' : tool_citations, - 'biostar_url' : trans.app.config.biostar_url, + 'biostar_url' : self.app.config.biostar_url, 'sharable_url' : sharable_url, 'message' : tool_message, 'versions' : tool_versions, @@ -2407,10 +2407,10 @@ def _map_source_to_history(self, trans, tool_inputs, params, history): def map_to_history(value): id = None source = None - if isinstance(value, trans.app.model.HistoryDatasetAssociation): + if isinstance(value, self.app.model.HistoryDatasetAssociation): id = value.dataset.id source = hda_source_dict - elif isinstance(value, trans.app.model.HistoryDatasetCollectionAssociation): + elif isinstance(value, self.app.model.HistoryDatasetCollectionAssociation): id = value.collection.id source = hdca_source_dict else: @@ -2430,7 +2430,7 @@ def map_to_history(value): def mapping_callback( input, value, prefixed_name, prefixed_label ): if isinstance( value, UnvalidatedValue ): try: - return input.to_html_value( value.value, trans.app ) + return input.to_html_value( value.value, self.app ) except Exception, e: # Need to determine when (if ever) the to_html_value call could fail. log.debug( "Failed to use input.to_html_value to determine value of unvalidated parameter, defaulting to string: %s" % ( e ) ) From 52b6881f017e38ea5969c5adb70b5c83d6753cd3 Mon Sep 17 00:00:00 2001 From: guerler Date: Fri, 22 Jan 2016 18:02:29 -0500 Subject: [PATCH 05/33] Revise history handling --- lib/galaxy/tools/__init__.py | 6 +--- lib/galaxy/tools/parameters/basic.py | 42 ++++++++++++------------- lib/galaxy/tools/parameters/grouping.py | 20 ++++++------ 3 files changed, 32 insertions(+), 36 deletions(-) diff --git a/lib/galaxy/tools/__init__.py b/lib/galaxy/tools/__init__.py index 6ef7eafadb77..0550da3ddd7a 100755 --- a/lib/galaxy/tools/__init__.py +++ b/lib/galaxy/tools/__init__.py @@ -1485,11 +1485,7 @@ def update_state( self, trans, inputs, state, incoming, source='html', prefix="" # load default initial value if not test_param_error: test_param_error = str( e ) - if trans is not None: - history = trans.get_history() - else: - history = None - value = input.test_param.get_initial_value( trans, context, history=history ) + value = input.test_param.get_initial_value( trans, context ) current_case = input.get_current_case( value, trans ) case_changed = current_case != old_current_case if case_changed: diff --git a/lib/galaxy/tools/parameters/basic.py b/lib/galaxy/tools/parameters/basic.py index bddc085d009e..2e1fe8940c7b 100644 --- a/lib/galaxy/tools/parameters/basic.py +++ b/lib/galaxy/tools/parameters/basic.py @@ -115,13 +115,13 @@ def from_html( self, value, trans=None, other_values={} ): def from_json( self, value, trans=None, other_values={} ): return self.from_html( value, trans, other_values ) - def get_initial_value( self, trans, context, history=None ): + def get_initial_value( self, trans, context ): """ Return the starting value of the parameter """ return None - def get_initial_value_from_history_prevent_repeats( self, trans, context, already_used, history=None ): + def get_initial_value_from_history_prevent_repeats( self, trans, context, 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 @@ -129,7 +129,7 @@ def get_initial_value_from_history_prevent_repeats( self, trans, context, alread 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, context, history=history) + return self.get_initial_value( trans, context ) def get_required_enctype( self ): """ @@ -297,7 +297,7 @@ def validate( self, value, history=None, workflow_building_mode=False ): if not ( workflow_building_mode and contains_workflow_parameter(value, search=search) ): return super( TextToolParameter, self ).validate( value, history ) - def get_initial_value( self, trans, context, history=None ): + def get_initial_value( self, trans, context ): return self.value def to_dict( self, trans, view='collection', value_mapper=None, other_values={} ): @@ -379,7 +379,7 @@ def to_python( self, value, app ): return None raise err - def get_initial_value( self, trans, context, history=None ): + def get_initial_value( self, trans, context ): if self.value: return int( self.value ) else: @@ -458,7 +458,7 @@ def to_python( self, value, app ): return None raise err - def get_initial_value( self, trans, context, history=None ): + def get_initial_value( self, trans, context ): try: return float( self.value ) except: @@ -511,7 +511,7 @@ def to_html_value( self, value, app ): def to_python( self, value, app ): return ( value in [ 'True', 'true' ]) - def get_initial_value( self, trans, context, history=None ): + def get_initial_value( self, trans, context ): return self.checked def to_param_dict_string( self, value, other_values={} ): @@ -601,7 +601,7 @@ def to_python( self, value, app ): else: raise Exception( "FileToolParameter cannot be persisted" ) - def get_initial_value( self, trans, context, history=None ): + def get_initial_value( self, trans, context ): return None @@ -618,7 +618,7 @@ def __init__( self, tool, input_source ): self.multiple = input_source.get_bool( 'multiple', True ) self.user_ftp_dir = '' - def get_initial_value( self, trans, context, history=None ): + def get_initial_value( self, trans, context ): if trans is not None: if trans.user is not None: self.user_ftp_dir = "%s/" % trans.user_ftp_dir @@ -700,7 +700,7 @@ def __init__( self, tool, input_source ): def get_html_field( self, trans=None, value=None, other_values={} ): return form_builder.HiddenField( self.name, self.value ) - def get_initial_value( self, trans, context, history=None ): + def get_initial_value( self, trans, context ): return self.value def get_label( self ): @@ -723,7 +723,7 @@ def __init__( self, tool, input_source ): def get_html_field( self, trans=None, value=None, other_values={} ): return form_builder.HiddenField( self.name, self.value ) - def get_initial_value( self, trans, context, history=None ): + def get_initial_value( self, trans, context ): return self.value.lower() @@ -737,7 +737,7 @@ def __init__( self, tool, input_source ): super( BaseURLToolParameter, self ).__init__( tool, input_source ) self.value = input_source.get( 'value', '' ) - def get_initial_value( self, trans, context, history=None ): + def get_initial_value( self, trans, context ): return self._get_value() def get_html_field( self, trans=None, value=None, other_values={} ): @@ -1003,7 +1003,7 @@ def value_from_basic( self, value, app, ignore_errors=False ): return value[ "value" ] return super( SelectToolParameter, self ).value_from_basic( value, app, ignore_errors=ignore_errors ) - def get_initial_value( self, trans, context, history=None ): + def get_initial_value( self, trans, context ): options = list( self.get_options( trans, context ) ) if len(options) == 0 and trans.workflow_building_mode: return None @@ -1311,7 +1311,7 @@ def get_options( self, trans, other_values ): options.append( ( 'Column: ' + col, col, False ) ) return options - def get_initial_value( self, trans, context, history=None ): + def get_initial_value( self, trans, context ): if self.default_value is not None: return self.default_value return SelectToolParameter.get_initial_value( self, trans, context ) @@ -1607,7 +1607,7 @@ def recurse_option( option_list, option ): rval = sanitize_param( rval ) return rval - def get_initial_value( self, trans, context, history=None ): + def get_initial_value( self, trans, context ): def recurse_options( initial_values, options ): for option in options: if option['selected']: @@ -1925,10 +1925,10 @@ 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, context, history=None ): - return self.get_initial_value_from_history_prevent_repeats(trans, context, None, history=history) + def get_initial_value( self, trans, context ): + return self.get_initial_value_from_history_prevent_repeats(trans, context, None ) - def get_initial_value_from_history_prevent_repeats( self, trans, context, already_used, history=None ): + def get_initial_value_from_history_prevent_repeats( self, trans, context, already_used ): """ NOTE: This is wasteful since dynamic options and dataset collection happens twice (here and when generating HTML). @@ -1936,7 +1936,7 @@ def get_initial_value_from_history_prevent_repeats( self, trans, context, alread # Can't look at history in workflow mode. Tool shed has no histories. if trans.workflow_building_mode or trans.webapp.name == 'tool_shed': return DummyDataset() - history = self._get_history( trans, history ) + history = self._get_history( trans ) dataset_matcher = DatasetMatcher( trans, self, None, context ) if self.optional: return None @@ -2458,7 +2458,7 @@ def __init__( self, tool, elem ): self.type = "hidden_data" self.hidden = True - def get_initial_value( self, trans, context, history=None ): + def get_initial_value( self, trans, context ): return None def get_html_field( self, trans=None, value=None, other_values={} ): @@ -2478,7 +2478,7 @@ def __init__( self, tool, input_source, context=None ): def get_html_field( self, trans=None, value=None, other_values={} ): return form_builder.LibraryField( self.name, value=value, trans=trans ) - def get_initial_value( self, trans, context, history=None ): + def get_initial_value( self, trans, context ): return None def from_html( self, value, trans, other_values={} ): diff --git a/lib/galaxy/tools/parameters/grouping.py b/lib/galaxy/tools/parameters/grouping.py index ecd006b934a7..8998dc897b25 100644 --- a/lib/galaxy/tools/parameters/grouping.py +++ b/lib/galaxy/tools/parameters/grouping.py @@ -43,7 +43,7 @@ def value_from_basic( self, value, app, ignore_errors=False ): """ return value - def get_initial_value( self, trans, context, history=None ): + def get_initial_value( self, trans, context ): """ Return the initial state/value for this group """ @@ -120,12 +120,12 @@ def visit_inputs( self, prefix, value, callback ): else: input.visit_inputs( new_prefix, d[input.name], callback ) - def get_initial_value( self, trans, context, history=None ): + def get_initial_value( self, trans, context ): rval = [] for i in range( self.default ): rval_dict = { '__index__': i} for input in self.inputs.itervalues(): - rval_dict[ input.name ] = input.get_initial_value( trans, context, history=history ) + rval_dict[ input.name ] = input.get_initial_value( trans, context ) rval.append( rval_dict ) return rval @@ -182,11 +182,11 @@ def visit_inputs( self, prefix, value, callback ): else: input.visit_inputs( prefix, value[input.name], callback ) - def get_initial_value( self, trans, context, history=None ): + def get_initial_value( self, trans, context ): rval = {} child_context = ExpressionContext( rval, context ) for child_input in self.inputs.itervalues(): - rval[ child_input.name ] = child_input.get_initial_value( trans, child_context, history=history ) + rval[ child_input.name ] = child_input.get_initial_value( trans, child_context ) return rval def to_dict( self, trans, view='collection', value_mapper=None ): @@ -296,14 +296,14 @@ def visit_inputs( self, prefix, value, callback ): else: input.visit_inputs( new_prefix, d[input.name], callback ) - def get_initial_value( self, trans, context, history=None ): + def get_initial_value( self, trans, context ): d_type = self.get_datatype( trans, context ) rval = [] for i, ( composite_name, composite_file ) in enumerate( d_type.writable_files.iteritems() ): rval_dict = {} rval_dict['__index__'] = i # create __index__ for input in self.inputs.itervalues(): - rval_dict[ input.name ] = input.get_initial_value( trans, context, history=history ) # input.value_to_basic( d[input.name], app ) + rval_dict[ input.name ] = input.get_initial_value( trans, context ) rval.append( rval_dict ) return rval @@ -611,12 +611,12 @@ def visit_inputs( self, prefix, value, callback ): else: input.visit_inputs( prefix, value[input.name], callback ) - def get_initial_value( self, trans, context, history=None ): + def get_initial_value( self, trans, context ): # State for a conditional is a plain dictionary. rval = {} # Get the default value for the 'test element' and use it # to determine the current case - test_value = self.test_param.get_initial_value( trans, context, history=history ) + test_value = self.test_param.get_initial_value( trans, context ) current_case = self.get_current_case( test_value, trans ) # Store the current case in a special value rval['__current_case__'] = current_case @@ -625,7 +625,7 @@ def get_initial_value( self, trans, context, history=None ): # Fill in state for selected case child_context = ExpressionContext( rval, context ) for child_input in self.cases[current_case].inputs.itervalues(): - rval[ child_input.name ] = child_input.get_initial_value( trans, child_context, history=history ) + rval[ child_input.name ] = child_input.get_initial_value( trans, child_context ) return rval def to_dict( self, trans, view='collection', value_mapper=None ): From 34f46c98c7bdace6af9126b44534fd41c9121002 Mon Sep 17 00:00:00 2001 From: guerler Date: Fri, 22 Jan 2016 18:04:05 -0500 Subject: [PATCH 06/33] Remove comments --- lib/galaxy/tools/parameters/grouping.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/galaxy/tools/parameters/grouping.py b/lib/galaxy/tools/parameters/grouping.py index 8998dc897b25..1942d78670ae 100644 --- a/lib/galaxy/tools/parameters/grouping.py +++ b/lib/galaxy/tools/parameters/grouping.py @@ -323,11 +323,9 @@ def get_file_name( file_name ): if not dataset_info: dataset_info = 'uploaded file' return Bunch( type='file', path=data_file['local_filename'], name=dataset_name ) - # return 'file', data_file['local_filename'], get_file_name( data_file.filename ), dataset_name, dataset_info except: # The uploaded file should've been persisted by the upload tool action return Bunch( type=None, path=None, name=None ) - # return None, None, None, None, None def get_url_paste_urls_or_filename( group_incoming, override_name=None, override_info=None ): url_paste_file = group_incoming.get( 'url_paste', None ) @@ -347,7 +345,6 @@ def get_url_paste_urls_or_filename( group_incoming, override_name=None, override if not dataset_info: dataset_info = 'uploaded url' yield Bunch( type='url', path=line, name=dataset_name ) - # yield ( 'url', line, precreated_name, dataset_name, dataset_info ) else: dataset_name = dataset_info = precreated_name = 'Pasted Entry' # we need to differentiate between various url pastes here if override_name: @@ -355,7 +352,6 @@ def get_url_paste_urls_or_filename( group_incoming, override_name=None, override if override_info: dataset_info = override_info yield Bunch( type='file', path=url_paste_file, name=precreated_name ) - # yield ( 'file', url_paste_file, precreated_name, dataset_name, dataset_info ) def get_one_filename( context ): data_file = context['file_data'] From 7eb6cc7b8247689d1bfef12c99a9514610bbd0bb Mon Sep 17 00:00:00 2001 From: guerler Date: Fri, 22 Jan 2016 18:44:18 -0500 Subject: [PATCH 07/33] Revise validate signature --- lib/galaxy/tools/parameters/__init__.py | 8 +++----- lib/galaxy/tools/parameters/validation.py | 24 +++++++++++------------ 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/lib/galaxy/tools/parameters/__init__.py b/lib/galaxy/tools/parameters/__init__.py index fec62c68063a..e9f4563cfe27 100644 --- a/lib/galaxy/tools/parameters/__init__.py +++ b/lib/galaxy/tools/parameters/__init__.py @@ -81,8 +81,6 @@ def check_param( trans, param, incoming_value, param_values, source='html', bool # resolves the inconsistent definition of boolean parameters (see base.py) without modifying shared code if boolean_fix and param.type == 'boolean' and isinstance( value, basestring ): return [ string_as_bool( value ), None ] - if history is None: - history = trans.history if value is not None or isinstance( param, DataToolParameter ) or isinstance( param, DataCollectionToolParameter ): # Convert value from HTML representation if source == 'html': @@ -90,12 +88,12 @@ def check_param( trans, param, incoming_value, param_values, source='html', bool else: value = param.from_json( value, request_context, param_values ) # Allow the value to be converted if necessary - filtered_value = param.filter_value( value, trans, param_values ) + filtered_value = param.filter_value( value, request_context, param_values ) # Then do any further validation on the value - param.validate( filtered_value, history, workflow_building_mode=workflow_building_mode ) + param.validate( filtered_value, request_context ) elif value is None and isinstance( param, SelectToolParameter ): # An empty select list or column list - param.validate( value, history, workflow_building_mode=workflow_building_mode ) + param.validate( value, request_context ) except ValueError, e: error = str( e ) return value, error diff --git a/lib/galaxy/tools/parameters/validation.py b/lib/galaxy/tools/parameters/validation.py index e84156a9bc6d..c4bf76a9e8f9 100644 --- a/lib/galaxy/tools/parameters/validation.py +++ b/lib/galaxy/tools/parameters/validation.py @@ -28,7 +28,7 @@ def from_element( cls, param, elem ): assert type is not None, "Required 'type' attribute missing from validator" return validator_types[type].from_element( param, elem ) - def validate( self, value, history=None ): + def validate( self, value, trans=None ): raise TypeError( "Abstract Method" ) @@ -61,7 +61,7 @@ def __init__( self, message, expression ): # the sre module. self.expression = expression - def validate( self, value, history=None ): + def validate( self, value, trans=None ): if re.match( self.expression, value ) is None: raise ValueError( self.message ) @@ -95,7 +95,7 @@ def __init__( self, message, expression, substitute_value_in_message ): # Save compiled expression, code objects are thread safe (right?) self.expression = compile( expression, '', 'eval' ) - def validate( self, value, history=None ): + def validate( self, value, trans=None ): if not( eval( self.expression, dict( value=value ) ) ): message = self.message if self.substitute_value_in_message: @@ -156,7 +156,7 @@ def __init__( self, message, range_min, range_max, exclude_min=False, exclude_ma op2 = '<' self.message = message or "Value must be %s %s and %s %s" % ( op1, self_min_str, op2, self_max_str ) - def validate( self, value, history=None ): + def validate( self, value, trans=None ): if self.exclude_min: if not self.min < float( value ): raise ValueError( self.message ) @@ -207,7 +207,7 @@ def __init__( self, message, length_min, length_max ): self.min = length_min self.max = length_max - def validate( self, value, history=None ): + def validate( self, value, trans=None ): if self.min is not None and len( value ) < self.min: raise ValueError( self.message or ( "Must have length of at least %d" % self.min ) ) if self.max is not None and len( value ) > self.max: @@ -226,7 +226,7 @@ def __init__( self, message=None ): def from_element( cls, param, elem ): return cls( elem.get( 'message', None ) ) - def validate( self, value, history=None ): + def validate( self, value, trans=None ): if value and value.state != model.Dataset.states.OK: if self.message is None: self.message = "The selected dataset is still being generated, select another dataset or wait until it is completed" @@ -248,7 +248,7 @@ def __init__( self, message=None, check="", skip="" ): 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 ): + def validate( self, value, trans=None ): if value: if not isinstance( value, model.DatasetInstance ): raise ValueError( 'A non-dataset value was provided.' ) @@ -274,7 +274,7 @@ def __init__( self, message=None ): def from_element( cls, param, elem ): return cls( elem.get( 'message', None ) ) - def validate( self, value, history=None ): + def validate( self, value, trans=None ): # if value is None, we cannot validate if value: dbkey = value.metadata.dbkey @@ -294,7 +294,7 @@ def __init__( self, message=None ): def from_element( cls, param, elem ): return cls( elem.get( 'message', None ) ) - def validate( self, value, history=None ): + def validate( self, value, trans=None ): if value is None: if self.message is None: self.message = "No options available for selection" @@ -311,7 +311,7 @@ def __init__( self, message=None ): def from_element( cls, param, elem ): return cls( elem.get( 'message', None ) ) - def validate( self, value, history=None ): + def validate( self, value, trans=None ): if value == '': if self.message is None: self.message = "Field requires a value" @@ -349,7 +349,7 @@ def __init__( self, filename, metadata_name, metadata_column, message="Value for if metadata_column < len( fields ): self.valid_values.append( fields[metadata_column].strip() ) - def validate( self, value, history=None ): + def validate( self, value, trans=None ): if not value: return if hasattr( value, "metadata" ): @@ -401,7 +401,7 @@ def _load_values( self ): if self._metadata_column < len( fields ): self.valid_values.append( fields[ self._metadata_column ] ) - def validate( self, value, history=None ): + def validate( self, value, trans=None ): if not value: return if hasattr( value, "metadata" ): From a272bff066516019ca74ee0012b2ae6fe02c21bc Mon Sep 17 00:00:00 2001 From: guerler Date: Fri, 22 Jan 2016 18:52:59 -0500 Subject: [PATCH 08/33] Use consistently other_values --- lib/galaxy/tools/__init__.py | 8 ++--- lib/galaxy/tools/parameters/basic.py | 52 ++++++++++++++-------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/lib/galaxy/tools/__init__.py b/lib/galaxy/tools/__init__.py index 0550da3ddd7a..dfbf36124ce8 100755 --- a/lib/galaxy/tools/__init__.py +++ b/lib/galaxy/tools/__init__.py @@ -1066,7 +1066,7 @@ def fill_in_new_state( self, trans, inputs, state, context=None, history=None ): """ context = ExpressionContext( state, context ) for input in inputs.itervalues(): - state[ input.name ] = input.get_initial_value( trans, context, history=history ) + state[ input.name ] = input.get_initial_value( trans, context ) def get_param_html_map( self, trans, page=0, other_values={} ): """ @@ -2177,7 +2177,7 @@ def check_state( trans, input, value, context ): def populate_state(trans, inputs, state, errors, incoming, prefix="", context=None ): context = ExpressionContext(state, context) for input in inputs.itervalues(): - state[input.name] = input.get_initial_value(trans, context, history=history) + state[input.name] = input.get_initial_value(trans, context) key = prefix + input.name if input.type == 'repeat': group_state = state[input.name] @@ -2238,7 +2238,7 @@ def iterate(group_inputs, inputs, state_inputs, other_values=None): tool_dict = input.to_dict(trans) if 'test_param' in tool_dict: test_param = tool_dict['test_param'] - test_param['default_value'] = jsonify(input.test_param.get_initial_value(trans, other_values, history=history)) + test_param['default_value'] = jsonify(input.test_param.get_initial_value(trans, other_values)) test_param['value'] = jsonify(group_state.get(test_param['name'], test_param['default_value'])) test_param['text_value'] = input.test_param.value_to_display_text(test_param['value'], self.app) for i in range(len( tool_dict['cases'] ) ): @@ -2260,7 +2260,7 @@ def iterate(group_inputs, inputs, state_inputs, other_values=None): # backup default value try: - tool_dict['default_value'] = input.get_initial_value(trans, other_values, history=history) + tool_dict['default_value'] = input.get_initial_value(trans, other_values) except Exception: tool_dict['default_value'] = None log.exception('tools::to_json() - Getting initial value failed %s.' % input.name) diff --git a/lib/galaxy/tools/parameters/basic.py b/lib/galaxy/tools/parameters/basic.py index 2e1fe8940c7b..b797613fb4cc 100644 --- a/lib/galaxy/tools/parameters/basic.py +++ b/lib/galaxy/tools/parameters/basic.py @@ -115,13 +115,13 @@ def from_html( self, value, trans=None, other_values={} ): def from_json( self, value, trans=None, other_values={} ): return self.from_html( value, trans, other_values ) - def get_initial_value( self, trans, context ): + def get_initial_value( self, trans, other_values ): """ Return the starting value of the parameter """ return None - def get_initial_value_from_history_prevent_repeats( self, trans, context, already_used ): + 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 @@ -129,7 +129,7 @@ def get_initial_value_from_history_prevent_repeats( self, trans, context, alread 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, context ) + return self.get_initial_value( trans, other_values ) def get_required_enctype( self ): """ @@ -297,7 +297,7 @@ def validate( self, value, history=None, workflow_building_mode=False ): if not ( workflow_building_mode and contains_workflow_parameter(value, search=search) ): return super( TextToolParameter, self ).validate( value, history ) - def get_initial_value( self, trans, context ): + def get_initial_value( self, trans, other_values ): return self.value def to_dict( self, trans, view='collection', value_mapper=None, other_values={} ): @@ -379,7 +379,7 @@ def to_python( self, value, app ): return None raise err - def get_initial_value( self, trans, context ): + def get_initial_value( self, trans, other_values ): if self.value: return int( self.value ) else: @@ -458,7 +458,7 @@ def to_python( self, value, app ): return None raise err - def get_initial_value( self, trans, context ): + def get_initial_value( self, trans, other_values ): try: return float( self.value ) except: @@ -511,7 +511,7 @@ def to_html_value( self, value, app ): def to_python( self, value, app ): return ( value in [ 'True', 'true' ]) - def get_initial_value( self, trans, context ): + def get_initial_value( self, trans, other_values ): return self.checked def to_param_dict_string( self, value, other_values={} ): @@ -601,7 +601,7 @@ def to_python( self, value, app ): else: raise Exception( "FileToolParameter cannot be persisted" ) - def get_initial_value( self, trans, context ): + def get_initial_value( self, trans, other_values ): return None @@ -618,7 +618,7 @@ def __init__( self, tool, input_source ): self.multiple = input_source.get_bool( 'multiple', True ) self.user_ftp_dir = '' - def get_initial_value( self, trans, context ): + def get_initial_value( self, trans, other_values ): if trans is not None: if trans.user is not None: self.user_ftp_dir = "%s/" % trans.user_ftp_dir @@ -700,7 +700,7 @@ def __init__( self, tool, input_source ): def get_html_field( self, trans=None, value=None, other_values={} ): return form_builder.HiddenField( self.name, self.value ) - def get_initial_value( self, trans, context ): + def get_initial_value( self, trans, other_values ): return self.value def get_label( self ): @@ -723,7 +723,7 @@ def __init__( self, tool, input_source ): def get_html_field( self, trans=None, value=None, other_values={} ): return form_builder.HiddenField( self.name, self.value ) - def get_initial_value( self, trans, context ): + def get_initial_value( self, trans, other_values ): return self.value.lower() @@ -737,7 +737,7 @@ def __init__( self, tool, input_source ): super( BaseURLToolParameter, self ).__init__( tool, input_source ) self.value = input_source.get( 'value', '' ) - def get_initial_value( self, trans, context ): + def get_initial_value( self, trans, other_values ): return self._get_value() def get_html_field( self, trans=None, value=None, other_values={} ): @@ -898,10 +898,10 @@ def get_legal_values( self, trans, other_values ): else: return self.legal_values - def get_html_field( self, trans=None, value=None, context={} ): + def get_html_field( self, trans=None, value=None, other_values={} ): # Dynamic options are not yet supported in workflow, allow # specifying the value as text for now. - options = list(self.get_options( trans, context )) + options = list(self.get_options( trans, other_values )) if len(list(options)) == 0 and trans.workflow_building_mode: if self.multiple: if value is None: @@ -1003,8 +1003,8 @@ def value_from_basic( self, value, app, ignore_errors=False ): return value[ "value" ] return super( SelectToolParameter, self ).value_from_basic( value, app, ignore_errors=ignore_errors ) - def get_initial_value( self, trans, context ): - options = list( self.get_options( trans, context ) ) + def get_initial_value( self, trans, other_values ): + options = list( self.get_options( trans, other_values ) ) if len(options) == 0 and trans.workflow_building_mode: return None value = [ optval for _, optval, selected in options if selected ] @@ -1311,10 +1311,10 @@ def get_options( self, trans, other_values ): options.append( ( 'Column: ' + col, col, False ) ) return options - def get_initial_value( self, trans, context ): + def get_initial_value( self, trans, other_values ): if self.default_value is not None: return self.default_value - return SelectToolParameter.get_initial_value( self, trans, context ) + return SelectToolParameter.get_initial_value( self, trans, other_values ) def get_legal_values( self, trans, other_values ): return set( self.get_column_list( trans, other_values ) ) @@ -1607,14 +1607,14 @@ def recurse_option( option_list, option ): rval = sanitize_param( rval ) return rval - def get_initial_value( self, trans, context ): + def get_initial_value( self, trans, other_values ): def recurse_options( initial_values, options ): for option in options: if option['selected']: initial_values.append( option['value'] ) recurse_options( initial_values, option['options'] ) # More working around dynamic options for workflow - options = self.get_options( trans=trans, other_values=context ) + options = self.get_options( trans=trans, other_values=other_values ) if len(list(options)) == 0 and trans.workflow_building_mode: return None initial_values = [] @@ -1925,10 +1925,10 @@ 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, context ): - return self.get_initial_value_from_history_prevent_repeats(trans, context, None ) + 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, context, already_used ): + 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). @@ -1937,7 +1937,7 @@ def get_initial_value_from_history_prevent_repeats( self, trans, context, alread if trans.workflow_building_mode or trans.webapp.name == 'tool_shed': return DummyDataset() history = self._get_history( trans ) - dataset_matcher = DatasetMatcher( trans, self, None, context ) + dataset_matcher = DatasetMatcher( trans, self, None, other_values ) if self.optional: return None most_recent_dataset = [] @@ -2458,7 +2458,7 @@ def __init__( self, tool, elem ): self.type = "hidden_data" self.hidden = True - def get_initial_value( self, trans, context ): + def get_initial_value( self, trans, other_values ): return None def get_html_field( self, trans=None, value=None, other_values={} ): @@ -2478,7 +2478,7 @@ def __init__( self, tool, input_source, context=None ): def get_html_field( self, trans=None, value=None, other_values={} ): return form_builder.LibraryField( self.name, value=value, trans=trans ) - def get_initial_value( self, trans, context ): + def get_initial_value( self, trans, other_values ): return None def from_html( self, value, trans, other_values={} ): From 550102915866ab4448a3e8a070437c80772320da Mon Sep 17 00:00:00 2001 From: guerler Date: Fri, 22 Jan 2016 20:05:11 -0500 Subject: [PATCH 09/33] Revise validate signature --- lib/galaxy/tools/parameters/basic.py | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/lib/galaxy/tools/parameters/basic.py b/lib/galaxy/tools/parameters/basic.py index b797613fb4cc..d738746d105d 100644 --- a/lib/galaxy/tools/parameters/basic.py +++ b/lib/galaxy/tools/parameters/basic.py @@ -210,11 +210,11 @@ def to_param_dict_string( self, value, other_values={} ): value = sanitize_param( value ) return value - def validate( self, value, history=None, workflow_building_mode=False ): + def validate( self, value, trans ): if value == "" and self.optional: return for validator in self.validators: - validator.validate( value, history ) + validator.validate( value, trans ) def to_dict( self, trans, view='collection', value_mapper=None, other_values={} ): """ to_dict tool parameter. This can be overridden by subclasses. """ @@ -292,10 +292,10 @@ def to_html_value( self, value, app ): else: return self.to_string( value, app ) - def validate( self, value, history=None, workflow_building_mode=False ): + def validate( self, value, trans ): search = self.type == "text" - if not ( workflow_building_mode and contains_workflow_parameter(value, search=search) ): - return super( TextToolParameter, self ).validate( value, history ) + if not ( trans.workflow_building_mode and contains_workflow_parameter(value, search=search) ): + return super( TextToolParameter, self ).validate( value, trans ) def get_initial_value( self, trans, other_values ): return self.value @@ -1683,13 +1683,11 @@ class BaseDataToolParameter( ToolParameter ): def __init__( self, tool, input_source, trans ): super(BaseDataToolParameter, self).__init__( tool, input_source ) - def _get_history( self, trans, history=None ): + def _get_history( self, trans ): class_name = self.__class__.__name__ assert trans is not None, "%s requires a trans" % class_name - if history is None: - history = trans.get_history() - assert history is not None, "%s requires a history" % class_name - return history + assert trans.history is not None, "%s requires a history" % class_name + return trans.history def _ensure_selection( self, field ): set_selected = field.get_selected( return_label=True, return_value=True, multi=False ) is not None @@ -2090,14 +2088,14 @@ def value_to_display_text( self, value, app ): pass return "No dataset" - def validate( self, value, history=None, workflow_building_mode=False ): + def validate( self, value, trans=None ): dataset_count = 0 for validator in self.validators: def do_validate( v ): if validator.requires_dataset_metadata and v and v.dataset.state != galaxy.model.Dataset.states.OK: return else: - validator.validate( v, history ) + validator.validate( v, trans ) if value and self.multiple: if not isinstance( value, list ): @@ -2402,7 +2400,7 @@ def value_to_display_text( self, value, app ): display_text = "No dataset collection." return display_text - def validate( self, value, history=None, workflow_building_mode=False ): + def validate( self, value, trans ): return True # TODO def to_dict( self, trans, view='collection', value_mapper=None, other_values=None ): From 4b6172299e2adc4edd117c505e5c7ddcde38c24b Mon Sep 17 00:00:00 2001 From: guerler Date: Sun, 24 Jan 2016 14:08:59 -0500 Subject: [PATCH 10/33] Use workcontext --- lib/galaxy/tools/evaluation.py | 11 ++++ lib/galaxy/tools/parameters/__init__.py | 8 +-- lib/galaxy/tools/parameters/basic.py | 70 ++++++++++++------------- lib/galaxy/work/context.py | 3 +- 4 files changed, 52 insertions(+), 40 deletions(-) diff --git a/lib/galaxy/tools/evaluation.py b/lib/galaxy/tools/evaluation.py index bfad5ed5d43d..8bdb2d83a97b 100644 --- a/lib/galaxy/tools/evaluation.py +++ b/lib/galaxy/tools/evaluation.py @@ -53,6 +53,17 @@ def set_compute_environment( self, compute_environment, get_special=None ): incoming = dict( [ ( p.name, p.value ) for p in job.parameters ] ) incoming = self.tool.params_from_strings( incoming, self.app ) + # Regular parameter validation + #def validate_inputs( input, value, prefixed_name, prefixed_label, context ): + # value = input.from_html( value, Bunch( + # user = job.history.user, + # history = job.history, + # ##user_ftp_dir = trans.user_ftp_dir, + # workflow_building_mode = False + # ), context ) + # input.validate( value, None ) + #visit_input_values ( self.tool.inputs, incoming, validate_inputs, details=True ) + # Restore input / output data lists inp_data = dict( [ ( da.name, da.dataset ) for da in job.input_datasets ] ) out_data = dict( [ ( da.name, da.dataset ) for da in job.output_datasets ] ) diff --git a/lib/galaxy/tools/parameters/__init__.py b/lib/galaxy/tools/parameters/__init__.py index e9f4563cfe27..fd63b4363896 100644 --- a/lib/galaxy/tools/parameters/__init__.py +++ b/lib/galaxy/tools/parameters/__init__.py @@ -6,7 +6,7 @@ from grouping import Conditional, Repeat, Section, UploadDataset from galaxy.util.json import dumps, json_fix, loads from galaxy.util.expressions import ExpressionContext -from galaxy.util.bunch import Bunch +from galaxy.work.context import WorkRequestContext REPLACE_ON_TRUTHY = object() @@ -69,10 +69,10 @@ def check_param( trans, param, incoming_value, param_values, source='html', bool previous parameters (this may actually be an ExpressionContext when dealing with grouping scenarios). """ - request_context = Bunch( + request_context = WorkRequestContext( + app = trans.app, user = trans.user, - history = trans.history, - user_ftp_dir = trans.user_ftp_dir, + history = history or trans.history, workflow_building_mode = workflow_building_mode ) value = incoming_value diff --git a/lib/galaxy/tools/parameters/basic.py b/lib/galaxy/tools/parameters/basic.py index d738746d105d..3ab296f1f373 100644 --- a/lib/galaxy/tools/parameters/basic.py +++ b/lib/galaxy/tools/parameters/basic.py @@ -560,7 +560,7 @@ def from_html( self, value, trans=None, other_values={} ): # Middleware or proxies may encode files in special ways (TODO: this # should be pluggable) if type( value ) == dict: - upload_store = self.app.config.nginx_upload_store + upload_store = trans.app.config.nginx_upload_store assert upload_store, \ "Request appears to have been processed by nginx_upload_module \ but Galaxy is not configured to recognize it" @@ -635,7 +635,7 @@ def get_html_field( self, trans=None, value=None, other_values={} ): user_ftp_dir = None else: user_ftp_dir = trans.user_ftp_dir - return form_builder.FTPFileField( self.name, user_ftp_dir, self.app.config.ftp_upload_site, value=value ) + return form_builder.FTPFileField( self.name, user_ftp_dir, trans.app.config.ftp_upload_site, value=value ) def to_param_dict_string( self, value, other_values={} ): if value is '': @@ -1151,7 +1151,7 @@ def _get_dbkey_names( self, trans=None ): if not self.tool: # Hack for unit tests, since we have no tool return util.read_dbnames( None ) - return self.app.genome_builds.get_genome_build_names( trans=trans ) + return trans.app.genome_builds.get_genome_build_names( trans=trans ) class ColumnListParameter( SelectToolParameter ): @@ -1708,7 +1708,7 @@ def _datatypes_registery( self, trans, tool ): if trans: # Must account for "Input Dataset" types, which while not a tool still need access to the real registry. # A handle to the transaction (and thus app) will be given by the module. - datatypes_registry = self.app.datatypes_registry + datatypes_registry = trans.app.datatypes_registry else: # This occurs for things such as unit tests import galaxy.datatypes.registry @@ -1866,7 +1866,7 @@ def value_modifier(value): name = history_dataset_collection.name hid = str( history_dataset_collection.hid ) hidden_text = "" # TODO - id = value_modifier( self.app.security.encode_id( history_dataset_collection.id ) ) + id = value_modifier( dataset_matcher.app.security.encode_id( history_dataset_collection.id ) ) selected = value and history_dataset_collection in value text = "%s:%s %s" % ( hid, hidden_text, name ) field.add_option( text, id, selected ) @@ -1978,44 +1978,44 @@ def from_html( self, value, trans, other_values={} ): for single_value in value: if isinstance( single_value, dict ) and 'src' in single_value and 'id' in single_value: if single_value['src'] == 'hda': - rval.append( self.app.model.context.query( self.app.model.HistoryDatasetAssociation ).get( self.app.security.decode_id(single_value['id']) )) + rval.append( trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( trans.app.security.decode_id(single_value['id']) )) elif single_value['src'] == 'hdca': found_hdca = True - decoded_id = self.app.security.decode_id( single_value[ 'id' ] ) - rval.append( self.app.model.context.query( self.app.model.HistoryDatasetCollectionAssociation ).get( decoded_id ) ) + decoded_id = trans.app.security.decode_id( single_value[ 'id' ] ) + rval.append( trans.sa_session.query( trans.app.model.HistoryDatasetCollectionAssociation ).get( decoded_id ) ) else: raise ValueError("Unknown input source %s passed to job submission API." % single_value['src']) - elif isinstance( single_value, self.app.model.HistoryDatasetCollectionAssociation ): + elif isinstance( single_value, trans.app.model.HistoryDatasetCollectionAssociation ): rval.append( single_value ) - elif isinstance( single_value, self.app.model.HistoryDatasetAssociation ): + elif isinstance( single_value, trans.app.model.HistoryDatasetAssociation ): rval.append( single_value ) else: - rval.append( self.app.model.context.query( self.app.model.HistoryDatasetAssociation ).get( single_value ) ) + rval.append( trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( single_value ) ) if found_hdca: for val in rval: - if not isinstance( val, self.app.model.HistoryDatasetCollectionAssociation ): + if not isinstance( val, trans.app.model.HistoryDatasetCollectionAssociation ): raise ValueError( "If collections are supplied to multiple data input parameter, only collections may be used." ) - elif isinstance( value, self.app.model.HistoryDatasetAssociation ): + elif isinstance( value, trans.app.model.HistoryDatasetAssociation ): rval = value elif isinstance( value, dict ) and 'src' in value and 'id' in value: if value['src'] == 'hda': - rval = self.app.model.context.query( self.app.model.HistoryDatasetAssociation ).get( self.app.security.decode_id(value['id']) ) + rval = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( trans.app.security.decode_id(value['id']) ) elif value['src'] == 'hdca': - decoded_id = self.app.security.decode_id( value[ 'id' ] ) - rval = self.app.model.context.query( self.app.model.HistoryDatasetCollectionAssociation ).get( decoded_id ) + decoded_id = trans.app.security.decode_id( value[ 'id' ] ) + rval = trans.sa_session.query( trans.app.model.HistoryDatasetCollectionAssociation ).get( decoded_id ) else: raise ValueError("Unknown input source %s passed to job submission API." % value['src']) elif str( value ).startswith( "__collection_reduce__|" ): encoded_ids = [ v[ len( "__collection_reduce__|" ): ] for v in str( value ).split(",") ] - decoded_ids = map( self.app.security.decode_id, encoded_ids ) + decoded_ids = map( trans.app.security.decode_id, encoded_ids ) rval = [] for decoded_id in decoded_ids: - hdca = self.app.model.context.query( self.app.model.HistoryDatasetCollectionAssociation ).get( decoded_id ) + hdca = trans.sa_session.query( trans.app.model.HistoryDatasetCollectionAssociation ).get( decoded_id ) rval.append( hdca ) - elif isinstance( value, self.app.model.HistoryDatasetCollectionAssociation ): + elif isinstance( value, trans.app.model.HistoryDatasetCollectionAssociation ): rval = value else: - rval = self.app.model.context.query( self.app.model.HistoryDatasetAssociation ).get( value ) + rval = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( value ) if isinstance( rval, list ): values = rval else: @@ -2201,7 +2201,7 @@ def to_dict( self, trans, view='collection', value_mapper=None, other_values={} if match: m = match.hda d['options']['hda'].append({ - 'id' : self.app.security.encode_id( m.id ), + 'id' : trans.app.security.encode_id( m.id ), 'hid' : m.hid, 'name' : m.name if m.visible else '(hidden) %s' % m.name, 'src' : 'hda' @@ -2212,7 +2212,7 @@ def to_dict( self, trans, view='collection', value_mapper=None, other_values={} for hdca in history.active_dataset_collections: if dataset_collection_matcher.hdca_match( hdca, reduction=multiple ): d['options']['hdca'].append({ - 'id' : self.app.security.encode_id( hdca.id ), + 'id' : trans.app.security.encode_id( hdca.id ), 'hid' : hdca.hid, 'name' : hdca.name, 'src' : 'hdca' @@ -2247,7 +2247,7 @@ def collection_types( self ): return self._collection_types def _history_query( self, trans ): - dataset_collection_type_descriptions = self.app.dataset_collections_service.collection_type_descriptions + dataset_collection_type_descriptions = trans.app.dataset_collections_service.collection_type_descriptions return history_query.HistoryQuery.from_parameter( self, dataset_collection_type_descriptions ) def get_html_field( self, trans=None, value=None, other_values={} ): @@ -2270,7 +2270,7 @@ def get_html_field( self, trans=None, value=None, other_values={} ): return self._switch_fields( fields, default_field=default_field ) def match_collections( self, trans, history, dataset_matcher ): - dataset_collections = self.app.dataset_collections_service.history_dataset_collections( history, self._history_query( trans ) ) + dataset_collections = trans.app.dataset_collections_service.history_dataset_collections( history, self._history_query( trans ) ) dataset_collection_matcher = DatasetCollectionMatcher( dataset_matcher ) for dataset_collection_instance in dataset_collections: @@ -2315,7 +2315,7 @@ def _get_select_dataset_collection_field( self, trans, history, multiple=False, hid = str( history_dataset_collection.hid ) hidden_text = "" # TODO subcollection_type = self._history_query( trans ).collection_type_description.collection_type - id = "%s|%s" % ( self.app.security.encode_id( history_dataset_collection.id ), subcollection_type ) + id = "%s|%s" % ( trans.app.security.encode_id( history_dataset_collection.id ), subcollection_type ) text = "%s:%s %s" % ( hid, hidden_text, name ) field.add_option( text, id, False ) @@ -2329,30 +2329,30 @@ def from_html( self, value, trans, other_values={} ): return None if isinstance( value, str ) and value.find( "," ) > 0: value = [ int( value_part ) for value_part in value.split( "," ) ] - elif isinstance( value, self.app.model.HistoryDatasetCollectionAssociation ): + elif isinstance( value, trans.app.model.HistoryDatasetCollectionAssociation ): rval = value - elif isinstance( value, self.app.model.DatasetCollectionElement ): + elif isinstance( value, trans.app.model.DatasetCollectionElement ): # When mapping over nested collection - this paramter will recieve # a DatasetCollectionElement instead of a # HistoryDatasetCollectionAssociation. rval = value elif isinstance( value, dict ) and 'src' in value and 'id' in value: if value['src'] == 'hdca': - rval = self.app.model.context.query( self.app.model.HistoryDatasetCollectionAssociation ).get( self.app.security.decode_id(value['id']) ) + rval = trans.sa_session.query( trans.app.model.HistoryDatasetCollectionAssociation ).get( trans.app.security.decode_id(value['id']) ) elif isinstance( value, list ): if len( value ) > 0: value = value[0] if isinstance( value, dict ) and 'src' in value and 'id' in value: if value['src'] == 'hdca': - rval = self.app.model.context.query( self.app.model.HistoryDatasetCollectionAssociation ).get( self.app.security.decode_id(value['id']) ) + rval = trans.sa_session.query( trans.app.model.HistoryDatasetCollectionAssociation ).get( trans.app.security.decode_id(value['id']) ) elif isinstance( value, basestring ): if value.startswith( "dce:" ): - rval = self.app.model.context.query( self.app.model.DatasetCollectionElement ).get( value[ len( "dce:"): ] ) + rval = trans.sa_session.query( trans.app.model.DatasetCollectionElement ).get( value[ len( "dce:"): ] ) elif value.startswith( "hdca:" ): - rval = self.app.model.context.query( self.app.model.HistoryDatasetCollectionAssociation ).get( value[ len( "hdca:"): ] ) + rval = trans.sa_session.query( trans.app.model.HistoryDatasetCollectionAssociation ).get( value[ len( "hdca:"): ] ) else: - rval = self.app.model.context.query( self.app.model.HistoryDatasetCollectionAssociation ).get( value ) - if rval and isinstance( rval, self.app.model.HistoryDatasetCollectionAssociation ): + rval = trans.sa_session.query( trans.app.model.HistoryDatasetCollectionAssociation ).get( value ) + if rval and isinstance( rval, trans.app.model.HistoryDatasetCollectionAssociation ): if rval.deleted: raise ValueError( "The previously selected dataset collection has been deleted" ) # TODO: Handle error states, implement error states ... @@ -2421,7 +2421,7 @@ def to_dict( self, trans, view='collection', value_mapper=None, other_values=Non # append directly matched collections for hdca in self.match_collections( trans, history, dataset_matcher ): d['options']['hdca'].append({ - 'id': self.app.security.encode_id( hdca.id ), + 'id': trans.app.security.encode_id( hdca.id ), 'hid': hdca.hid, 'name': hdca.name, 'src': 'hdca' @@ -2431,7 +2431,7 @@ def to_dict( self, trans, view='collection', value_mapper=None, other_values=Non for hdca in self.match_multirun_collections( trans, history, dataset_matcher ): subcollection_type = self._history_query( trans ).can_map_over( hdca ).collection_type d['options']['hdca'].append({ - 'id': self.app.security.encode_id( hdca.id ), + 'id': trans.app.security.encode_id( hdca.id ), 'hid': hdca.hid, 'name': hdca.name, 'src': 'hdca', diff --git a/lib/galaxy/work/context.py b/lib/galaxy/work/context.py index 47782440b008..323d5d23661d 100644 --- a/lib/galaxy/work/context.py +++ b/lib/galaxy/work/context.py @@ -18,12 +18,13 @@ class WorkRequestContext( ProvidesAppContext, ProvidesUserContext, ProvidesHisto objects. """ - def __init__( self, app, user=None, history=None ): + def __init__( self, app, user=None, history=None, workflow_building_mode=None ): self.app = app self.security = app.security self.__user = user self.__history = history self.api_inherit_admin = False + self.workflow_building_mode = workflow_building_mode def get_history( self, create=False ): if create: From eaf02029d43620db309e2860d4502e0f830bc2a9 Mon Sep 17 00:00:00 2001 From: guerler Date: Sun, 24 Jan 2016 14:14:37 -0500 Subject: [PATCH 11/33] Fix remaining self.app, use workcontext app --- lib/galaxy/tools/parameters/basic.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/galaxy/tools/parameters/basic.py b/lib/galaxy/tools/parameters/basic.py index 3ab296f1f373..acd3a39cfb21 100644 --- a/lib/galaxy/tools/parameters/basic.py +++ b/lib/galaxy/tools/parameters/basic.py @@ -51,7 +51,6 @@ class ToolParameter( object, Dictifiable ): def __init__( self, tool, input_source, context=None ): input_source = ensure_input_source(input_source) - self.app = tool.app self.tool = tool self.refresh_on_change = False self.refresh_on_change_values = [] @@ -647,7 +646,7 @@ def to_param_dict_string( self, value, other_values={} ): return lst[ 0 ] def from_html( self, value, trans=None, other_values={} ): - return self.to_python( value, self.app, validate=True ) + return self.to_python( value, trans.app, validate=True ) def to_string( self, value, app ): return self.to_python( value, app ) @@ -2480,7 +2479,7 @@ def get_initial_value( self, trans, other_values ): return None def from_html( self, value, trans, other_values={} ): - return self.to_python( value, self.app, other_values=other_values, validate=True ) + return self.to_python( value, trans.app, other_values=other_values, validate=True ) def to_param_dict_string( self, value, other_values={} ): if value is None: From 5a72480719055ac4a6d04ff690f69d5a118b5c81 Mon Sep 17 00:00:00 2001 From: guerler Date: Sun, 24 Jan 2016 14:21:07 -0500 Subject: [PATCH 12/33] Fix dataset selection --- lib/galaxy/tools/parameters/basic.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/galaxy/tools/parameters/basic.py b/lib/galaxy/tools/parameters/basic.py index acd3a39cfb21..613fad22e517 100644 --- a/lib/galaxy/tools/parameters/basic.py +++ b/lib/galaxy/tools/parameters/basic.py @@ -901,7 +901,7 @@ def get_html_field( self, trans=None, value=None, other_values={} ): # Dynamic options are not yet supported in workflow, allow # specifying the value as text for now. options = list(self.get_options( trans, other_values )) - if len(list(options)) == 0 and trans.workflow_building_mode: + if len( list( options ) ) == 0 and trans.workflow_building_mode: if self.multiple: if value is None: value = "" @@ -1529,7 +1529,7 @@ def get_html_field( self, trans=None, value=None, other_values={} ): # Dynamic options are not yet supported in workflow, allow # specifying the value as text for now. options = self.get_options( trans, value, other_values ) - if len(list(options)) == 0 and trans.workflow_building_mode: + if len( list( options ) ) == 0 and trans.workflow_building_mode: if self.multiple: if value is None: value = "" @@ -1795,7 +1795,7 @@ def __init__( self, tool, input_source, trans=None): conv_types = [ tool.app.datatypes_registry.get_datatype_by_extension( conv_extensions.lower() ) ] self.conversions.append( ( name, conv_extensions, conv_types ) ) - def get_html_field( self, trans=None, value=None, other_values={} ): + def get_html_field( self, trans, value=None, other_values={} ): if value is not None: if type( value ) != list: value = [ value ] @@ -1811,7 +1811,7 @@ def get_html_field( self, trans=None, value=None, other_values={} ): fields[ "multiselect_single" ] = multi_select if self.__display_multirun_option(): - collection_select = self._get_select_dataset_collection_fields( history, dataset_matcher, suffix="", reduction=True ) + collection_select = self._get_select_dataset_collection_fields( trans, dataset_matcher, suffix="", reduction=True ) if collection_select.get_selected(return_value=True): default_field = "multiselect_collection" fields[ "multiselect_collection" ] = collection_select @@ -1840,12 +1840,12 @@ def get_html_field( self, trans=None, value=None, other_values={} ): multi_dataset_matcher = DatasetMatcher( trans, self, multirun_value, other_values ) multi_select = self._get_select_dataset_field( history, multi_dataset_matcher, multiple=True, suffix="|__multirun__" ) fields[ "select_multiple" ] = multi_select - collection_field = self._get_select_dataset_collection_fields( history, dataset_matcher, multiple=False, reduction=False ) + collection_field = self._get_select_dataset_collection_fields( trans, dataset_matcher, multiple=False, reduction=False ) fields[ "select_collection" ] = collection_field return self._switch_fields( fields, default_field=default_field ) - def _get_select_dataset_collection_fields( self, history, dataset_matcher, multiple=False, suffix="|__collection_multirun__", reduction=False ): + def _get_select_dataset_collection_fields( self, trans, dataset_matcher, multiple=False, suffix="|__collection_multirun__", reduction=False ): if not reduction: def value_modifier(x): return x @@ -1861,11 +1861,11 @@ def value_modifier(value): field_name = "%s%s" % ( self.name, suffix ) field = form_builder.SelectField( field_name, multiple, None, self.refresh_on_change, refresh_on_change_values=self.refresh_on_change_values ) - for history_dataset_collection in self.match_collections( history, dataset_matcher, reduction=reduction ): + for history_dataset_collection in self.match_collections( trans.history, dataset_matcher, reduction=reduction ): name = history_dataset_collection.name hid = str( history_dataset_collection.hid ) hidden_text = "" # TODO - id = value_modifier( dataset_matcher.app.security.encode_id( history_dataset_collection.id ) ) + id = value_modifier( trans.app.security.encode_id( history_dataset_collection.id ) ) selected = value and history_dataset_collection in value text = "%s:%s %s" % ( hid, hidden_text, name ) field.add_option( text, id, selected ) From 7cc505019d2b2af938b61efe0e00bd25a13af91b Mon Sep 17 00:00:00 2001 From: guerler Date: Sun, 24 Jan 2016 14:24:33 -0500 Subject: [PATCH 13/33] Use sa_session of workcontext --- lib/galaxy/util/dbkeys.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/galaxy/util/dbkeys.py b/lib/galaxy/util/dbkeys.py index 8aa66bbf8c7f..e57f28e290be 100644 --- a/lib/galaxy/util/dbkeys.py +++ b/lib/galaxy/util/dbkeys.py @@ -33,7 +33,7 @@ def get_genome_build_names( self, trans=None ): # It does allow one-off, history specific dbkeys to be created by a user. But we are not filtering, # so a len file will be listed twice (as the build name and again as dataset name), # if custom dbkey creation/conversion occurred within the current history. - datasets = self._app.model.context.query( self._app.model.HistoryDatasetAssociation ) \ + datasets = trans.sa_session.query( self._app.model.HistoryDatasetAssociation ) \ .filter_by( deleted=False, history_id=trans.history.id, extension="len" ) for dataset in datasets: rval.append( ( dataset.dbkey, "%s (%s) [History]" % ( dataset.name, dataset.dbkey ) ) ) @@ -72,11 +72,11 @@ def get_chrom_info( self, dbkey, trans=None, custom_build_hack_get_len_from_fast # fasta-to-len converter. if 'fasta' in custom_build_dict and custom_build_hack_get_len_from_fasta_conversion: # Build is defined by fasta; get len file, which is obtained from converting fasta. - build_fasta_dataset = self._app.model.context.query( self._app.model.HistoryDatasetAssociation ).get( custom_build_dict[ 'fasta' ] ) + build_fasta_dataset = trans.sa_session.query( self._app.model.HistoryDatasetAssociation ).get( custom_build_dict[ 'fasta' ] ) chrom_info = build_fasta_dataset.get_converted_dataset( trans, 'len' ).file_name elif 'len' in custom_build_dict: # Build is defined by len file, so use it. - chrom_info = self._app.model.context.query( self._app.model.HistoryDatasetAssociation ).get( custom_build_dict[ 'len' ] ).file_name + chrom_info = trans.sa_session.query( self._app.model.HistoryDatasetAssociation ).get( custom_build_dict[ 'len' ] ).file_name # Check Data table if not chrom_info: dbkey_table = self._app.tool_data_tables.get( self._data_table_name, None ) From b56574115fa9ae32f2d4703f0b257991ad2f4c26 Mon Sep 17 00:00:00 2001 From: guerler Date: Sun, 24 Jan 2016 14:26:06 -0500 Subject: [PATCH 14/33] Fix trans usage --- lib/galaxy/util/dbkeys.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/galaxy/util/dbkeys.py b/lib/galaxy/util/dbkeys.py index e57f28e290be..216e7cb6d388 100644 --- a/lib/galaxy/util/dbkeys.py +++ b/lib/galaxy/util/dbkeys.py @@ -72,11 +72,11 @@ def get_chrom_info( self, dbkey, trans=None, custom_build_hack_get_len_from_fast # fasta-to-len converter. if 'fasta' in custom_build_dict and custom_build_hack_get_len_from_fasta_conversion: # Build is defined by fasta; get len file, which is obtained from converting fasta. - build_fasta_dataset = trans.sa_session.query( self._app.model.HistoryDatasetAssociation ).get( custom_build_dict[ 'fasta' ] ) + build_fasta_dataset = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( custom_build_dict[ 'fasta' ] ) chrom_info = build_fasta_dataset.get_converted_dataset( trans, 'len' ).file_name elif 'len' in custom_build_dict: # Build is defined by len file, so use it. - chrom_info = trans.sa_session.query( self._app.model.HistoryDatasetAssociation ).get( custom_build_dict[ 'len' ] ).file_name + chrom_info = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( custom_build_dict[ 'len' ] ).file_name # Check Data table if not chrom_info: dbkey_table = self._app.tool_data_tables.get( self._data_table_name, None ) From 93dbf742b36b614bacbb7a806431532567203b70 Mon Sep 17 00:00:00 2001 From: guerler Date: Sun, 24 Jan 2016 14:30:08 -0500 Subject: [PATCH 15/33] Reinsert last validation --- lib/galaxy/tools/evaluation.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/galaxy/tools/evaluation.py b/lib/galaxy/tools/evaluation.py index 8bdb2d83a97b..34011f157548 100644 --- a/lib/galaxy/tools/evaluation.py +++ b/lib/galaxy/tools/evaluation.py @@ -54,15 +54,15 @@ def set_compute_environment( self, compute_environment, get_special=None ): incoming = self.tool.params_from_strings( incoming, self.app ) # Regular parameter validation - #def validate_inputs( input, value, prefixed_name, prefixed_label, context ): - # value = input.from_html( value, Bunch( - # user = job.history.user, - # history = job.history, - # ##user_ftp_dir = trans.user_ftp_dir, - # workflow_building_mode = False - # ), context ) - # input.validate( value, None ) - #visit_input_values ( self.tool.inputs, incoming, validate_inputs, details=True ) + def validate_inputs( input, value, prefixed_name, prefixed_label, context ): + value = input.from_html( value, Bunch( + app = app, + user = job.history.user, + history = job.history, + workflow_building_mode = False + ), context ) + input.validate( value, None ) + visit_input_values ( self.tool.inputs, incoming, validate_inputs, details=True ) # Restore input / output data lists inp_data = dict( [ ( da.name, da.dataset ) for da in job.input_datasets ] ) From 7c69227c8cde400df37f5e9390fdd88e51f64f2a Mon Sep 17 00:00:00 2001 From: guerler Date: Sun, 24 Jan 2016 15:17:56 -0500 Subject: [PATCH 16/33] Fix db_builds --- lib/galaxy/tools/parameters/basic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/galaxy/tools/parameters/basic.py b/lib/galaxy/tools/parameters/basic.py index 613fad22e517..1a5f31678725 100644 --- a/lib/galaxy/tools/parameters/basic.py +++ b/lib/galaxy/tools/parameters/basic.py @@ -1150,7 +1150,7 @@ def _get_dbkey_names( self, trans=None ): if not self.tool: # Hack for unit tests, since we have no tool return util.read_dbnames( None ) - return trans.app.genome_builds.get_genome_build_names( trans=trans ) + return self.tool.app.genome_builds.get_genome_build_names( trans=trans ) class ColumnListParameter( SelectToolParameter ): From 269ce36d3f5212b2d98315a67b25cc6db5a3429c Mon Sep 17 00:00:00 2001 From: guerler Date: Sun, 24 Jan 2016 17:30:10 -0500 Subject: [PATCH 17/33] Fix check params --- lib/galaxy/tools/__init__.py | 24 ++++++++++++------------ lib/galaxy/tools/evaluation.py | 17 +++++++++-------- lib/galaxy/tools/execute.py | 2 +- lib/galaxy/workflow/modules.py | 2 +- 4 files changed, 23 insertions(+), 22 deletions(-) diff --git a/lib/galaxy/tools/__init__.py b/lib/galaxy/tools/__init__.py index dfbf36124ce8..e4a90f74b702 100755 --- a/lib/galaxy/tools/__init__.py +++ b/lib/galaxy/tools/__init__.py @@ -1648,17 +1648,17 @@ def params_to_strings( self, 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, update_values=True, allow_workflow_parameters=False ): + 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, update_values=update_values, allow_workflow_parameters=allow_workflow_parameters ) + 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="", update_values=True, allow_workflow_parameters=False ): + 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` """ @@ -1673,7 +1673,7 @@ def check_and_update_param_values_helper( self, inputs, values, trans, messages, messages[ input.name ] = cond_messages test_value = input.test_param.get_initial_value( trans, context ) current_case = input.get_current_case( test_value, trans ) - self.check_and_update_param_values_helper( input.cases[ current_case ].inputs, {}, trans, cond_messages, context, prefix, allow_workflow_parameters=allow_workflow_parameters ) + self.check_and_update_param_values_helper( input.cases[ current_case ].inputs, {}, trans, cond_messages, context, prefix ) elif isinstance( input, Repeat ): if input.min: messages[ input.name ] = [] @@ -1681,10 +1681,10 @@ def check_and_update_param_values_helper( self, inputs, values, trans, messages, rep_prefix = prefix + "%s %d > " % ( input.title, i + 1 ) rep_dict = dict() messages[ input.name ].append( rep_dict ) - self.check_and_update_param_values_helper( input.inputs, {}, trans, rep_dict, context, rep_prefix, allow_workflow_parameters=allow_workflow_parameters ) + self.check_and_update_param_values_helper( input.inputs, {}, trans, rep_dict, context, rep_prefix ) elif isinstance( input, Section ): messages[ input.name ] = {} - self.check_and_update_param_values_helper( input.inputs, {}, trans, messages[ input.name ], context, prefix, allow_workflow_parameters=allow_workflow_parameters ) + self.check_and_update_param_values_helper( input.inputs, {}, trans, messages[ input.name ], context, prefix ) else: messages[ input.name ] = "No value found for '%s%s', using default" % ( prefix, input.label ) values[ input.name ] = input.get_initial_value( trans, context ) @@ -1693,7 +1693,7 @@ def check_and_update_param_values_helper( self, inputs, values, trans, messages, if isinstance( input, Repeat ): for i, d in enumerate( values[ input.name ] ): rep_prefix = prefix + "%s %d > " % ( input.title, i + 1 ) - self.check_and_update_param_values_helper( input.inputs, d, trans, messages, context, rep_prefix, allow_workflow_parameters=allow_workflow_parameters ) + self.check_and_update_param_values_helper( input.inputs, d, trans, messages, context, rep_prefix ) elif isinstance( input, Conditional ): group_values = values[ input.name ] use_initial_value = False @@ -1711,22 +1711,22 @@ def check_and_update_param_values_helper( self, inputs, values, trans, messages, messages[ child_input.name ] = "Value no longer valid for '%s%s', replacing with default" % ( prefix, child_input.label ) else: current = group_values["__current_case__"] - self.check_and_update_param_values_helper( input.cases[current].inputs, group_values, trans, messages, context, prefix, allow_workflow_parameters=allow_workflow_parameters ) + self.check_and_update_param_values_helper( input.cases[current].inputs, group_values, trans, messages, context, prefix ) elif isinstance( input, Section ): messages[ input.name ] = {} - self.check_and_update_param_values_helper( input.inputs, values[ input.name ], trans, messages[ input.name ], context, prefix, allow_workflow_parameters=allow_workflow_parameters ) + self.check_and_update_param_values_helper( input.inputs, values[ input.name ], trans, messages[ input.name ], context, prefix ) else: # Regular tool parameter, no recursion needed try: value = values[ input.name ] - if not allow_workflow_parameters: + if not trans.workflow_building_mode: input.value_from_basic( input.value_to_basic( value, trans.app ), trans.app, ignore_errors=False ) - input.validate( value, history=trans.history ) + input.validate( value, trans ) else: # skip check if is workflow parameters ck_param = True search = input.type in ["text"] - if allow_workflow_parameters and contains_workflow_parameter( values[ input.name ], search=search ): + if trans.workflow_building_mode and contains_workflow_parameter( values[ input.name ], search=search ): ck_param = False # this will fail when a parameter's type has changed to a non-compatible one: e.g. conditional group changed to dataset input if ck_param: diff --git a/lib/galaxy/tools/evaluation.py b/lib/galaxy/tools/evaluation.py index 34011f157548..f23f73f11557 100644 --- a/lib/galaxy/tools/evaluation.py +++ b/lib/galaxy/tools/evaluation.py @@ -25,7 +25,7 @@ from galaxy.tools.parameters.grouping import Conditional, Repeat, Section from galaxy.tools import global_tool_errors from galaxy.jobs.datasets import dataset_path_rewrites - +from galaxy.work.context import WorkRequestContext import logging log = logging.getLogger( __name__ ) @@ -54,14 +54,15 @@ def set_compute_environment( self, compute_environment, get_special=None ): incoming = self.tool.params_from_strings( incoming, self.app ) # Regular parameter validation + request_context = WorkRequestContext( + app = self.app, + user = job.history.user, + history = job.history, + workflow_building_mode = False + ) def validate_inputs( input, value, prefixed_name, prefixed_label, context ): - value = input.from_html( value, Bunch( - app = app, - user = job.history.user, - history = job.history, - workflow_building_mode = False - ), context ) - input.validate( value, None ) + value = input.from_html( value, request_context, context ) + input.validate( value, request_context ) visit_input_values ( self.tool.inputs, incoming, validate_inputs, details=True ) # Restore input / output data lists diff --git a/lib/galaxy/tools/execute.py b/lib/galaxy/tools/execute.py index e1763f346156..3a2bc03bc456 100644 --- a/lib/galaxy/tools/execute.py +++ b/lib/galaxy/tools/execute.py @@ -39,7 +39,7 @@ def execute_single_job(params): # the state we about to execute one last time. Consider whether tool executions # should run this as well. if workflow_invocation_uuid: - messages = tool.check_and_update_param_values( params, trans, update_values=False, allow_workflow_parameters=False ) + messages = tool.check_and_update_param_values( params, trans, update_values=False ) if messages: execution_tracker.record_error( messages ) return diff --git a/lib/galaxy/workflow/modules.py b/lib/galaxy/workflow/modules.py index 7ae7aa45925e..37931da7e5b6 100644 --- a/lib/galaxy/workflow/modules.py +++ b/lib/galaxy/workflow/modules.py @@ -1080,7 +1080,7 @@ def item_callback( trans, key, input, value, error, old_value, context ): def check_and_update_state( self ): inputs = self.state.inputs - return self.tool.check_and_update_param_values( inputs, self.trans, allow_workflow_parameters=True ) + return self.tool.check_and_update_param_values( inputs, self.trans ) def compute_runtime_state( self, trans, step_updates=None, source="html" ): # Warning: This method destructively modifies existing step state. From 3acdee5143586d0224f896d2bfc5c085e3409349 Mon Sep 17 00:00:00 2001 From: guerler Date: Sun, 24 Jan 2016 17:58:41 -0500 Subject: [PATCH 18/33] Show validation error for workflow step preparation --- lib/galaxy/jobs/runners/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/galaxy/jobs/runners/__init__.py b/lib/galaxy/jobs/runners/__init__.py index 0e6b78607d8d..608aabfa9c5c 100644 --- a/lib/galaxy/jobs/runners/__init__.py +++ b/lib/galaxy/jobs/runners/__init__.py @@ -169,9 +169,9 @@ def prepare_job(self, job_wrapper, include_metadata=False, include_work_dir_outp include_metadata=include_metadata, include_work_dir_outputs=include_work_dir_outputs, ) - except: + except Exception, e: log.exception("(%s) Failure preparing job" % job_id) - job_wrapper.fail( "failure preparing job", exception=True ) + job_wrapper.fail( e.message if hasattr( e, 'message' ) else "Job preparation failed", exception=True ) return False if not job_wrapper.runner_command_line: From b38479c4a49efcf2c56e400b56d1da4f5eb4a02d Mon Sep 17 00:00:00 2001 From: guerler Date: Sun, 24 Jan 2016 18:20:20 -0500 Subject: [PATCH 19/33] Remove unvalidated value handling in workflow extraction --- lib/galaxy/tools/parameters/basic.py | 2 +- lib/galaxy/work/context.py | 2 +- lib/galaxy/workflow/extract.py | 3 --- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/galaxy/tools/parameters/basic.py b/lib/galaxy/tools/parameters/basic.py index 1a5f31678725..ff4e4254cbbc 100644 --- a/lib/galaxy/tools/parameters/basic.py +++ b/lib/galaxy/tools/parameters/basic.py @@ -1614,7 +1614,7 @@ def recurse_options( initial_values, options ): recurse_options( initial_values, option['options'] ) # More working around dynamic options for workflow options = self.get_options( trans=trans, other_values=other_values ) - if len(list(options)) == 0 and trans.workflow_building_mode: + if len( list( options ) ) == 0 and trans.workflow_building_mode: return None initial_values = [] recurse_options( initial_values, options ) diff --git a/lib/galaxy/work/context.py b/lib/galaxy/work/context.py index 323d5d23661d..4252ef9f4a02 100644 --- a/lib/galaxy/work/context.py +++ b/lib/galaxy/work/context.py @@ -18,7 +18,7 @@ class WorkRequestContext( ProvidesAppContext, ProvidesUserContext, ProvidesHisto objects. """ - def __init__( self, app, user=None, history=None, workflow_building_mode=None ): + def __init__( self, app, user=None, history=None, workflow_building_mode=False ): self.app = app self.security = app.security self.__user = user diff --git a/lib/galaxy/workflow/extract.py b/lib/galaxy/workflow/extract.py index c9309192645f..8971dbb4b6ff 100644 --- a/lib/galaxy/workflow/extract.py +++ b/lib/galaxy/workflow/extract.py @@ -317,9 +317,6 @@ def __cleanup_param_values( inputs, values ): # Recursively clean data inputs and dynamic selects def cleanup( prefix, inputs, values ): for key, input in inputs.items(): - if isinstance( input, ( SelectToolParameter, DrillDownSelectToolParameter ) ): - if input.is_dynamic and not isinstance( values[key], UnvalidatedValue ): - values[key] = UnvalidatedValue( values[key] ) if isinstance( input, DataToolParameter ) or isinstance( input, DataCollectionToolParameter ): tmp = values[key] values[key] = None From 6939c99f1bb06532e5c4cb4c2a4ef936075b4569 Mon Sep 17 00:00:00 2001 From: guerler Date: Sun, 24 Jan 2016 18:29:19 -0500 Subject: [PATCH 20/33] Remove more unvalidated value hacks --- lib/galaxy/jobs/__init__.py | 4 +--- lib/galaxy/tools/__init__.py | 13 +------------ lib/galaxy/tools/imp_exp/__init__.py | 3 --- lib/galaxy/tools/parameters/basic.py | 10 ---------- lib/galaxy/workflow/extract.py | 3 +-- 5 files changed, 3 insertions(+), 30 deletions(-) diff --git a/lib/galaxy/jobs/__init__.py b/lib/galaxy/jobs/__init__.py index 4759fa8f1b47..9892732d698b 100644 --- a/lib/galaxy/jobs/__init__.py +++ b/lib/galaxy/jobs/__init__.py @@ -1301,9 +1301,7 @@ def path_rewriter( path ): if not data: continue input_ext = data.ext - # why not re-use self.param_dict here? ##dunno...probably should, this causes - # tools.parameters.basic.UnvalidatedValue to be used in following methods - # instead of validated and transformed values during i.e. running workflows + # why not re-use self.param_dict here? param_dict = dict( [ ( p.name, p.value ) for p in job.parameters ] ) param_dict = self.tool.params_from_strings( param_dict, self.app ) # Create generated output children and primary datasets and add to param_dict diff --git a/lib/galaxy/tools/__init__.py b/lib/galaxy/tools/__init__.py index e4a90f74b702..8668e4bf6b33 100755 --- a/lib/galaxy/tools/__init__.py +++ b/lib/galaxy/tools/__init__.py @@ -31,7 +31,7 @@ from galaxy.tools.parameters import output_collect from galaxy.tools.parameters.basic import (BaseURLToolParameter, DataToolParameter, DataCollectionToolParameter, HiddenToolParameter, - SelectToolParameter, ToolParameter, UnvalidatedValue, + SelectToolParameter, ToolParameter, contains_workflow_parameter) from galaxy.tools.parameters.grouping import Conditional, ConditionalWhen, Repeat, Section, UploadDataset from galaxy.tools.parameters.input_translation import ToolInputTranslator @@ -2419,18 +2419,7 @@ def map_to_history(value): else: return None - # Unpack unvalidated values to strings, they'll be validated when the - # form is submitted (this happens when re-running a job that was - # initially run by a workflow) - # This needs to be done recursively through grouping parameters def mapping_callback( input, value, prefixed_name, prefixed_label ): - if isinstance( value, UnvalidatedValue ): - try: - return input.to_html_value( value.value, self.app ) - except Exception, e: - # Need to determine when (if ever) the to_html_value call could fail. - log.debug( "Failed to use input.to_html_value to determine value of unvalidated parameter, defaulting to string: %s" % ( e ) ) - return str( value ) if isinstance( input, DataToolParameter ): if isinstance(value, list): values = [] diff --git a/lib/galaxy/tools/imp_exp/__init__.py b/lib/galaxy/tools/imp_exp/__init__.py index 87f65f2f38d6..7db8ae032fa9 100644 --- a/lib/galaxy/tools/imp_exp/__init__.py +++ b/lib/galaxy/tools/imp_exp/__init__.py @@ -9,7 +9,6 @@ from galaxy import model from galaxy.model.item_attrs import UsesAnnotations -from galaxy.tools.parameters.basic import UnvalidatedValue from galaxy.util.json import dumps, loads from galaxy.web.framework.helpers import to_unicode @@ -382,8 +381,6 @@ def default( self, obj ): else: rval['exported'] = True return rval - if isinstance( obj, UnvalidatedValue ): - return obj.__str__() return json.JSONEncoder.default( self, obj ) # diff --git a/lib/galaxy/tools/parameters/basic.py b/lib/galaxy/tools/parameters/basic.py index ff4e4254cbbc..177653645527 100644 --- a/lib/galaxy/tools/parameters/basic.py +++ b/lib/galaxy/tools/parameters/basic.py @@ -2576,16 +2576,6 @@ def to_dict( self, trans, view='collection', value_mapper=None, other_values=Non drill_down=DrillDownSelectToolParameter ) -class UnvalidatedValue( object ): - """ - Wrapper to mark a value that has not been validated - """ - def __init__( self, value ): - self.value = value - - def __str__( self ): - return str( self.value ) - class RuntimeValue( object ): """ Wrapper to note a value that is not yet set, but will be required at diff --git a/lib/galaxy/workflow/extract.py b/lib/galaxy/workflow/extract.py index 8971dbb4b6ff..901b7e9c1dce 100644 --- a/lib/galaxy/workflow/extract.py +++ b/lib/galaxy/workflow/extract.py @@ -8,8 +8,7 @@ DataToolParameter, DataCollectionToolParameter, DrillDownSelectToolParameter, - SelectToolParameter, - UnvalidatedValue + SelectToolParameter ) from galaxy.tools.parser import ToolOutputCollectionPart from galaxy.tools.parameters.grouping import ( From 539ddd4d90bda5400c3006ab4c574bebd353d280 Mon Sep 17 00:00:00 2001 From: guerler Date: Mon, 25 Jan 2016 01:00:19 -0500 Subject: [PATCH 21/33] Remove optional parameter from request context initialization --- lib/galaxy/tools/evaluation.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/galaxy/tools/evaluation.py b/lib/galaxy/tools/evaluation.py index f23f73f11557..4ecc14b47f17 100644 --- a/lib/galaxy/tools/evaluation.py +++ b/lib/galaxy/tools/evaluation.py @@ -53,12 +53,11 @@ def set_compute_environment( self, compute_environment, get_special=None ): incoming = dict( [ ( p.name, p.value ) for p in job.parameters ] ) incoming = self.tool.params_from_strings( incoming, self.app ) - # Regular parameter validation + # Full parameter validation request_context = WorkRequestContext( app = self.app, user = job.history.user, - history = job.history, - workflow_building_mode = False + history = job.history ) def validate_inputs( input, value, prefixed_name, prefixed_label, context ): value = input.from_html( value, request_context, context ) From cc2cfe8d6adb264df41e18b4c33781712bb12cbb Mon Sep 17 00:00:00 2001 From: guerler Date: Mon, 25 Jan 2016 01:54:39 -0500 Subject: [PATCH 22/33] Use request context instead of trans in to_json --- lib/galaxy/tools/__init__.py | 62 ++++++++++++++----------- lib/galaxy/tools/parameters/__init__.py | 19 +++----- lib/galaxy/tools/parameters/basic.py | 2 +- 3 files changed, 41 insertions(+), 42 deletions(-) diff --git a/lib/galaxy/tools/__init__.py b/lib/galaxy/tools/__init__.py index 8668e4bf6b33..be9c608a8e03 100755 --- a/lib/galaxy/tools/__init__.py +++ b/lib/galaxy/tools/__init__.py @@ -53,6 +53,7 @@ from galaxy.web import url_for from galaxy.web.form_builder import SelectField from galaxy.util.dictifiable import Dictifiable +from galaxy.work.context import WorkRequestContext from tool_shed.util import common_util from tool_shed.util import shed_util_common as suc @@ -2076,17 +2077,22 @@ def to_json(self, trans, kwd={}, job=None, workflow_mode=False): except Exception, e: raise exceptions.MessageException( '[history_id=%s] Failed to retrieve history. %s.' % ( history_id, str( e ) ) ) - # set workflow mode ( TODO: Should be revised/parsed without trans to tool parameters (basic.py) ) - trans.workflow_building_mode = workflow_mode + # build request context + request_context = WorkRequestContext( + app = trans.app, + user = trans.user, + history = history, + workflow_building_mode = workflow_mode + ) # load job parameters into incoming tool_message = '' if job: try: job_params = job.get_param_values( self.app, ignore_errors=True ) - self.check_and_update_param_values( job_params, trans, update_values=False ) - self._map_source_to_history( trans, self.inputs, job_params, history ) - tool_message = self._compare_tool_version(trans, job) + self.check_and_update_param_values( job_params, request_context, update_values=False ) + self._map_source_to_history( request_context, self.inputs, job_params, history ) + tool_message = self._compare_tool_version( job ) params_to_incoming( kwd, self.inputs, job_params, self.app, to_html=False ) except Exception, e: raise exceptions.MessageException( str( e ) ) @@ -2157,7 +2163,7 @@ def sanitize(dict, key='value'): dict[key] = value # check the current state of a value and update it if necessary - def check_state( trans, input, value, context ): + def check_state( input, value, context ): error = 'State validation failed.' if isinstance( value, galaxy.tools.parameters.basic.DummyDataset ): return [ None, None ] @@ -2167,17 +2173,17 @@ def check_state( trans, input, value, context ): if value.get( '__class__' ) == 'RuntimeValue': return [ value, None ] try: - value, error = check_param( trans, input, value, context, history=history, boolean_fix=True, workflow_building_mode=workflow_mode ) + value, error = check_param( request_context, input, value, context, boolean_fix=True ) except Exception, err: log.error( 'Checking parameter %s failed. %s', input.name, str( err ) ) pass return [ value, error ] # populates state with incoming url parameters - def populate_state(trans, inputs, state, errors, incoming, prefix="", context=None ): + def populate_state( inputs, state, errors, incoming, prefix="", context=None ): context = ExpressionContext(state, context) for input in inputs.itervalues(): - state[input.name] = input.get_initial_value(trans, context) + state[input.name] = input.get_initial_value( request_context, context ) key = prefix + input.name if input.type == 'repeat': group_state = state[input.name] @@ -2191,21 +2197,21 @@ def populate_state(trans, inputs, state, errors, incoming, prefix="", context=No new_state = {} new_state['__index__'] = rep_index group_state.append(new_state) - populate_state(trans, input.inputs, new_state, errors, incoming, prefix=rep_name + "|", context=context) + populate_state( input.inputs, new_state, errors, incoming, prefix=rep_name + "|", context=context ) rep_index += 1 elif input.type == 'conditional': group_state = state[input.name] group_prefix = "%s|" % ( key ) test_param_key = group_prefix + input.test_param.name default_value = incoming.get(test_param_key, group_state.get(input.test_param.name, None)) - value, error = check_state(trans, input.test_param, default_value, context) + value, error = check_state( input.test_param, default_value, context ) if error: errors[test_param_key] = error else: try: - current_case = input.get_current_case(value, trans) + current_case = input.get_current_case( value, request_context ) group_state = state[input.name] = {} - populate_state( trans, input.cases[current_case].inputs, group_state, errors, incoming, prefix=group_prefix, context=context) + populate_state( input.cases[current_case].inputs, group_state, errors, incoming, prefix=group_prefix, context=context ) group_state['__current_case__'] = current_case except Exception: errors[test_param_key] = 'The selected case is unavailable/invalid.' @@ -2214,53 +2220,53 @@ def populate_state(trans, inputs, state, errors, incoming, prefix="", context=No elif input.type == 'section': group_state = state[input.name] group_prefix = "%s|" % ( key ) - populate_state(trans, input.inputs, group_state, errors, incoming, prefix=group_prefix, context=context) + populate_state( input.inputs, group_state, errors, incoming, prefix=group_prefix, context=context ) else: default_value = incoming.get(key, state.get(input.name, None)) - value, error = check_state(trans, input, default_value, context) + value, error = check_state( input, default_value, context ) if error: errors[key] = error state[input.name] = value # builds tool model including all attributes - def iterate(group_inputs, inputs, state_inputs, other_values=None): + def iterate( group_inputs, inputs, state_inputs, other_values=None ): other_values = ExpressionContext( state_inputs, other_values ) for input_index, input in enumerate( inputs.itervalues() ): tool_dict = None group_state = state_inputs.get(input.name, {}) if input.type == 'repeat': - tool_dict = input.to_dict(trans) + tool_dict = input.to_dict( request_context ) group_cache = tool_dict['cache'] = {} for i in range( len( group_state ) ): group_cache[i] = {} iterate( group_cache[i], input.inputs, group_state[i], other_values ) elif input.type == 'conditional': - tool_dict = input.to_dict(trans) + tool_dict = input.to_dict( request_context ) if 'test_param' in tool_dict: test_param = tool_dict['test_param'] - test_param['default_value'] = jsonify(input.test_param.get_initial_value(trans, other_values)) + test_param['default_value'] = jsonify( input.test_param.get_initial_value( request_context, other_values ) ) test_param['value'] = jsonify(group_state.get(test_param['name'], test_param['default_value'])) test_param['text_value'] = input.test_param.value_to_display_text(test_param['value'], self.app) for i in range(len( tool_dict['cases'] ) ): current_state = {} if i == group_state.get('__current_case__', None): current_state = group_state - iterate(tool_dict['cases'][i]['inputs'], input.cases[i].inputs, current_state, other_values) + iterate( tool_dict['cases'][i]['inputs'], input.cases[i].inputs, current_state, other_values ) elif input.type == 'section': - tool_dict = input.to_dict(trans) + tool_dict = input.to_dict( request_context ) iterate( tool_dict['inputs'], input.inputs, group_state, other_values ) else: # expand input dictionary, resolve dynamic parameters try: - tool_dict = input.to_dict(trans, other_values=other_values) + tool_dict = input.to_dict( request_context, other_values=other_values ) except Exception: - tool_dict = input.to_dict(trans) + tool_dict = input.to_dict( request_context ) log.exception('tools::to_json() - Skipping parameter expansion for %s.' % input.name) pass # backup default value try: - tool_dict['default_value'] = input.get_initial_value(trans, other_values) + tool_dict['default_value'] = input.get_initial_value( request_context, other_values ) except Exception: tool_dict['default_value'] = None log.exception('tools::to_json() - Getting initial value failed %s.' % input.name) @@ -2305,14 +2311,14 @@ def sanitize_state(state): # initialize and populate tool state state_inputs = {} state_errors = {} - populate_state(trans, self.inputs, state_inputs, state_errors, params.__dict__) + populate_state( request_context, self.inputs, state_inputs, state_errors, params.__dict__ ) # create basic tool model - tool_model = self.to_dict(trans) + tool_model = self.to_dict( request_context ) tool_model['inputs'] = {} # build tool model and tool state - iterate(tool_model['inputs'], self.inputs, state_inputs, '') + iterate( request_context, tool_model['inputs'], self.inputs, state_inputs, '' ) # sanitize tool state sanitize_state(state_inputs) @@ -2436,7 +2442,7 @@ def mapping_callback( input, value, prefixed_name, prefixed_label ): return map_to_history( value ) visit_input_values( tool_inputs, params, mapping_callback ) - def _compare_tool_version( self, trans, job ): + def _compare_tool_version( self, job ): """ Compares a tool version with the tool version from a job (from ToolRunner). """ diff --git a/lib/galaxy/tools/parameters/__init__.py b/lib/galaxy/tools/parameters/__init__.py index fd63b4363896..bfdb8061dd33 100644 --- a/lib/galaxy/tools/parameters/__init__.py +++ b/lib/galaxy/tools/parameters/__init__.py @@ -6,7 +6,6 @@ from grouping import Conditional, Repeat, Section, UploadDataset from galaxy.util.json import dumps, json_fix, loads from galaxy.util.expressions import ExpressionContext -from galaxy.work.context import WorkRequestContext REPLACE_ON_TRUTHY = object() @@ -61,7 +60,7 @@ def visit_input_values( inputs, input_values, callback, name_prefix="", label_pr input_values[input.name] = new_value -def check_param( trans, param, incoming_value, param_values, source='html', boolean_fix=False, history=None, workflow_building_mode=False ): +def check_param( trans, param, incoming_value, param_values, source='html', boolean_fix=False ): """ Check the value of a single parameter `param`. The value in `incoming_value` is converted from its HTML encoding and validated. @@ -69,12 +68,6 @@ def check_param( trans, param, incoming_value, param_values, source='html', bool previous parameters (this may actually be an ExpressionContext when dealing with grouping scenarios). """ - request_context = WorkRequestContext( - app = trans.app, - user = trans.user, - history = history or trans.history, - workflow_building_mode = workflow_building_mode - ) value = incoming_value error = None try: @@ -84,16 +77,16 @@ def check_param( trans, param, incoming_value, param_values, source='html', bool if value is not None or isinstance( param, DataToolParameter ) or isinstance( param, DataCollectionToolParameter ): # Convert value from HTML representation if source == 'html': - value = param.from_html( value, request_context, param_values ) + value = param.from_html( value, trans, param_values ) else: - value = param.from_json( value, request_context, param_values ) + value = param.from_json( value, trans, param_values ) # Allow the value to be converted if necessary - filtered_value = param.filter_value( value, request_context, param_values ) + filtered_value = param.filter_value( value, trans, param_values ) # Then do any further validation on the value - param.validate( filtered_value, request_context ) + param.validate( filtered_value, trans ) elif value is None and isinstance( param, SelectToolParameter ): # An empty select list or column list - param.validate( value, request_context ) + param.validate( value, trans ) except ValueError, e: error = str( e ) return value, error diff --git a/lib/galaxy/tools/parameters/basic.py b/lib/galaxy/tools/parameters/basic.py index 177653645527..c05db4a90e69 100644 --- a/lib/galaxy/tools/parameters/basic.py +++ b/lib/galaxy/tools/parameters/basic.py @@ -1931,7 +1931,7 @@ def get_initial_value_from_history_prevent_repeats( self, trans, other_values, a 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 or trans.webapp.name == 'tool_shed': + if trans.workflow_building_mode or trans.app.name == 'tool_shed': return DummyDataset() history = self._get_history( trans ) dataset_matcher = DatasetMatcher( trans, self, None, other_values ) From a7117574268ab907fb27483a485d5d9e501b7e5e Mon Sep 17 00:00:00 2001 From: guerler Date: Mon, 25 Jan 2016 02:12:50 -0500 Subject: [PATCH 23/33] Remove unused error handler, error is handled consistently through full validation --- lib/galaxy/jobs/__init__.py | 3 --- lib/galaxy/tools/__init__.py | 13 ------------- lib/galaxy/tools/parameters/validation.py | 6 ------ 3 files changed, 22 deletions(-) diff --git a/lib/galaxy/jobs/__init__.py b/lib/galaxy/jobs/__init__.py index 9892732d698b..39a8f166c52f 100644 --- a/lib/galaxy/jobs/__init__.py +++ b/lib/galaxy/jobs/__init__.py @@ -965,9 +965,6 @@ def fail( self, message, exception=False, stdout="", stderr="", exit_code=None ) # Get the exception and let the tool attempt to generate # a better message etype, evalue, tb = sys.exc_info() - m = self.tool.handle_job_failure_exception( evalue ) - if m: - message = m if self.app.config.outputs_to_working_directory: for dataset_path in self.get_output_fnames(): try: diff --git a/lib/galaxy/tools/__init__.py b/lib/galaxy/tools/__init__.py index be9c608a8e03..e0b018a14a3c 100755 --- a/lib/galaxy/tools/__init__.py +++ b/lib/galaxy/tools/__init__.py @@ -35,7 +35,6 @@ contains_workflow_parameter) from galaxy.tools.parameters.grouping import Conditional, ConditionalWhen, Repeat, Section, UploadDataset from galaxy.tools.parameters.input_translation import ToolInputTranslator -from galaxy.tools.parameters.validation import LateValidationError from galaxy.tools.test import parse_tests from galaxy.tools.parser import get_tool_source from galaxy.tools.parser.xml import XmlPageSource @@ -1738,18 +1737,6 @@ def check_and_update_param_values_helper( self, inputs, values, trans, messages, if update_values: values[ input.name ] = input.get_initial_value( trans, context ) - def handle_job_failure_exception( self, e ): - """ - Called by job.fail when an exception is generated to allow generation - of a better error message (returning None yields the default behavior) - """ - message = None - # If the exception was generated by late validation, use its error - # message (contains the parameter name and value) - if isinstance( e, LateValidationError ): - message = e.message - return message - def build_dependency_shell_commands( self, job_directory=None ): """Return a list of commands to be run to populate the current environment to include this tools requirements.""" return self.app.toolbox.dependency_manager.dependency_shell_commands( diff --git a/lib/galaxy/tools/parameters/validation.py b/lib/galaxy/tools/parameters/validation.py index c4bf76a9e8f9..d802fd8429e3 100644 --- a/lib/galaxy/tools/parameters/validation.py +++ b/lib/galaxy/tools/parameters/validation.py @@ -10,12 +10,6 @@ log = logging.getLogger( __name__ ) -class LateValidationError( Exception ): - - def __init__( self, message ): - self.message = message - - class Validator( object ): """ A validator checks that a value meets some conditions OR raises ValueError From 0ca9c7027b5ee3cd8ba433a4e8bc3e5ad57a5d7f Mon Sep 17 00:00:00 2001 From: guerler Date: Mon, 25 Jan 2016 02:18:03 -0500 Subject: [PATCH 24/33] Use request context in handle inputs --- lib/galaxy/tools/__init__.py | 57 ++++++------------- lib/galaxy/tools/evaluation.py | 9 +-- lib/galaxy/tools/parameters/__init__.py | 1 + lib/galaxy/tools/parameters/basic.py | 6 +- .../tools/parameters/dynamic_options.py | 1 - lib/galaxy/workflow/extract.py | 4 +- 6 files changed, 26 insertions(+), 52 deletions(-) diff --git a/lib/galaxy/tools/__init__.py b/lib/galaxy/tools/__init__.py index e0b018a14a3c..4392b784193c 100755 --- a/lib/galaxy/tools/__init__.py +++ b/lib/galaxy/tools/__init__.py @@ -1049,17 +1049,17 @@ def check_workflow_compatible( self, tool_source ): # outputs? return True - def new_state( self, trans, history=None ): + def new_state( self, trans ): """ Create a new `DefaultToolState` for this tool. It will be initialized with default values for inputs. """ state = DefaultToolState() state.inputs = {} - self.fill_in_new_state( trans, self.inputs, state.inputs, history=history ) + self.fill_in_new_state( trans, self.inputs, state.inputs ) return state - def fill_in_new_state( self, trans, inputs, state, context=None, history=None ): + def fill_in_new_state( self, trans, inputs, state, context=None ): """ Fill in a tool state dictionary with default values for all parameters in the dictionary `inputs`. Grouping elements are filled in recursively. @@ -1068,22 +1068,6 @@ def fill_in_new_state( self, trans, inputs, state, context=None, history=None ): for input in inputs.itervalues(): state[ input.name ] = input.get_initial_value( trans, context ) - def get_param_html_map( self, trans, page=0, other_values={} ): - """ - Return a dictionary containing the HTML representation of each - parameter. This is used for rendering display elements. It is - currently not compatible with grouping constructs. - - NOTE: This should be considered deprecated, it is only used for tools - with `display` elements. These should be eliminated. - """ - rval = dict() - for key, param in self.inputs_by_page[page].iteritems(): - if not isinstance( param, ToolParameter ): - raise Exception( "'get_param_html_map' only supported for simple paramters" ) - rval[key] = param.get_html( trans, other_values=other_values ) - return rval - def get_param( self, key ): """ Returns the parameter named `key` or None if there is no such @@ -1128,6 +1112,7 @@ def handle_input( self, trans, incoming, history=None, source='html' ): to the form or execute the tool (only if 'execute' was clicked and there were no errors). """ + request_context = WorkRequestContext( app=trans.app, user=trans.user, history=history or trans.history ) rerun_remap_job_id = None if 'rerun_remap_job_id' in incoming: try: @@ -1152,7 +1137,7 @@ def handle_input( self, trans, incoming, history=None, source='html' ): all_params = [] validate_input = self.get_hook( 'validate_input' ) for expanded_incoming in expanded_incomings: - expanded_state = self.new_state( trans, history=history ) + expanded_state = self.new_state( request_context ) # Process incoming data if not self.check_values: # If `self.check_values` is false we don't do any checking or @@ -1163,7 +1148,7 @@ def handle_input( self, trans, incoming, history=None, source='html' ): else: # Update state for all inputs on the current page taking new # values from `incoming`. - errors = self.populate_state( trans, self.inputs, expanded_state.inputs, expanded_incoming, history, source=source ) + errors = self.populate_state( request_context, self.inputs, expanded_state.inputs, expanded_incoming, source=source ) # If the tool provides a `validate_input` hook, call it. if validate_input: validate_input( trans, errors, expanded_state.inputs, self.inputs ) @@ -1176,7 +1161,7 @@ def handle_input( self, trans, incoming, history=None, source='html' ): if any( all_errors ): raise exceptions.MessageException( err_data=all_errors[ 0 ] ) else: - execution_tracker = execute_job( trans, self, all_params, history=history, rerun_remap_job_id=rerun_remap_job_id, collection_info=collection_info ) + execution_tracker = execute_job( trans, self, all_params, history=request_context.history, rerun_remap_job_id=rerun_remap_job_id, collection_info=collection_info ) if execution_tracker.successful_jobs: return dict( out_data=execution_tracker.output_datasets, num_jobs=len( execution_tracker.successful_jobs ), @@ -1219,7 +1204,7 @@ def find_fieldstorage( self, x ): elif isinstance(x, list): [ self.find_fieldstorage( y ) for y in x ] - def populate_state( self, trans, inputs, state, incoming, history=None, source="html", prefix="", context=None ): + def populate_state( self, trans, inputs, state, incoming, source="html", prefix="", context=None ): errors = dict() # Push this level onto the context stack context = ExpressionContext( state, context ) @@ -1239,14 +1224,13 @@ def populate_state( self, trans, inputs, state, incoming, history=None, source=" if rep_index < input.max: new_state = {} new_state['__index__'] = rep_index - self.fill_in_new_state( trans, input.inputs, new_state, context, history=history ) + self.fill_in_new_state( trans, input.inputs, new_state, context ) group_state.append( new_state ) group_errors.append( {} ) rep_errors = self.populate_state( trans, input.inputs, new_state, incoming, - history, source, prefix=rep_name + "|", context=context ) @@ -1288,12 +1272,11 @@ def populate_state( self, trans, inputs, state, incoming, history=None, source=" # Current case has changed, throw away old state group_state = state[input.name] = {} # TODO: we should try to preserve values if we can - self.fill_in_new_state( trans, input.cases[current_case].inputs, group_state, context, history=history ) + self.fill_in_new_state( trans, input.cases[current_case].inputs, group_state, context ) group_errors = self.populate_state( trans, input.cases[current_case].inputs, group_state, incoming, - history, source, prefix=group_prefix, context=context) @@ -1306,12 +1289,11 @@ def populate_state( self, trans, inputs, state, incoming, history=None, source=" elif isinstance( input, Section ): group_state = state[input.name] group_prefix = "%s|" % ( key ) - self.fill_in_new_state( trans, input.inputs, group_state, context, history=history ) + self.fill_in_new_state( trans, input.inputs, group_state, context ) group_errors = self.populate_state( trans, input.inputs, group_state, incoming, - history, source, prefix=group_prefix, context=context ) @@ -1344,7 +1326,6 @@ def populate_state( self, trans, inputs, state, incoming, history=None, source=" input.inputs, rep_state, incoming, - history, source, prefix=rep_prefix, context=context) @@ -2065,12 +2046,7 @@ def to_json(self, trans, kwd={}, job=None, workflow_mode=False): raise exceptions.MessageException( '[history_id=%s] Failed to retrieve history. %s.' % ( history_id, str( e ) ) ) # build request context - request_context = WorkRequestContext( - app = trans.app, - user = trans.user, - history = history, - workflow_building_mode = workflow_mode - ) + request_context = WorkRequestContext( app=trans.app, user=trans.user, history=history, workflow_building_mode=workflow_mode ) # load job parameters into incoming tool_message = '' @@ -2078,7 +2054,7 @@ def to_json(self, trans, kwd={}, job=None, workflow_mode=False): try: job_params = job.get_param_values( self.app, ignore_errors=True ) self.check_and_update_param_values( job_params, request_context, update_values=False ) - self._map_source_to_history( request_context, self.inputs, job_params, history ) + self._map_source_to_history( request_context, self.inputs, job_params ) tool_message = self._compare_tool_version( job ) params_to_incoming( kwd, self.inputs, job_params, self.app, to_html=False ) except Exception, e: @@ -2298,14 +2274,14 @@ def sanitize_state(state): # initialize and populate tool state state_inputs = {} state_errors = {} - populate_state( request_context, self.inputs, state_inputs, state_errors, params.__dict__ ) + populate_state( self.inputs, state_inputs, state_errors, params.__dict__ ) # create basic tool model tool_model = self.to_dict( request_context ) tool_model['inputs'] = {} # build tool model and tool state - iterate( request_context, tool_model['inputs'], self.inputs, state_inputs, '' ) + iterate( tool_model['inputs'], self.inputs, state_inputs, '' ) # sanitize tool state sanitize_state(state_inputs) @@ -2375,10 +2351,11 @@ def _get_job_remap( self, job): pass return False - def _map_source_to_history(self, trans, tool_inputs, params, history): + def _map_source_to_history( self, trans, tool_inputs, params ): # Need to remap dataset parameters. Job parameters point to original # dataset used; parameter should be the analygous dataset in the # current history. + history = trans.history # Create index for hdas. hda_source_dict = {} diff --git a/lib/galaxy/tools/evaluation.py b/lib/galaxy/tools/evaluation.py index 4ecc14b47f17..1934d0936dc1 100644 --- a/lib/galaxy/tools/evaluation.py +++ b/lib/galaxy/tools/evaluation.py @@ -54,15 +54,12 @@ def set_compute_environment( self, compute_environment, get_special=None ): incoming = self.tool.params_from_strings( incoming, self.app ) # Full parameter validation - request_context = WorkRequestContext( - app = self.app, - user = job.history.user, - history = job.history - ) + request_context = WorkRequestContext( app=self.app, user=job.history.user, history=job.history ) + def validate_inputs( input, value, prefixed_name, prefixed_label, context ): value = input.from_html( value, request_context, context ) input.validate( value, request_context ) - visit_input_values ( self.tool.inputs, incoming, validate_inputs, details=True ) + visit_input_values( self.tool.inputs, incoming, validate_inputs, details=True ) # Restore input / output data lists inp_data = dict( [ ( da.name, da.dataset ) for da in job.input_datasets ] ) diff --git a/lib/galaxy/tools/parameters/__init__.py b/lib/galaxy/tools/parameters/__init__.py index bfdb8061dd33..6829c3144039 100644 --- a/lib/galaxy/tools/parameters/__init__.py +++ b/lib/galaxy/tools/parameters/__init__.py @@ -4,6 +4,7 @@ from basic import DataCollectionToolParameter, DataToolParameter, SelectToolParameter from grouping import Conditional, Repeat, Section, UploadDataset +from galaxy.util import string_as_bool from galaxy.util.json import dumps, json_fix, loads from galaxy.util.expressions import ExpressionContext diff --git a/lib/galaxy/tools/parameters/basic.py b/lib/galaxy/tools/parameters/basic.py index c05db4a90e69..5f1efe2eaa3f 100644 --- a/lib/galaxy/tools/parameters/basic.py +++ b/lib/galaxy/tools/parameters/basic.py @@ -615,6 +615,7 @@ def __init__( self, tool, input_source ): input_source = ensure_input_source(input_source) ToolParameter.__init__( self, tool, input_source ) self.multiple = input_source.get_bool( 'multiple', True ) + self.optional = input_source.parse_optional( True ) self.user_ftp_dir = '' def get_initial_value( self, trans, other_values ): @@ -652,8 +653,6 @@ def to_string( self, value, app ): return self.to_python( value, app ) def to_python( self, value, app, validate=False ): - if validate and self.tool.app.config.ftp_upload_dir is None: - raise ValueError( "The FTP directory is not configured." ) if not isinstance( value, list ): value = [ value ] lst = [] @@ -669,6 +668,8 @@ def to_python( self, value, app, validate=False ): if not self.optional and validate: raise ValueError( "Please select a valid FTP file." ) return '' + if validate and self.tool.app.config.ftp_upload_dir is None: + raise ValueError( "The FTP directory is not configured." ) return lst def to_dict( self, trans, view='collection', value_mapper=None, other_values=None ): @@ -2576,6 +2577,7 @@ def to_dict( self, trans, view='collection', value_mapper=None, other_values=Non drill_down=DrillDownSelectToolParameter ) + class RuntimeValue( object ): """ Wrapper to note a value that is not yet set, but will be required at diff --git a/lib/galaxy/tools/parameters/dynamic_options.py b/lib/galaxy/tools/parameters/dynamic_options.py index e33cec7780f7..c70a385f27cf 100644 --- a/lib/galaxy/tools/parameters/dynamic_options.py +++ b/lib/galaxy/tools/parameters/dynamic_options.py @@ -5,7 +5,6 @@ import logging import os -import basic import validation from galaxy.util import string_as_bool from galaxy.model import User diff --git a/lib/galaxy/workflow/extract.py b/lib/galaxy/workflow/extract.py index 901b7e9c1dce..05887a556662 100644 --- a/lib/galaxy/workflow/extract.py +++ b/lib/galaxy/workflow/extract.py @@ -6,9 +6,7 @@ from galaxy import model from galaxy.tools.parameters.basic import ( DataToolParameter, - DataCollectionToolParameter, - DrillDownSelectToolParameter, - SelectToolParameter + DataCollectionToolParameter ) from galaxy.tools.parser import ToolOutputCollectionPart from galaxy.tools.parameters.grouping import ( From 193c5293d9552d53a2358254fa2a25b236a31511 Mon Sep 17 00:00:00 2001 From: guerler Date: Tue, 26 Jan 2016 01:25:56 -0500 Subject: [PATCH 25/33] Remove invalid validator from upload.xml --- tools/data_source/upload.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/data_source/upload.xml b/tools/data_source/upload.xml index 196237fd4141..e28b95dbb56f 100644 --- a/tools/data_source/upload.xml +++ b/tools/data_source/upload.xml @@ -34,7 +34,6 @@ - not ( ( isinstance( value, unicode ) or isinstance( value, str ) ) and value != "" ) From 0fc8726414bfedcc234d7c4738ebff3a1b37e3d4 Mon Sep 17 00:00:00 2001 From: guerler Date: Tue, 26 Jan 2016 02:17:57 -0500 Subject: [PATCH 26/33] Fix prefixed_label concatenation --- lib/galaxy/tools/parameters/__init__.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/galaxy/tools/parameters/__init__.py b/lib/galaxy/tools/parameters/__init__.py index 6829c3144039..8feabcbb7dc4 100644 --- a/lib/galaxy/tools/parameters/__init__.py +++ b/lib/galaxy/tools/parameters/__init__.py @@ -35,20 +35,18 @@ def visit_input_values( inputs, input_values, callback, name_prefix="", label_pr elif isinstance( input, Conditional ): values = input_values[ input.name ] current = values["__current_case__"] - label_prefix = label_prefix new_name_prefix = name_prefix + input.name + "|" visit_input_values( input.cases[current].inputs, values, callback, new_name_prefix, label_prefix, no_replacement_value=no_replacement_value, context=context, details=details ) elif isinstance( input, Section ): values = input_values[ input.name ] - label_prefix = label_prefix new_name_prefix = name_prefix + input.name + "|" visit_input_values( input.inputs, values, callback, new_name_prefix, label_prefix, no_replacement_value=no_replacement_value, context=context, details=details ) else: args = { 'input' : input, - 'value' : input_values[input.name], - 'prefixed_name' : name_prefix + input.name, - 'prefixed_label' : label_prefix + input.label + 'value' : input_values[ input.name ], + 'prefixed_name' : "%s%s" % ( name_prefix, input.name ), + 'prefixed_label' : "%s%s" % ( label_prefix, input.label ) } if details: args[ 'context' ] = context From 0521644bb37336f31577c8bd73ac1fef6c936016 Mon Sep 17 00:00:00 2001 From: guerler Date: Tue, 26 Jan 2016 02:58:42 -0500 Subject: [PATCH 27/33] Fix select validator --- lib/galaxy/tools/parameters/basic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/galaxy/tools/parameters/basic.py b/lib/galaxy/tools/parameters/basic.py index 5f1efe2eaa3f..ba5c6fb217ec 100644 --- a/lib/galaxy/tools/parameters/basic.py +++ b/lib/galaxy/tools/parameters/basic.py @@ -938,7 +938,7 @@ def from_html( self, value, trans, other_values={} ): # use \r\n to separate lines. value = value.split() return value - if not legal_values and self.optional: + if ( not legal_values or value is None ) and self.optional: return None if not legal_values: raise ValueError( "Parameter %s requires a value, but has no legal values defined." % self.name ) From 8bd4cabdde922f23c06c64f95f50ea4d81caa940 Mon Sep 17 00:00:00 2001 From: guerler Date: Tue, 26 Jan 2016 03:15:38 -0500 Subject: [PATCH 28/33] Use request context for parameter helper --- lib/galaxy/tools/__init__.py | 17 +++++++++-------- lib/galaxy/tools/evaluation.py | 2 +- lib/galaxy/workflow/modules.py | 2 +- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/galaxy/tools/__init__.py b/lib/galaxy/tools/__init__.py index 4392b784193c..4b456dd5b5e9 100755 --- a/lib/galaxy/tools/__init__.py +++ b/lib/galaxy/tools/__init__.py @@ -1629,14 +1629,15 @@ def params_to_strings( self, 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, update_values=True ): + def check_and_update_param_values( self, values, trans, update_values=True, workflow_building_mode=False ): """ 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, update_values=update_values ) + request_context = WorkRequestContext( app=trans.app, user=trans.user, history=trans.history, workflow_building_mode=workflow_building_mode ) + self.check_and_update_param_values_helper( self.inputs, values, request_context, messages, update_values=update_values ) return messages def check_and_update_param_values_helper( self, inputs, values, trans, messages, context=None, prefix="", update_values=True ): @@ -1654,7 +1655,7 @@ def check_and_update_param_values_helper( self, inputs, values, trans, messages, messages[ input.name ] = cond_messages test_value = input.test_param.get_initial_value( trans, context ) current_case = input.get_current_case( test_value, trans ) - self.check_and_update_param_values_helper( input.cases[ current_case ].inputs, {}, trans, cond_messages, context, prefix ) + self.check_and_update_param_values_helper( input.cases[ current_case ].inputs, {}, trans, cond_messages, context, prefix, update_values=update_values ) elif isinstance( input, Repeat ): if input.min: messages[ input.name ] = [] @@ -1662,10 +1663,10 @@ def check_and_update_param_values_helper( self, inputs, values, trans, messages, rep_prefix = prefix + "%s %d > " % ( input.title, i + 1 ) rep_dict = dict() messages[ input.name ].append( rep_dict ) - self.check_and_update_param_values_helper( input.inputs, {}, trans, rep_dict, context, rep_prefix ) + self.check_and_update_param_values_helper( input.inputs, {}, trans, rep_dict, context, rep_prefix, update_values=update_values ) elif isinstance( input, Section ): messages[ input.name ] = {} - self.check_and_update_param_values_helper( input.inputs, {}, trans, messages[ input.name ], context, prefix ) + self.check_and_update_param_values_helper( input.inputs, {}, trans, messages[ input.name ], context, prefix, update_values=update_values ) else: messages[ input.name ] = "No value found for '%s%s', using default" % ( prefix, input.label ) values[ input.name ] = input.get_initial_value( trans, context ) @@ -1674,7 +1675,7 @@ def check_and_update_param_values_helper( self, inputs, values, trans, messages, if isinstance( input, Repeat ): for i, d in enumerate( values[ input.name ] ): rep_prefix = prefix + "%s %d > " % ( input.title, i + 1 ) - self.check_and_update_param_values_helper( input.inputs, d, trans, messages, context, rep_prefix ) + self.check_and_update_param_values_helper( input.inputs, d, trans, messages, context, rep_prefix, update_values=update_values ) elif isinstance( input, Conditional ): group_values = values[ input.name ] use_initial_value = False @@ -1692,10 +1693,10 @@ def check_and_update_param_values_helper( self, inputs, values, trans, messages, messages[ child_input.name ] = "Value no longer valid for '%s%s', replacing with default" % ( prefix, child_input.label ) else: current = group_values["__current_case__"] - self.check_and_update_param_values_helper( input.cases[current].inputs, group_values, trans, messages, context, prefix ) + self.check_and_update_param_values_helper( input.cases[current].inputs, group_values, trans, messages, context, prefix, update_values=update_values ) elif isinstance( input, Section ): messages[ input.name ] = {} - self.check_and_update_param_values_helper( input.inputs, values[ input.name ], trans, messages[ input.name ], context, prefix ) + self.check_and_update_param_values_helper( input.inputs, values[ input.name ], trans, messages[ input.name ], context, prefix, update_values=update_values ) else: # Regular tool parameter, no recursion needed try: diff --git a/lib/galaxy/tools/evaluation.py b/lib/galaxy/tools/evaluation.py index 1934d0936dc1..6e845b94b70c 100644 --- a/lib/galaxy/tools/evaluation.py +++ b/lib/galaxy/tools/evaluation.py @@ -54,7 +54,7 @@ def set_compute_environment( self, compute_environment, get_special=None ): incoming = self.tool.params_from_strings( incoming, self.app ) # Full parameter validation - request_context = WorkRequestContext( app=self.app, user=job.history.user, history=job.history ) + request_context = WorkRequestContext( app=self.app, user=job.history and job.history.user, history=job.history ) def validate_inputs( input, value, prefixed_name, prefixed_label, context ): value = input.from_html( value, request_context, context ) diff --git a/lib/galaxy/workflow/modules.py b/lib/galaxy/workflow/modules.py index 37931da7e5b6..4433d6b8b9d5 100644 --- a/lib/galaxy/workflow/modules.py +++ b/lib/galaxy/workflow/modules.py @@ -1080,7 +1080,7 @@ def item_callback( trans, key, input, value, error, old_value, context ): def check_and_update_state( self ): inputs = self.state.inputs - return self.tool.check_and_update_param_values( inputs, self.trans ) + return self.tool.check_and_update_param_values( inputs, self.trans, workflow_building_mode=True ) def compute_runtime_state( self, trans, step_updates=None, source="html" ): # Warning: This method destructively modifies existing step state. From b3f3f81a7d0d221e4a698dbd9a586a92cd6662af Mon Sep 17 00:00:00 2001 From: guerler Date: Wed, 27 Jan 2016 01:50:05 -0500 Subject: [PATCH 29/33] Remove unused to_html helper --- lib/galaxy/tools/__init__.py | 2 +- lib/galaxy/tools/parameters/__init__.py | 10 ++++----- lib/galaxy/tools/parameters/basic.py | 22 ------------------- .../galaxy/workflow/editor_tool_form.mako | 2 +- templates/webapps/galaxy/workflow/run.mako | 2 +- 5 files changed, 7 insertions(+), 31 deletions(-) diff --git a/lib/galaxy/tools/__init__.py b/lib/galaxy/tools/__init__.py index 4b456dd5b5e9..25789a87c87c 100755 --- a/lib/galaxy/tools/__init__.py +++ b/lib/galaxy/tools/__init__.py @@ -2057,7 +2057,7 @@ def to_json(self, trans, kwd={}, job=None, workflow_mode=False): self.check_and_update_param_values( job_params, request_context, update_values=False ) self._map_source_to_history( request_context, self.inputs, job_params ) tool_message = self._compare_tool_version( job ) - params_to_incoming( kwd, self.inputs, job_params, self.app, to_html=False ) + params_to_incoming( kwd, self.inputs, job_params, self.app ) except Exception, e: raise exceptions.MessageException( str( e ) ) diff --git a/lib/galaxy/tools/parameters/__init__.py b/lib/galaxy/tools/parameters/__init__.py index 8feabcbb7dc4..3590a9c5e8d2 100644 --- a/lib/galaxy/tools/parameters/__init__.py +++ b/lib/galaxy/tools/parameters/__init__.py @@ -123,7 +123,7 @@ def params_from_strings( params, param_values, app, ignore_errors=False ): return rval -def params_to_incoming( incoming, inputs, input_values, app, name_prefix="", to_html=True ): +def params_to_incoming( incoming, inputs, input_values, app, name_prefix="" ): """ Given a tool's parameter definition (`inputs`) and a specific set of parameter `input_values` objects, populate `incoming` with the html values. @@ -135,19 +135,17 @@ def params_to_incoming( incoming, inputs, input_values, app, name_prefix="", to_ for d in input_values[ input.name ]: index = d['__index__'] new_name_prefix = name_prefix + "%s_%d|" % ( input.name, index ) - params_to_incoming( incoming, input.inputs, d, app, new_name_prefix, to_html=to_html) + params_to_incoming( incoming, input.inputs, d, app, new_name_prefix ) elif isinstance( input, Conditional ): values = input_values[ input.name ] current = values["__current_case__"] new_name_prefix = name_prefix + input.name + "|" incoming[ new_name_prefix + input.test_param.name ] = values[ input.test_param.name ] - params_to_incoming( incoming, input.cases[current].inputs, values, app, new_name_prefix, to_html=to_html ) + params_to_incoming( incoming, input.cases[current].inputs, values, app, new_name_prefix ) elif isinstance( input, Section ): values = input_values[ input.name ] new_name_prefix = name_prefix + input.name + "|" - params_to_incoming( incoming, input.inputs, values, app, new_name_prefix, to_html=to_html ) + params_to_incoming( incoming, input.inputs, values, app, new_name_prefix ) else: value = input_values.get( input.name ) - if to_html: - value = input.to_html_value( value, app ) incoming[ name_prefix + input.name ] = value diff --git a/lib/galaxy/tools/parameters/basic.py b/lib/galaxy/tools/parameters/basic.py index ba5c6fb217ec..3fda7438038f 100644 --- a/lib/galaxy/tools/parameters/basic.py +++ b/lib/galaxy/tools/parameters/basic.py @@ -151,10 +151,6 @@ def filter_value( self, value, trans=None, other_values={} ): """ return value - def to_html_value( self, value, app ): - """Convert an object value to the value expected from an html post""" - return self.to_string( value, app ) - def to_string( self, value, app ): """Convert a value to a string representation suitable for persisting""" if not isinstance( value, basestring ): @@ -285,12 +281,6 @@ def to_string( self, value, app ): rval = util.smart_str( value ) return rval - def to_html_value( self, value, app ): - if value is None: - return '' - else: - return self.to_string( value, app ) - def validate( self, value, trans ): search = self.type == "text" if not ( trans.workflow_building_mode and contains_workflow_parameter(value, search=search) ): @@ -501,12 +491,6 @@ def from_html( self, value, trans=None, other_values={} ): def from_json( self, value, trans=None, other_values={} ): return string_as_bool( value ) - def to_html_value( self, value, app ): - if value: - return [ 'true', 'true' ] - else: - return [ 'true' ] - def to_python( self, value, app ): return ( value in [ 'True', 'true' ]) @@ -963,12 +947,6 @@ def from_html( self, value, trans, other_values={} ): raise ValueError( "An invalid option was selected for %s, %r, please verify." % ( self.name, value ) ) return value - def to_html_value( self, value, app ): - if isinstance( value, list ): - return value - else: - return str( value ) - def to_param_dict_string( self, value, other_values={}, value_map=DEFAULT_VALUE_MAP ): if value is None: return "None" diff --git a/templates/webapps/galaxy/workflow/editor_tool_form.mako b/templates/webapps/galaxy/workflow/editor_tool_form.mako index 95cd50c75b66..2922f68605ff 100644 --- a/templates/webapps/galaxy/workflow/editor_tool_form.mako +++ b/templates/webapps/galaxy/workflow/editor_tool_form.mako @@ -3,7 +3,7 @@ ## This avoids making two separate requests since the classic form requires the mako anyway. from galaxy.tools.parameters import params_to_incoming incoming = {} - params_to_incoming( incoming, tool.inputs, module.state.inputs, trans.app, to_html=False) + params_to_incoming( incoming, tool.inputs, module.state.inputs, trans.app ) self.form_config = tool.to_json(trans, incoming, workflow_mode=True) self.form_config.update({ 'id' : tool.id, diff --git a/templates/webapps/galaxy/workflow/run.mako b/templates/webapps/galaxy/workflow/run.mako index 2e499621ec09..e4d0851687d1 100644 --- a/templates/webapps/galaxy/workflow/run.mako +++ b/templates/webapps/galaxy/workflow/run.mako @@ -27,7 +27,7 @@ elif step.type == 'tool': incoming = {} tool = trans.app.toolbox.get_tool( step.tool_id ) - params_to_incoming( incoming, tool.inputs, step.state.inputs, trans.app, to_html=False ) + params_to_incoming( incoming, tool.inputs, step.state.inputs, trans.app ) step_model = tool.to_json( trans, incoming, workflow_mode=True ) step_model[ 'post_job_actions' ] = [{ 'short_str' : ActionBox.get_short_str( pja ), From 8b6e4c9f2584d5768926836ee08607aeae0bb501 Mon Sep 17 00:00:00 2001 From: guerler Date: Wed, 27 Jan 2016 01:57:57 -0500 Subject: [PATCH 30/33] Remove unused filter value helper --- lib/galaxy/tools/parameters/__init__.py | 4 +--- lib/galaxy/tools/parameters/basic.py | 12 ------------ lib/galaxy/tools/parameters/grouping.py | 2 +- 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/lib/galaxy/tools/parameters/__init__.py b/lib/galaxy/tools/parameters/__init__.py index 3590a9c5e8d2..a243ce35114d 100644 --- a/lib/galaxy/tools/parameters/__init__.py +++ b/lib/galaxy/tools/parameters/__init__.py @@ -79,10 +79,8 @@ def check_param( trans, param, incoming_value, param_values, source='html', bool value = param.from_html( value, trans, param_values ) else: value = param.from_json( value, trans, param_values ) - # Allow the value to be converted if necessary - filtered_value = param.filter_value( value, trans, param_values ) # Then do any further validation on the value - param.validate( filtered_value, trans ) + param.validate( value, trans ) elif value is None and isinstance( param, SelectToolParameter ): # An empty select list or column list param.validate( value, trans ) diff --git a/lib/galaxy/tools/parameters/basic.py b/lib/galaxy/tools/parameters/basic.py index 3fda7438038f..d33c92cf1207 100644 --- a/lib/galaxy/tools/parameters/basic.py +++ b/lib/galaxy/tools/parameters/basic.py @@ -144,13 +144,6 @@ def get_dependencies( self ): """ return [] - def filter_value( self, value, trans=None, other_values={} ): - """ - Parse the value returned by the view into a form usable by the tool OR - raise a ValueError. - """ - return value - def to_string( self, value, app ): """Convert a value to a string representation suitable for persisting""" if not isinstance( value, basestring ): @@ -778,8 +771,6 @@ class SelectToolParameter( ToolParameter ): - >>> print p.filter_value( "y" ) - y >>> p = SelectToolParameter( None, XML( ... ''' @@ -1085,9 +1076,6 @@ class GenomeBuildParameter( SelectToolParameter ): ... - - >>> print p.filter_value( "hg17" ) - hg17 """ def __init__( self, *args, **kwds ): super( GenomeBuildParameter, self ).__init__( *args, **kwds ) diff --git a/lib/galaxy/tools/parameters/grouping.py b/lib/galaxy/tools/parameters/grouping.py index 1942d78670ae..b667daa35f30 100644 --- a/lib/galaxy/tools/parameters/grouping.py +++ b/lib/galaxy/tools/parameters/grouping.py @@ -557,7 +557,7 @@ def get_current_case( self, value, trans ): if isinstance( value, bool ): str_value = self.test_param.to_param_dict_string( value ) else: - str_value = self.test_param.filter_value( value, trans ) + str_value = value # Find the matching case for index, case in enumerate( self.cases ): if str_value == case.value: From 27df773c5a8823fff2d0dd68a8bd162147336bed Mon Sep 17 00:00:00 2001 From: guerler Date: Thu, 28 Jan 2016 00:23:17 -0500 Subject: [PATCH 31/33] Always display discarded datasets on rerun --- lib/galaxy/tools/parameters/basic.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/lib/galaxy/tools/parameters/basic.py b/lib/galaxy/tools/parameters/basic.py index d33c92cf1207..5b8bc258b517 100644 --- a/lib/galaxy/tools/parameters/basic.py +++ b/lib/galaxy/tools/parameters/basic.py @@ -2160,29 +2160,27 @@ def to_dict( self, trans, view='collection', value_mapper=None, other_values={} if history is None: return d + # build and append a new select option + def append( list, id, hid, name, src ): + return list.append( { 'id' : trans.app.security.encode_id( id ), 'hid' : hid, 'name' : name, 'src' : src } ) + # add datasets visible_hda = other_values.get( self.name ) + has_matched = False for hda in history.active_datasets_children_and_roles: match = dataset_matcher.hda_match( hda, ensure_visible=visible_hda != hda ) if match: m = match.hda - d['options']['hda'].append({ - 'id' : trans.app.security.encode_id( m.id ), - 'hid' : m.hid, - 'name' : m.name if m.visible else '(hidden) %s' % m.name, - 'src' : 'hda' - }) + has_matched = has_matched or visible_hda == m + append( d[ 'options' ][ 'hda' ], m.id, m.hid, m.name if m.visible else '(hidden) %s' % m.name, 'hda' ) + if not has_matched and isinstance( visible_hda, trans.app.model.HistoryDatasetAssociation ): + append( d[ 'options' ][ 'hda' ], visible_hda.id, visible_hda.hid, '(unavailable) %s' % visible_hda.name, 'hda' ) # add dataset collections dataset_collection_matcher = DatasetCollectionMatcher( dataset_matcher ) for hdca in history.active_dataset_collections: if dataset_collection_matcher.hdca_match( hdca, reduction=multiple ): - d['options']['hdca'].append({ - 'id' : trans.app.security.encode_id( hdca.id ), - 'hid' : hdca.hid, - 'name' : hdca.name, - 'src' : 'hdca' - }) + append( d[ 'options' ][ 'hdca' ], hdca.id, hdca.hid, hdca.name, 'hdca' ) # sort both lists d['options']['hda'] = sorted(d['options']['hda'], key=lambda k: k['hid'], reverse=True) From f8e3fa51f4b2fbaab54becd869ede40e43c5067a Mon Sep 17 00:00:00 2001 From: guerler Date: Thu, 28 Jan 2016 13:12:46 -0500 Subject: [PATCH 32/33] Apply suggested fixes, fix test cases --- lib/galaxy/jobs/runners/__init__.py | 2 +- lib/galaxy/tools/parameters/basic.py | 48 ++++++++++++----------- test/unit/tools/test_data_parameters.py | 1 + test/unit/tools/test_evaluation.py | 5 ++- test/unit/tools/test_execution.py | 1 + test/unit/tools/test_select_parameters.py | 4 +- test/unit/tools_support.py | 1 + 7 files changed, 35 insertions(+), 27 deletions(-) diff --git a/lib/galaxy/jobs/runners/__init__.py b/lib/galaxy/jobs/runners/__init__.py index 608aabfa9c5c..ba7f2120d0eb 100644 --- a/lib/galaxy/jobs/runners/__init__.py +++ b/lib/galaxy/jobs/runners/__init__.py @@ -169,7 +169,7 @@ def prepare_job(self, job_wrapper, include_metadata=False, include_work_dir_outp include_metadata=include_metadata, include_work_dir_outputs=include_work_dir_outputs, ) - except Exception, e: + except Exception as e: log.exception("(%s) Failure preparing job" % job_id) job_wrapper.fail( e.message if hasattr( e, 'message' ) else "Job preparation failed", exception=True ) return False diff --git a/lib/galaxy/tools/parameters/basic.py b/lib/galaxy/tools/parameters/basic.py index 5b8bc258b517..715e1993ceb4 100644 --- a/lib/galaxy/tools/parameters/basic.py +++ b/lib/galaxy/tools/parameters/basic.py @@ -198,7 +198,7 @@ def to_param_dict_string( self, value, other_values={} ): value = sanitize_param( value ) return value - def validate( self, value, trans ): + def validate( self, value, trans=None ): if value == "" and self.optional: return for validator in self.validators: @@ -274,9 +274,9 @@ def to_string( self, value, app ): rval = util.smart_str( value ) return rval - def validate( self, value, trans ): + def validate( self, value, trans=None ): search = self.type == "text" - if not ( trans.workflow_building_mode and contains_workflow_parameter(value, search=search) ): + if not ( trans and trans.workflow_building_mode and contains_workflow_parameter(value, search=search) ): return super( TextToolParameter, self ).validate( value, trans ) def get_initial_value( self, trans, other_values ): @@ -292,15 +292,16 @@ def to_dict( self, trans, view='collection', value_mapper=None, other_values={} class IntegerToolParameter( TextToolParameter ): """ Parameter that takes an integer value. - + >>> from galaxy.util.bunch import Bunch + >>> trans = Bunch( history=Bunch(), workflow_building_mode=True ) >>> p = IntegerToolParameter( None, XML( '' ) ) >>> print p.name blah >>> print p.get_html() - >>> type( p.from_html( "10" ) ) + >>> type( p.from_html( "10", trans ) ) - >>> type( p.from_html( "bleh" ) ) + >>> type( p.from_html( "bleh", trans ) ) Traceback (most recent call last): ... ValueError: An integer or workflow parameter e.g. ${name} is required @@ -371,15 +372,16 @@ def get_initial_value( self, trans, other_values ): class FloatToolParameter( TextToolParameter ): """ Parameter that takes a real number value. - + >>> from galaxy.util.bunch import Bunch + >>> trans = Bunch( history=Bunch(), workflow_building_mode=True ) >>> p = FloatToolParameter( None, XML( '' ) ) >>> print p.name blah >>> print p.get_html() - >>> type( p.from_html( "36.1" ) ) + >>> type( p.from_html( "36.1", trans ) ) - >>> type( p.from_html( "bleh" ) ) + >>> type( p.from_html( "bleh", trans ) ) Traceback (most recent call last): ... ValueError: A real number or workflow parameter e.g. ${name} is required @@ -1832,7 +1834,7 @@ def value_modifier(value): name = history_dataset_collection.name hid = str( history_dataset_collection.hid ) hidden_text = "" # TODO - id = value_modifier( trans.app.security.encode_id( history_dataset_collection.id ) ) + id = value_modifier( trans.security.encode_id( history_dataset_collection.id ) ) selected = value and history_dataset_collection in value text = "%s:%s %s" % ( hid, hidden_text, name ) field.add_option( text, id, selected ) @@ -1944,10 +1946,10 @@ def from_html( self, value, trans, other_values={} ): for single_value in value: if isinstance( single_value, dict ) and 'src' in single_value and 'id' in single_value: if single_value['src'] == 'hda': - rval.append( trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( trans.app.security.decode_id(single_value['id']) )) + rval.append( trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( trans.security.decode_id(single_value['id']) )) elif single_value['src'] == 'hdca': found_hdca = True - decoded_id = trans.app.security.decode_id( single_value[ 'id' ] ) + decoded_id = trans.security.decode_id( single_value[ 'id' ] ) rval.append( trans.sa_session.query( trans.app.model.HistoryDatasetCollectionAssociation ).get( decoded_id ) ) else: raise ValueError("Unknown input source %s passed to job submission API." % single_value['src']) @@ -1965,15 +1967,15 @@ def from_html( self, value, trans, other_values={} ): rval = value elif isinstance( value, dict ) and 'src' in value and 'id' in value: if value['src'] == 'hda': - rval = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( trans.app.security.decode_id(value['id']) ) + rval = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( trans.security.decode_id(value['id']) ) elif value['src'] == 'hdca': - decoded_id = trans.app.security.decode_id( value[ 'id' ] ) + decoded_id = trans.security.decode_id( value[ 'id' ] ) rval = trans.sa_session.query( trans.app.model.HistoryDatasetCollectionAssociation ).get( decoded_id ) else: raise ValueError("Unknown input source %s passed to job submission API." % value['src']) elif str( value ).startswith( "__collection_reduce__|" ): encoded_ids = [ v[ len( "__collection_reduce__|" ): ] for v in str( value ).split(",") ] - decoded_ids = map( trans.app.security.decode_id, encoded_ids ) + decoded_ids = map( trans.security.decode_id, encoded_ids ) rval = [] for decoded_id in decoded_ids: hdca = trans.sa_session.query( trans.app.model.HistoryDatasetCollectionAssociation ).get( decoded_id ) @@ -2162,7 +2164,7 @@ def to_dict( self, trans, view='collection', value_mapper=None, other_values={} # build and append a new select option def append( list, id, hid, name, src ): - return list.append( { 'id' : trans.app.security.encode_id( id ), 'hid' : hid, 'name' : name, 'src' : src } ) + return list.append( { 'id' : trans.security.encode_id( id ), 'hid' : hid, 'name' : name, 'src' : src } ) # add datasets visible_hda = other_values.get( self.name ) @@ -2278,8 +2280,8 @@ def _get_select_dataset_collection_field( self, trans, history, multiple=False, name = history_dataset_collection.name hid = str( history_dataset_collection.hid ) hidden_text = "" # TODO - subcollection_type = self._history_query( trans ).collection_type_description.collection_type - id = "%s|%s" % ( trans.app.security.encode_id( history_dataset_collection.id ), subcollection_type ) + subcollection_type = self._history_query( trans ).can_map_over( history_dataset_collection ).collection_type + id = "%s|%s" % ( trans.security.encode_id( history_dataset_collection.id ), subcollection_type ) text = "%s:%s %s" % ( hid, hidden_text, name ) field.add_option( text, id, False ) @@ -2302,13 +2304,13 @@ def from_html( self, value, trans, other_values={} ): rval = value elif isinstance( value, dict ) and 'src' in value and 'id' in value: if value['src'] == 'hdca': - rval = trans.sa_session.query( trans.app.model.HistoryDatasetCollectionAssociation ).get( trans.app.security.decode_id(value['id']) ) + rval = trans.sa_session.query( trans.app.model.HistoryDatasetCollectionAssociation ).get( trans.security.decode_id(value['id']) ) elif isinstance( value, list ): if len( value ) > 0: value = value[0] if isinstance( value, dict ) and 'src' in value and 'id' in value: if value['src'] == 'hdca': - rval = trans.sa_session.query( trans.app.model.HistoryDatasetCollectionAssociation ).get( trans.app.security.decode_id(value['id']) ) + rval = trans.sa_session.query( trans.app.model.HistoryDatasetCollectionAssociation ).get( trans.security.decode_id(value['id']) ) elif isinstance( value, basestring ): if value.startswith( "dce:" ): rval = trans.sa_session.query( trans.app.model.DatasetCollectionElement ).get( value[ len( "dce:"): ] ) @@ -2364,7 +2366,7 @@ def value_to_display_text( self, value, app ): display_text = "No dataset collection." return display_text - def validate( self, value, trans ): + def validate( self, value, trans=None ): return True # TODO def to_dict( self, trans, view='collection', value_mapper=None, other_values=None ): @@ -2385,7 +2387,7 @@ def to_dict( self, trans, view='collection', value_mapper=None, other_values=Non # append directly matched collections for hdca in self.match_collections( trans, history, dataset_matcher ): d['options']['hdca'].append({ - 'id': trans.app.security.encode_id( hdca.id ), + 'id': trans.security.encode_id( hdca.id ), 'hid': hdca.hid, 'name': hdca.name, 'src': 'hdca' @@ -2395,7 +2397,7 @@ def to_dict( self, trans, view='collection', value_mapper=None, other_values=Non for hdca in self.match_multirun_collections( trans, history, dataset_matcher ): subcollection_type = self._history_query( trans ).can_map_over( hdca ).collection_type d['options']['hdca'].append({ - 'id': trans.app.security.encode_id( hdca.id ), + 'id': trans.security.encode_id( hdca.id ), 'hid': hdca.hid, 'name': hdca.name, 'src': 'hdca', diff --git a/test/unit/tools/test_data_parameters.py b/test/unit/tools/test_data_parameters.py index c78d05af6994..c847ba164ab5 100644 --- a/test/unit/tools/test_data_parameters.py +++ b/test/unit/tools/test_data_parameters.py @@ -154,6 +154,7 @@ def setUp( self ): get_current_user_roles=lambda: [], workflow_building_mode=False, webapp=bunch.Bunch( name="galaxy" ), + history=self.test_history, ) self.multiple = False self.optional = False diff --git a/test/unit/tools/test_evaluation.py b/test/unit/tools/test_evaluation.py index 127a6073c245..63ff8d542f2b 100644 --- a/test/unit/tools/test_evaluation.py +++ b/test/unit/tools/test_evaluation.py @@ -149,7 +149,10 @@ def get_field_by_name_for_value( name, value, trans, other_values ): assert name == "path" return ["/old/path/human"] - parameter.options = Bunch(get_field_by_name_for_value=get_field_by_name_for_value) + def get_options( trans, other_values ): + return [ [ "", "/old/path/human", "" ] ] + + parameter.options = Bunch(get_field_by_name_for_value=get_field_by_name_for_value, get_options=get_options) self.tool.set_params( { "index_path": parameter } ) diff --git a/test/unit/tools/test_execution.py b/test/unit/tools/test_execution.py index c3a2bc8e2af0..df947825084f 100644 --- a/test/unit/tools/test_execution.py +++ b/test/unit/tools/test_execution.py @@ -268,6 +268,7 @@ class MockTrans( object ): def __init__( self, app, history ): self.app = app self.history = history + self.user = None self.history._active_datasets_children_and_roles = filter( lambda hda: hda.active and hda.history == history, self.app.model.context.model_objects[ galaxy.model.HistoryDatasetAssociation ] ) self.workflow_building_mode = False self.webapp = Bunch( name="galaxy" ) diff --git a/test/unit/tools/test_select_parameters.py b/test/unit/tools/test_select_parameters.py index 0e18010975b8..e4ebe7590bd5 100644 --- a/test/unit/tools/test_select_parameters.py +++ b/test/unit/tools/test_select_parameters.py @@ -28,7 +28,7 @@ def test_validated_values_missing_dependency( self ): def test_unvalidated_values( self ): self.options_xml = '''''' self.trans.workflow_building_mode = True - assert self.param.from_html("42", self.trans).value == "42" + assert self.param.from_html("42", self.trans) == "42" def test_validated_datasets( self ): self.options_xml = '''''' @@ -42,7 +42,7 @@ def test_validated_datasets( self ): def test_unvalidated_datasets( self ): self.options_xml = '''''' self.trans.workflow_building_mode = True - assert isinstance( self.param.from_html( model.HistoryDatasetAssociation(), self.trans, { "input_bam": basic.RuntimeValue() } ).value, model.HistoryDatasetAssociation ) + assert isinstance( self.param.from_html( model.HistoryDatasetAssociation(), self.trans, { "input_bam": basic.RuntimeValue() } ), model.HistoryDatasetAssociation ) def test_filter_param_value( self ): self.options_xml = '''''' diff --git a/test/unit/tools_support.py b/test/unit/tools_support.py index 0249cb2bf88d..3d435ca1f68d 100644 --- a/test/unit/tools_support.py +++ b/test/unit/tools_support.py @@ -154,6 +154,7 @@ def __init__(self, model_objects=None): self.flushed = False self.model_objects = model_objects or defaultdict( lambda: {} ) self.created_objects = [] + self.current = self def expunge_all(self): self.expunged_all = True From 72370b251723eac746bd1720a85df539cd96e78a Mon Sep 17 00:00:00 2001 From: guerler Date: Thu, 28 Jan 2016 19:28:57 -0500 Subject: [PATCH 33/33] Fix paused workflow step resubmission --- lib/galaxy/tools/actions/__init__.py | 6 ++++-- lib/galaxy/tools/parameters/__init__.py | 21 ++++++++++++++++++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/lib/galaxy/tools/actions/__init__.py b/lib/galaxy/tools/actions/__init__.py index eacae091ddf6..f14fe80168b6 100644 --- a/lib/galaxy/tools/actions/__init__.py +++ b/lib/galaxy/tools/actions/__init__.py @@ -6,6 +6,7 @@ from galaxy import model from galaxy.tools.parameters.basic import DataCollectionToolParameter, DataToolParameter from galaxy.tools.parameters.wrapped import WrappedParameters +from galaxy.tools.parameters import update_param from galaxy.util import ExecutionTimer from galaxy.util.json import dumps from galaxy.util.none_like import NoneDataset @@ -491,9 +492,10 @@ def handle_output( name, output, hidden=None ): if hda.state == hda.states.PAUSED: hda.state = hda.states.NEW hda.info = None + input_values = dict( [ ( p.name, json.loads( p.value ) ) for p in job_to_remap.parameters ] ) + update_param( jtid.name, input_values, str( out_data[ jtod.name ].id ) ) for p in job_to_remap.parameters: - if p.name == jtid.name and p.value == str(jtod.dataset.id): - p.value = str(out_data[jtod.name].id) + p.value = json.dumps( input_values[ p.name ] ) jtid.dataset = out_data[jtod.name] jtid.dataset.hid = jtod.dataset.hid log.info('Job %s input HDA %s remapped to new HDA %s' % (job_to_remap.id, jtod.dataset.id, jtid.dataset.id)) diff --git a/lib/galaxy/tools/parameters/__init__.py b/lib/galaxy/tools/parameters/__init__.py index a243ce35114d..2312110130b1 100644 --- a/lib/galaxy/tools/parameters/__init__.py +++ b/lib/galaxy/tools/parameters/__init__.py @@ -1,7 +1,7 @@ """ Classes encapsulating Galaxy tool parameters. """ - +import re from basic import DataCollectionToolParameter, DataToolParameter, SelectToolParameter from grouping import Conditional, Repeat, Section, UploadDataset from galaxy.util import string_as_bool @@ -147,3 +147,22 @@ def params_to_incoming( incoming, inputs, input_values, app, name_prefix="" ): else: value = input_values.get( input.name ) incoming[ name_prefix + input.name ] = value + + +def update_param( prefixed_name, input_values, new_value ): + """ + Given a prefixed parameter name, e.g. 'parameter_0|parameter_1', update + the corresponding input value in a nested input values dictionary. + """ + for key in input_values: + match = re.match( '^' + key + '_(\d+)\|(.+)', prefixed_name ) + if match: + index = int( match.group( 1 ) ) + if isinstance( input_values[ key ], list ) and len( input_values[ key ] ) > index: + update_param( match.group( 2 ), input_values[ key ][ index ], new_value ) + else: + match = re.match( '^' + key + '\|(.+)', prefixed_name ) + if isinstance( input_values[ key ], dict ) and match: + update_param( match.group( 1 ), input_values[ key ], new_value ) + elif prefixed_name == key: + input_values[ key ] = new_value