mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
Revise late validation condition by considering the availability of options
This commit is contained in:
@@ -59,12 +59,10 @@ def check_param( trans, param, incoming_value, param_values, source='html' ):
|
||||
value = param.from_html( value, trans, param_values )
|
||||
else:
|
||||
value = param.from_json( value, trans, param_values )
|
||||
# Only validate if late validation is not needed
|
||||
if not param.need_late_validation( 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.history )
|
||||
# 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.history )
|
||||
elif value is None and isinstance( param, SelectToolParameter ):
|
||||
# An empty select list or column list
|
||||
param.validate( value, trans.history )
|
||||
|
||||
@@ -841,9 +841,9 @@ class SelectToolParameter( ToolParameter ):
|
||||
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.
|
||||
if self.need_late_validation( trans, context ):
|
||||
if value is not None:
|
||||
assert isinstance( value, UnvalidatedValue ), "Late validation needed for '%s', but provided value (%s) is not of type UnvalidatedValue (%s)." % ( self.name, value, type( value ) )
|
||||
options = self.get_options( trans, context )
|
||||
if self.need_late_validation( trans, options ):
|
||||
if isinstance( value, UnvalidatedValue ):
|
||||
value = value.value
|
||||
if self.multiple:
|
||||
if value is None:
|
||||
@@ -859,7 +859,6 @@ class SelectToolParameter( ToolParameter ):
|
||||
# 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 )
|
||||
options = self.get_options( trans, context )
|
||||
for text, optval, selected in options:
|
||||
if isinstance( optval, UnvalidatedValue ):
|
||||
optval = optval.value
|
||||
@@ -870,7 +869,8 @@ class SelectToolParameter( ToolParameter ):
|
||||
return field
|
||||
|
||||
def from_html( self, value, trans=None, context={} ):
|
||||
if self.need_late_validation( trans, context ):
|
||||
legal_values = self.get_legal_values( trans, context )
|
||||
if self.need_late_validation( trans, legal_values ):
|
||||
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
|
||||
@@ -885,7 +885,6 @@ class SelectToolParameter( ToolParameter ):
|
||||
# use \r\n to separate lines.
|
||||
value = value.split()
|
||||
return UnvalidatedValue( value )
|
||||
legal_values = self.get_legal_values( trans, context )
|
||||
if not legal_values and self.optional:
|
||||
return None
|
||||
if not legal_values:
|
||||
@@ -952,61 +951,22 @@ class SelectToolParameter( ToolParameter ):
|
||||
return UnvalidatedValue( value["value"] )
|
||||
return super( SelectToolParameter, self ).value_from_basic( value, app, ignore_errors=ignore_errors )
|
||||
|
||||
def need_late_validation( self, trans, context ):
|
||||
def need_late_validation( self, trans, options ):
|
||||
"""
|
||||
Determine whether we need to wait to validate this parameters value
|
||||
given the current state. For parameters with static options this is
|
||||
always false (can always validate immediately). For parameters with
|
||||
dynamic options, we need to check whether the other parameters which
|
||||
determine what options are valid have been set. For the old style
|
||||
dynamic options which do not specify dependencies, this is always true
|
||||
(must validate at runtime).
|
||||
always false (can always validate immediately).
|
||||
"""
|
||||
# Option list is statically defined, never need late validation
|
||||
if not self.is_dynamic:
|
||||
return False
|
||||
# Old style dynamic options, no dependency information so there isn't
|
||||
# a lot we can do: if we're dealing with workflows, have to assume
|
||||
# late validation no matter what.
|
||||
if self.dynamic_options is not None and ( trans is None or trans.workflow_building_mode ):
|
||||
if len(list(options)) == 0 and (trans is None or trans.workflow_building_mode):
|
||||
return True
|
||||
# If we got this far, we can actually look at the dependencies
|
||||
# to see if their values will not be available until runtime.
|
||||
for dep_name in self.get_dependencies():
|
||||
# This may not be completely correct, but it's possible to go
|
||||
# through the layers indicated below without assigning dep_value,
|
||||
# which is even worse. TODO fix it?
|
||||
dep_value = None
|
||||
if dep_name in context:
|
||||
dep_value = context[ dep_name ]
|
||||
else:
|
||||
# Quick hack to check deeper in the context.
|
||||
# TODO: Context should really be scoped and the correct subset passed along.
|
||||
# This happens specifically in all the GATK tools, the way the reference genome is handled.
|
||||
for layer in context.itervalues():
|
||||
if isinstance( layer, dict ) and self.name in layer and dep_name in layer:
|
||||
dep_value = layer[dep_name]
|
||||
# Dependency on a dataset that does not yet exist
|
||||
if isinstance( dep_value, DummyDataset ):
|
||||
return True
|
||||
# Dependency on a value that has not been checked
|
||||
if isinstance( dep_value, UnvalidatedValue ):
|
||||
return True
|
||||
# Dependency on a value that does not yet exist
|
||||
if isinstance( dep_value, RuntimeValue ):
|
||||
return True
|
||||
#dataset not ready yet
|
||||
if hasattr( self, 'ref_input' ) and isinstance( dep_value, self.tool.app.model.HistoryDatasetAssociation ) and ( dep_value.is_pending or not dep_value.datatype.matches_any( self.ref_input.formats ) ):
|
||||
return True
|
||||
# Dynamic, but all dependenceis are known and have values
|
||||
return False
|
||||
|
||||
def get_initial_value( self, trans, context, history=None ):
|
||||
# More working around dynamic options for workflow
|
||||
if self.need_late_validation( trans, context ):
|
||||
options = list( self.get_options( trans, context ) )
|
||||
if self.need_late_validation( trans, options ):
|
||||
# Really the best we can do?
|
||||
return UnvalidatedValue( None )
|
||||
options = list( self.get_options( trans, context ) )
|
||||
value = [ optval for _, optval, selected in options if selected ]
|
||||
if len( value ) == 0:
|
||||
if not self.multiple and options:
|
||||
@@ -1255,8 +1215,12 @@ class ColumnListParameter( SelectToolParameter ):
|
||||
return []
|
||||
column_list = None
|
||||
for dataset in util.listify( dataset ):
|
||||
# Handle columns not available.
|
||||
if not dataset.metadata.columns:
|
||||
unavailable = False
|
||||
if not hasattr(dataset, 'metadata'):
|
||||
unavailable = True
|
||||
elif not dataset.metadata.columns:
|
||||
unavailable = True
|
||||
if unavailable:
|
||||
default_column_list = []
|
||||
if self.accept_default:
|
||||
default_column_list.append( self.default_value or '1' )
|
||||
@@ -1316,9 +1280,6 @@ class ColumnListParameter( SelectToolParameter ):
|
||||
|
||||
def get_initial_value( self, trans, context, history=None ):
|
||||
if self.default_value is not None:
|
||||
# dataset not ready / in workflow / etc
|
||||
if self.need_late_validation( trans, context ):
|
||||
return UnvalidatedValue( self.default_value )
|
||||
return self.default_value
|
||||
return SelectToolParameter.get_initial_value( self, trans, context )
|
||||
|
||||
@@ -1328,33 +1289,6 @@ class ColumnListParameter( SelectToolParameter ):
|
||||
def get_dependencies( self ):
|
||||
return [ self.data_ref ]
|
||||
|
||||
def need_late_validation( self, trans, context ):
|
||||
if super( ColumnListParameter, self ).need_late_validation( trans, context ):
|
||||
return True
|
||||
if self.data_ref not in context:
|
||||
return False
|
||||
# Get the selected dataset if selected
|
||||
referent = context[ self.data_ref ]
|
||||
if getattr( referent, 'history_content_type', None ) == "dataset_collection":
|
||||
# TODO: also check datasets have been populated.
|
||||
referent = referent.collection.dataset_instances
|
||||
|
||||
datasets = util.listify( referent )
|
||||
for dataset in datasets:
|
||||
if dataset:
|
||||
# Check if metadata is available
|
||||
if not hasattr(dataset, 'metadata'):
|
||||
return True
|
||||
|
||||
# Check if the dataset does not have the expected metadata for columns
|
||||
if not dataset.metadata.columns:
|
||||
# Only allow late validation if the dataset is not yet ready
|
||||
# (since we have reason to expect the metadata to be ready eventually)
|
||||
if dataset.is_pending or not dataset.datatype.matches_any( self.ref_input.formats ):
|
||||
return True
|
||||
# No late validation
|
||||
return False
|
||||
|
||||
def to_dict( self, trans, view='collection', value_mapper=None, other_values={} ):
|
||||
# call parent to_dict
|
||||
d = super( ColumnListParameter, self ).to_dict( trans, other_values=other_values)
|
||||
@@ -1558,9 +1492,9 @@ class DrillDownSelectToolParameter( SelectToolParameter ):
|
||||
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.
|
||||
if self.need_late_validation( trans, other_values ):
|
||||
if value is not None:
|
||||
assert isinstance( value, UnvalidatedValue ), "Late validation needed for '%s', but provided value (%s) is not of type UnvalidatedValue (%s)." % ( self.name, value, type( value ) )
|
||||
options = self.get_options( trans, value, other_values )
|
||||
if self.need_late_validation( trans, options ):
|
||||
if isinstance( value, UnvalidatedValue ):
|
||||
value = value.value
|
||||
if self.multiple:
|
||||
if value is None:
|
||||
@@ -1570,10 +1504,11 @@ class DrillDownSelectToolParameter( SelectToolParameter ):
|
||||
return form_builder.TextArea( self.name, value=value )
|
||||
else:
|
||||
return form_builder.TextField( self.name, value=(value or "") )
|
||||
return form_builder.DrillDownField( self.name, self.multiple, self.display, self.refresh_on_change, self.get_options( trans, value, other_values ), value, refresh_on_change_values=self.refresh_on_change_values )
|
||||
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={} ):
|
||||
if self.need_late_validation( trans, other_values ):
|
||||
legal_values = self.get_legal_values( trans, other_values )
|
||||
if self.need_late_validation( trans, legal_values ):
|
||||
if self.multiple:
|
||||
if value == '': # No option selected
|
||||
value = None
|
||||
@@ -1589,7 +1524,6 @@ class DrillDownSelectToolParameter( SelectToolParameter ):
|
||||
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 = []
|
||||
legal_values = self.get_legal_values( trans, other_values )
|
||||
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:
|
||||
@@ -1645,8 +1579,9 @@ class DrillDownSelectToolParameter( SelectToolParameter ):
|
||||
initial_values.append( option['value'] )
|
||||
recurse_options( initial_values, option['options'] )
|
||||
# More working around dynamic options for workflow
|
||||
if self.need_late_validation( trans, context ):
|
||||
# Really the best we can do?
|
||||
initial_values = []
|
||||
recurse_options( initial_values, self.get_options( trans=trans, other_values=context ) )
|
||||
if self.need_late_validation( trans, initial_values ):
|
||||
return UnvalidatedValue( None )
|
||||
initial_values = []
|
||||
recurse_options( initial_values, self.get_options( trans=trans, other_values=context ) )
|
||||
|
||||
Reference in New Issue
Block a user