root/galaxy-central/lib/galaxy/tools/parameters/output.py

リビジョン 2, 22.9 KB (コミッタ: hatakeyama, 14 年 前)

import galaxy-central

行番号 
1"""
2Support for dynamically modifying output attributes.
3"""
4
5import logging, os.path, string, re
6from galaxy import util
7
8log = logging.getLogger( __name__ )
9
10class ToolOutputActionGroup( object ):
11    """
12    Manages a set of tool output dataset actions directives
13    """
14    tag = "group"
15    def __init__( self, parent, config_elem ):
16        self.parent = parent
17        self.actions = []
18        if config_elem:
19            for elem in config_elem:
20                if elem.tag == "conditional":
21                    self.actions.append( ToolOutputActionConditional( self, elem ) )
22                elif elem.tag == "action":
23                    self.actions.append( ToolOutputAction.from_elem( self, elem ) )
24                else:
25                    log.debug( "Unknown ToolOutputAction tag specified: %s" % elem.tag )
26    def apply_action( self, output_dataset, other_values ):
27        for action in self.actions:
28            action.apply_action( output_dataset, other_values )
29    @property
30    def tool( self ):
31        return self.parent.tool
32    def __len__( self ):
33        return len( self.actions )
34
35class ToolOutputActionConditionalWhen( ToolOutputActionGroup ):
36    tag="when"
37    @classmethod
38    def from_elem( cls, parent, when_elem ):
39        """Loads the proper when by attributes of elem"""
40        when_value = when_elem.get( "value", None )
41        if when_value is not None:
42            return ValueToolOutputActionConditionalWhen( parent, when_elem, when_value )
43        else:
44            when_value = when_elem.get( "datatype_isinstance", None )
45            if when_value is not None:
46                return DatatypeIsInstanceToolOutputActionConditionalWhen( parent, when_elem, when_value )
47        raise TypeError( "When type not implemented" )
48    def __init__( self, parent, config_elem, value ):
49        super( ToolOutputActionConditionalWhen, self ).__init__( parent, config_elem )
50        self.value = value
51    def is_case( self, output_dataset, other_values ):
52        raise TypeError( "Not implemented" )
53    def get_ref( self, output_dataset, other_values ):
54        ref = other_values
55        for ref_name in self.parent.name:
56            assert ref_name in ref, "Required dependency '%s' not found in incoming values" % ref_name
57            ref = ref.get( ref_name )
58        return ref
59    def apply_action( self, output_dataset, other_values ):
60        if self.is_case( output_dataset, other_values ):
61            return super( ToolOutputActionConditionalWhen, self ).apply_action( output_dataset, other_values )
62
63class ValueToolOutputActionConditionalWhen( ToolOutputActionConditionalWhen ):
64    tag = "when value"
65    def is_case( self, output_dataset, other_values ):
66        ref = self.get_ref( output_dataset, other_values )
67        return bool( str( ref ) == self.value )
68       
69class DatatypeIsInstanceToolOutputActionConditionalWhen( ToolOutputActionConditionalWhen ):
70    tag = "when datatype_isinstance"
71    def __init__( self, parent, config_elem, value ):
72        super( DatatypeIsInstanceToolOutputActionConditionalWhen, self ).__init__( parent, config_elem, value )
73        self.value = type( self.tool.app.datatypes_registry.get_datatype_by_extension( value ) )
74    def is_case( self, output_dataset, other_values ):
75        ref = self.get_ref( output_dataset, other_values )
76        return isinstance( ref.datatype, self.value )
77
78class ToolOutputActionConditional( object ):
79    tag = "conditional"
80    def __init__( self, parent, config_elem ):
81        self.parent = parent
82        self.name = config_elem.get( 'name', None )
83        assert self.name is not None, "Required 'name' attribute missing from ToolOutputActionConditional"
84        self.name = self.name.split( '.' )
85        self.cases = []
86        for when_elem in config_elem.findall( 'when' ):
87            self.cases.append( ToolOutputActionConditionalWhen.from_elem( self, when_elem ) )
88    def apply_action( self, output_dataset, other_values ):
89        for case in self.cases:
90            case.apply_action( output_dataset, other_values )
91    @property
92    def tool( self ):
93        return self.parent.tool
94
95class ToolOutputAction( object ):
96    tag = "action"
97    @classmethod
98    def from_elem( cls, parent, elem ):
99        """Loads the proper action by the type attribute of elem"""
100        action_type = elem.get( 'type', None )
101        assert action_type is not None, "Required 'type' attribute missing from ToolOutputAction"
102        return action_types[ action_type ]( parent, elem )
103    def __init__( self, parent, elem ):
104        self.parent = parent
105        self.default = elem.get( 'default', None )
106        option_elem = elem.find( 'option' )
107        self.option = ToolOutputActionOption.from_elem( self, option_elem )
108    def apply_action( self, output_dataset, other_values ):
109        raise TypeError( "Not implemented" )
110    @property
111    def tool( self ):
112        return self.parent.tool
113
114class ToolOutputActionOption( object ):
115    tag = "object"
116    @classmethod
117    def from_elem( cls, parent, elem ):
118        """Loads the proper action by the type attribute of elem"""
119        if elem is None:
120            option_type = NullToolOutputActionOption.tag # no ToolOutputActionOption's have been defined, use implicit NullToolOutputActionOption
121        else:
122            option_type = elem.get( 'type', None )
123        assert option_type is not None, "Required 'type' attribute missing from ToolOutputActionOption"
124        return option_types[ option_type ]( parent, elem )
125    def __init__( self, parent, elem ):
126        self.parent = parent
127        self.filters = []
128        if elem is not None:
129            for filter_elem in elem.findall( 'filter' ):
130                self.filters.append( ToolOutputActionOptionFilter.from_elem( self, filter_elem ) )
131    def get_value( self, other_values ):
132        raise TypeError( "Not implemented" )
133    @property
134    def tool( self ):
135        return self.parent.tool
136
137class NullToolOutputActionOption( ToolOutputActionOption ):
138    tag = "null_option"
139    def get_value( self, other_values ):
140        return None
141
142class FromFileToolOutputActionOption( ToolOutputActionOption ):
143    tag = "from_file"
144    def __init__( self, parent, elem ):
145        super( FromFileToolOutputActionOption, self ).__init__( parent, elem )
146        self.name = elem.get( 'name', None )
147        assert self.name is not None, "Required 'name' attribute missing from FromFileToolOutputActionOption"
148        self.column = elem.get( 'column', None )
149        assert self.column is not None, "Required 'column' attribute missing from FromFileToolOutputActionOption"
150        self.column = int( self.column )
151        self.offset = elem.get( 'offset', -1 )
152        self.offset = int( self.offset )
153        self.separator = elem.get( 'separator', '\t' )
154        self.options = []
155        data_file = self.name
156        if not os.path.isabs( data_file ):
157            data_file = os.path.join( self.tool.app.config.tool_data_path, data_file )
158        for line in open( data_file ):
159            self.options.append( line.rstrip( '\n\r' ).split( self.separator ) )
160    def get_value( self, other_values ):
161        options = self.options
162        for filter in self.filters:
163            options = filter.filter_options( options, other_values )
164        try:
165            if options:
166                return str( options[ self.offset ][ self.column ] )
167        except Exception, e:
168            log.debug( "Error in FromFileToolOutputActionOption get_value: %s" % e )
169        return None
170
171class FromParamToolOutputActionOption( ToolOutputActionOption ):
172    tag = "from_param"
173    def __init__( self, parent, elem ):
174        super( FromParamToolOutputActionOption, self ).__init__( parent, elem )
175        self.name = elem.get( 'name', None )
176        assert self.name is not None, "Required 'name' attribute missing from FromFileToolOutputActionOption"
177        self.name = self.name.split( '.' )
178        self.column = elem.get( 'column', 0 )
179        self.column = int( self.column )
180        self.offset = elem.get( 'offset', -1 )
181        self.offset = int( self.offset )
182    def get_value( self, other_values ):
183        value = other_values
184        for ref_name in self.name:
185            assert ref_name in value, "Required dependency '%s' not found in incoming values" % ref_name
186            value = value.get( ref_name )
187        options = [ [ str( value ) ] ]
188        for filter in self.filters:
189            options = filter.filter_options( options, other_values )
190        try:
191            if options:
192                return str( options[ self.offset ][ self.column ] )
193        except Exception, e:
194            log.debug( "Error in FromParamToolOutputActionOption get_value: %s" % e )
195        return None
196
197class FromDataTableOutputActionOption( ToolOutputActionOption ):
198    tag = "from_data_table"
199    #TODO: allow accessing by column 'name' not just index
200    def __init__( self, parent, elem ):
201        super( FromDataTableOutputActionOption, self ).__init__( parent, elem )
202        self.name = elem.get( 'name', None )
203        assert self.name is not None, "Required 'name' attribute missing from FromDataTableOutputActionOption"
204        assert self.name in self.tool.app.tool_data_tables, "Data table named '%s' is required by tool but not configured" % self.name
205        self.options = self.tool.app.tool_data_tables[ self.name ].get_fields()
206        self.column = elem.get( 'column', None )
207        assert self.column is not None, "Required 'column' attribute missing from FromDataTableOutputActionOption"
208        self.column = int( self.column )
209        self.offset = elem.get( 'offset', -1 )
210        self.offset = int( self.offset )
211    def get_value( self, other_values ):
212        options = self.options
213        for filter in self.filters:
214            options = filter.filter_options( options, other_values )
215        try:
216            if options:
217                return str( options[ self.offset ][ self.column ] )
218        except Exception, e:
219            log.debug( "Error in FromDataTableOutputActionOption get_value: %s" % e )
220        return None
221
222class MetadataToolOutputAction( ToolOutputAction ):
223    tag = "metadata"
224    def __init__( self, parent, elem ):
225        super( MetadataToolOutputAction, self ).__init__( parent, elem )
226        self.name = elem.get( 'name', None )
227        assert self.name is not None, "Required 'name' attribute missing from MetadataToolOutputAction"
228    def apply_action( self, output_dataset, other_values ):
229        value = self.option.get_value( other_values )
230        if value is None and self.default is not None:
231            value = self.default
232        if value is not None:
233            setattr( output_dataset.metadata, self.name, value )
234
235class FormatToolOutputAction( ToolOutputAction ):
236    tag = "format"
237    def __init__( self, parent, elem ):
238        super( FormatToolOutputAction, self ).__init__( parent, elem )
239        self.default = elem.get( 'default', None )
240       
241    def apply_action( self, output_dataset, other_values ):
242        value = self.option.get_value( other_values )
243        if value is None and self.default is not None:
244            value = self.default
245        if value is not None:
246            output_dataset.extension = value
247
248class ToolOutputActionOptionFilter( object ):
249    tag = "filter"
250    @classmethod
251    def from_elem( cls, parent, elem ):
252        """Loads the proper action by the type attribute of elem"""
253        filter_type = elem.get( 'type', None )
254        assert filter_type is not None, "Required 'type' attribute missing from ToolOutputActionOptionFilter"
255        return filter_types[ filter_type ]( parent, elem )
256    def __init__( self, parent, elem ):
257        self.parent = parent
258    def filter_options( self, options, other_values ):
259        raise TypeError( "Not implemented" )
260    @property
261    def tool( self ):
262        return self.parent.tool
263
264class ParamValueToolOutputActionOptionFilter( ToolOutputActionOptionFilter ):
265    tag = "param_value"
266    def __init__( self, parent, elem ):
267        super( ParamValueToolOutputActionOptionFilter, self ).__init__( parent, elem )
268        self.ref = elem.get( 'ref', None )
269        if self.ref:
270            self.ref = self.ref.split( '.' )
271        self.value = elem.get( 'value', None )
272        assert self.ref != self.value, "Required 'ref' or 'value' attribute missing from ParamValueToolOutputActionOptionFilter"
273        self.column = elem.get( 'column', None )
274        assert self.column is not None, "Required 'column' attribute missing from ParamValueToolOutputActionOptionFilter"
275        self.column = int( self.column )
276        self.keep = util.string_as_bool( elem.get( "keep", 'True' ) )
277        self.compare = parse_compare_type( elem.get( 'compare', None ) )
278        self.cast = parse_cast_attribute( elem.get( "cast", None ) )
279    def filter_options( self, options, other_values ):
280        if self.ref:
281            #find ref value
282            value = other_values
283            for ref_name in self.ref:
284                assert ref_name in value, "Required dependency '%s' not found in incoming values" % ref_name
285                value = value.get( ref_name )
286            value = str( value )
287        else:
288            value = self.value
289        value = self.cast( value )
290        rval = []
291        for fields in options:
292            try:
293                if self.keep == ( self.compare( self.cast( fields[self.column] ), value ) ):
294                    rval.append( fields )
295            except Exception, e:
296                log.debug(e)
297                continue #likely a bad cast or column out of range
298        return rval
299
300class InsertColumnToolOutputActionOptionFilter( ToolOutputActionOptionFilter ):
301    tag = "insert_column"
302    def __init__( self, parent, elem ):
303        super( InsertColumnToolOutputActionOptionFilter, self ).__init__( parent, elem )
304        self.ref = elem.get( 'ref', None )
305        if self.ref:
306            self.ref = self.ref.split( '.' )
307        self.value = elem.get( 'value', None )
308        assert self.ref != self.value, "Required 'ref' or 'value' attribute missing from InsertColumnToolOutputActionOptionFilter"
309        self.column = elem.get( 'column', None ) #None is append
310        if self.column:
311            self.column = int( self.column )
312        self.iterate = util.string_as_bool( elem.get( "iterate", 'False' ) )
313    def filter_options( self, options, other_values ):
314        if self.ref:
315            #find ref value
316            value = other_values
317            for ref_name in self.ref:
318                assert ref_name in value, "Required dependency '%s' not found in incoming values" % ref_name
319                value = value.get( ref_name )
320            value = str( value )
321        else:
322            value = self.value
323        if self.iterate:
324            value = int( value )
325        rval = []
326        for fields in options:
327            if self.column is None:
328                rval.append( fields + [ str( value ) ] )
329            else:
330                fields = list( fields )
331                fields.insert( self.column, str( value ) )
332                rval.append( fields )
333            if self.iterate:
334                value += 1
335        return rval
336
337class MultipleSplitterFilter( ToolOutputActionOptionFilter ):
338    tag = "multiple_splitter"
339    def __init__( self, parent, elem ):
340        super( MultipleSplitterFilter, self ).__init__( parent, elem )
341        self.column = elem.get( 'column', None )
342        assert self.column is not None, "Required 'column' attribute missing from MultipleSplitterFilter"
343        self.column = int( self.column )
344        self.separator = elem.get( "separator", "," )
345    def filter_options( self, options, other_values ):
346        rval = []
347        for fields in options:
348            for field in fields[self.column].split( self.separator ):
349                rval.append( fields[0:self.column] + [field] + fields[self.column+1:] )
350        return rval
351
352class ColumnStripFilter( ToolOutputActionOptionFilter ):
353    tag = "column_strip"
354    def __init__( self, parent, elem ):
355        super( ColumnStripFilter, self ).__init__( parent, elem )
356        self.column = elem.get( 'column', None )
357        assert self.column is not None, "Required 'column' attribute missing from ColumnStripFilter"
358        self.column = int( self.column )
359        self.strip = elem.get( "strip", None )
360    def filter_options( self, options, other_values ):
361        rval = []
362        for fields in options:
363            rval.append( fields[0:self.column] + [ fields[self.column].strip( self.strip ) ] + fields[self.column+1:] )
364        return rval
365
366class ColumnReplaceFilter( ToolOutputActionOptionFilter ):
367    tag = "column_replace"
368    def __init__( self, parent, elem ):
369        super( ColumnReplaceFilter, self ).__init__( parent, elem )
370        self.old_column = elem.get( 'old_column', None )
371        self.old_value = elem.get( "old_value", None )
372        self.new_value = elem.get( "new_value", None )
373        self.new_column = elem.get( 'new_column', None )
374        assert ( bool( self.old_column ) ^ bool( self.old_value ) and bool( self.new_column ) ^ bool( self.new_value ) ), "Required 'old_column' or 'old_value' and 'new_column' or 'new_value' attribute missing from ColumnReplaceFilter"
375        self.column = elem.get( 'column', None )
376        assert self.column is not None, "Required 'column' attribute missing from ColumnReplaceFilter"
377        self.column = int( self.column )
378        if self.old_column is not None:
379            self.old_column = int( self.old_column )
380        if self.new_column is not None:
381            self.new_column = int( self.new_column )
382    def filter_options( self, options, other_values ):
383        rval = []
384        for fields in options:
385            if self.old_column:
386                old_value = fields[self.old_column]
387            else:
388                old_value = self.old_value
389            if self.new_column:
390                new_value = fields[self.new_column]
391            else:
392                new_value = self.new_value
393            rval.append( fields[0:self.column] + [ fields[self.column].replace( old_value, new_value ) ] + fields[self.column+1:] )
394        return rval
395
396class MetadataValueFilter( ToolOutputActionOptionFilter ):
397    tag = "metadata_value"
398    def __init__( self, parent, elem ):
399        super( MetadataValueFilter, self ).__init__( parent, elem )
400        self.ref = elem.get( 'ref', None )
401        assert self.ref is not None, "Required 'ref' attribute missing from MetadataValueFilter"
402        self.ref = self.ref.split( '.' )
403        self.name = elem.get( 'name', None )
404        assert self.name is not None, "Required 'name' attribute missing from MetadataValueFilter"
405        self.column = elem.get( 'column', None )
406        assert self.column is not None, "Required 'column' attribute missing from MetadataValueFilter"
407        self.column = int( self.column )
408        self.keep = util.string_as_bool( elem.get( "keep", 'True' ) )
409        self.compare = parse_compare_type( elem.get( 'compare', None ) )
410    def filter_options( self, options, other_values ):
411        ref = other_values
412        for ref_name in self.ref:
413            assert ref_name in ref, "Required dependency '%s' not found in incoming values" % ref_name
414            ref = ref.get( ref_name )
415        value = str( getattr( ref.metadata, self.name ) )
416        rval = []
417        for fields in options:
418            if self.keep == ( self.compare( fields[self.column], value ) ):
419                rval.append( fields )
420        return rval
421
422class BooleanFilter( ToolOutputActionOptionFilter ):
423    tag = "boolean"
424    def __init__( self, parent, elem ):
425        super( BooleanFilter, self ).__init__( parent, elem )
426        self.column = elem.get( 'column', None )
427        assert self.column is not None, "Required 'column' attribute missing from BooleanFilter"
428        self.column = int( self.column )
429        self.keep = util.string_as_bool( elem.get( "keep", 'True' ) )
430        self.cast = parse_cast_attribute( elem.get( "cast", None ) )
431    def filter_options( self, options, other_values ):
432        rval = []
433        for fields in options:
434            try:
435                value = fields[self.column]
436                value = self.cast( value )
437            except:
438                value = False #unable to cast or access value; treat as false
439            if self.keep == bool( value ):
440                rval.append( fields )
441        return rval
442
443class StringFunctionFilter( ToolOutputActionOptionFilter ):
444    tag = "string_function"
445    def __init__( self, parent, elem ):
446        super( StringFunctionFilter, self ).__init__( parent, elem )
447        self.column = elem.get( 'column', None )
448        assert self.column is not None, "Required 'column' attribute missing from StringFunctionFilter"
449        self.column = int( self.column )
450        self.function = elem.get( "name", None )
451        assert self.function in [ 'lower', 'upper' ], "Required function 'name' missing or invalid from StringFunctionFilter" #add function names as needed
452        self.function = getattr( string, self.function )
453    def filter_options( self, options, other_values ):
454        rval = []
455        for fields in options:
456            rval.append( fields[0:self.column] + [ self.function( fields[self.column] ) ] + fields[self.column+1:] )
457        return rval
458
459#tag to class lookups
460action_types = {}
461for action_type in [ MetadataToolOutputAction, FormatToolOutputAction ]:
462    action_types[ action_type.tag ] = action_type
463
464option_types = {}
465for option_type in [ NullToolOutputActionOption, FromFileToolOutputActionOption, FromParamToolOutputActionOption, FromDataTableOutputActionOption ]:
466    option_types[ option_type.tag ] = option_type
467   
468filter_types = {}
469for filter_type in [ ParamValueToolOutputActionOptionFilter, InsertColumnToolOutputActionOptionFilter, MultipleSplitterFilter, ColumnStripFilter, MetadataValueFilter, BooleanFilter, StringFunctionFilter, ColumnReplaceFilter ]:
470    filter_types[ filter_type.tag ] = filter_type
471
472
473#helper classes
474#determine cast function
475def parse_cast_attribute( cast ):
476    if cast == 'string_as_bool':
477        cast = util.string_as_bool
478    elif cast == 'int':
479        cast = int
480    elif cast == 'str':
481        cast = str
482    else:
483        cast = lambda x: x #return value as-is
484    return cast
485#comparison
486def parse_compare_type( compare ):
487    if compare is None: compare = 'eq'
488    assert compare in compare_types, "Invalid compare type specified: %s" % compare
489    return compare_types[ compare ]
490def compare_eq( value1, value2  ):
491    return value1 == value2
492def compare_neq( value1, value2  ):
493    return value1 != value2
494def compare_gt( value1, value2  ):
495    return value1 > value2
496def compare_gte( value1, value2  ):
497    return value1 >= value2
498def compare_lt( value1, value2  ):
499    return value1 < value2
500def compare_lte( value1, value2  ):
501    return value1 <= value2
502def compare_in( value1, value2 ):
503    return value1 in value2
504def compare_startswith( value1, value2 ):
505    return value1.startswith( value2 )
506def compare_endswith( value1, value2 ):
507    return value1.endswith( value2 )
508def compare_re_search( value1, value2 ):
509    #checks pattern=value2 in value1
510    return bool( re.search( value2, value1 ) )
511   
512compare_types = { 'eq':compare_eq, 'neq':compare_neq, 'gt':compare_gt, 'gte':compare_gte, 'lt':compare_lt, 'lte':compare_lte, 'in':compare_in, 'startswith':compare_startswith, 'endswith':compare_endswith, "re_search":compare_re_search }
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。