iotypes.py 9.16 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#
# Copyright (C) 2012 INRA
# 
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

18
19
20
21
import os, re
import abc
from _pyio import __metaclass__

22

Jerome Mariette's avatar
Jerome Mariette committed
23
24
25
26
27
28
class Formats(object):
    ANY = "any"
    BAM = "bam"
    FASTQ = "fastq"
    FASTA = "fasta"
    SFF = "sff"
29
30
    QUAL = "qual"
    FLOW = "flow"
Jerome Mariette's avatar
Jerome Mariette committed
31
    HTML = "html"
Jerome Mariette's avatar
Jerome Mariette committed
32
    
33
# 
Jerome Mariette's avatar
Jerome Mariette committed
34
35
# Inputs classes
#
36
class InputFile(str):
Jerome Mariette's avatar
Jerome Mariette committed
37
    
38
39
    def __new__(self, input, format=Formats.ANY):
        self.format = format
Jerome Mariette's avatar
Jerome Mariette committed
40
41
        if input.__class__.__name__ == "str":
            return str.__new__(self, input)
42
        elif input.__class__.__name__ == "OutputFile" and (input.format == self.format or self.format == Formats.ANY):
Jerome Mariette's avatar
Jerome Mariette committed
43
            return str.__new__(self, input)
44
45
        elif input.__class__.__name__ == "OutputFile" and not (input.format == self.format or self.format == Formats.ANY):
            raise IOError(input.format+" format is incompatible with allowed format "+self.format)
Jerome Mariette's avatar
Jerome Mariette committed
46
        else:
47
            raise IOError(input.__class__.__name__+" cannot be used as InputFile")
48
    
Jerome Mariette's avatar
Jerome Mariette committed
49
    def check(self):
Jerome Mariette's avatar
Jerome Mariette committed
50
        return "TODO: check input file"
51

52
class InputFileList(list):
Jerome Mariette's avatar
Jerome Mariette committed
53

54
55
    def __init__(self, inputs, format=Formats.ANY):
        self.format = format
Jerome Mariette's avatar
Jerome Mariette committed
56
57
        if inputs.__class__.__name__ == "str":
            return list.__init__(self, [inputs])
58
        elif inputs.__class__.__name__ == "OutputFile" and (inputs.format == self.format or self.format == Formats.ANY):
Jerome Mariette's avatar
Jerome Mariette committed
59
60
61
            return list.__init__(self, [inputs])
        elif inputs.__class__.__name__ == "list":
            return list.__init__(self, inputs)
62
        elif inputs.__class__.__name__ == "OutputFileList" and (inputs.format == self.format or self.format == Formats.ANY):
Jerome Mariette's avatar
Jerome Mariette committed
63
            return list.__init__(self, inputs)
64
65
66
67
        elif inputs.__class__.__name__ == "OutputFileEndsWith" and (inputs.format == self.format or self.format == Formats.ANY):
            return list.__init__(self, inputs)
        elif inputs.__class__.__name__ == "OutputFilePattern" and (inputs.format == self.format or self.format == Formats.ANY):
            return list.__init__(self, inputs)
68
69
70
        elif (inputs.__class__.__name__ == "OutputFile" or inputs.__class__.__name__ == "OutputFileList") and \
            not (inputs.format == self.format or self.format == Formats.ANY):
            raise IOError(inputs.format+" format is incompatible with allowed format "+self.format)
Jerome Mariette's avatar
Jerome Mariette committed
71
        else:
72
            raise IOError(inputs.__class__.__name__+" cannot be used as InputFileList")
Jerome Mariette's avatar
Jerome Mariette committed
73

Jerome Mariette's avatar
Jerome Mariette committed
74
    def check(self):
Jerome Mariette's avatar
Jerome Mariette committed
75
        return "TODO: check input file list"
76
77

class InputDirectory(str):
Jerome Mariette's avatar
Jerome Mariette committed
78
    
79
80
81
82
83
84
85
86
87
    def __new__(self, input):
        if input.__class__.__name__ == "str":
            return str.__new__(self, input)
        elif input.__class__.__name__ == "OutputDirectory":
            return str.__new__(self, input)
        else:
            raise IOError(input.__class__.__name__+" cannot be used as InputDirectory")
    
    def check(self):
Jerome Mariette's avatar
Jerome Mariette committed
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
        return "TODO: check input directory"

class InputDirectoryList(list):

    def __init__(self, inputs):
        if inputs.__class__.__name__ == "str":
            return list.__init__(self, [inputs])
        elif inputs.__class__.__name__ == "OutputDirectory":
            return list.__init__(self, [inputs])
        elif inputs.__class__.__name__ == "list":
            return list.__init__(self, inputs)
        elif inputs.__class__.__name__ == "OutputDirectoryList":
            return list.__init__(self, inputs)
        else:
            raise IOError(inputs.__class__.__name__+" cannot be used as InputDirectoryList")
103

Jerome Mariette's avatar
Jerome Mariette committed
104
105
106
# 
# Outputs classes
#
107
108
109
110
111
112
113
114
115
116
117
118
119
class DynamicOutput(list):
    """        
     @warning : with this class of output, the component become dynamic.
    """
    __metaclass__ = abc.ABCMeta
    
    @abc.abstractmethod
    def update(self):
        """ 
         This method is used at the end of component execution to update output list.
        """
        raise NotImplementedError
    
120
class OutputFile(str):
121
    
Jerome Mariette's avatar
Jerome Mariette committed
122
123
124
125
126
    def __new__(self, output, format=Formats.ANY):
        self.format = format
        if output.__class__.__name__ == "str":
            return str.__new__(self, output)
        else:
127
            raise IOError(output.__class__.__name__+" cannot be used as OutputFile")
128
    
Jerome Mariette's avatar
Jerome Mariette committed
129
    def check(self):
Jerome Mariette's avatar
Jerome Mariette committed
130
        return "TODO: check output file"
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
        
class OutputFileList(list):
    
    def __init__(self, outputs, format=Formats.ANY):
        self.format = format
        if outputs.__class__.__name__ == "str":
            return list.__init__(self, [outputs])
        elif outputs.__class__.__name__ == "list":
            return list.__init__(self, outputs)
        else:
            raise IOError(outputs.__class__.__name__+" cannot be used as OutputFileList")

    def check(self):
        return "TODO: check output file list"

class OutputFilePattern(DynamicOutput):
    
    def __init__(self, output_directory, pattern, format=Formats.ANY, include=True):
        """        
         @warning : with this class of output, the component become dynamic.
         @param output_directory : path to the directory where outputs will be created.
         @param pattern : the pattern of (a part) the file names.
         @param format : the files format.
         @param include : if true, the files with the pattern in file name are added into output files.
                          If false, the files with the pattern in file name are added into output files.
        """
        self.output_directory = output_directory
        self.pattern = pattern
        self.format = format
        self.include = include
        return list.__init__(self, [])

    def update(self):
        output_files = list()
        for file in os.listdir( self.output_directory ):
            if self.include and re.search( self.pattern, file ) is not None:
                output_files.append( os.path.join(self.output_directory, file) )
            elif not self.include and re.search( self.pattern, file ) is None:
                output_files.append( os.path.join(self.output_directory, file) )
        return list.__init__(self, output_files)
    
    def check(self):
        return "TODO: check output file list"

class OutputFileEndsWith(DynamicOutput):
    
    def __init__(self, output_directory, end_str, format=Formats.ANY, include=True):
        """        
         @warning : with this class of output, the component become dynamic.
         @param output_directory : path to the directory where outputs will be created.
         @param end_str : the end of the files names.
         @param format : the files format.
         @param include : if true, the files with name terminated by end_str are added into output files.
                          If false, the files with name not terminated by end_str are added into output files.
        """
        self.output_directory = output_directory
        self.end_str = end_str
        self.format = format
        self.include = include
        return list.__init__(self, [])

    def update(self):
        output_files = list()
        for file in os.listdir( self.output_directory ):
            if file.endswith( self.end_str ) and self.include :
                output_files.append( os.path.join(self.output_directory, file) )
            elif not file.endswith( self.end_str ) and not self.include:
                output_files.append( os.path.join(self.output_directory, file) )
        return list.__init__(self, output_files)
    
    def check(self):
        return "TODO: check output file list"
203

204
class OutputFileList(list):
Jerome Mariette's avatar
Jerome Mariette committed
205
    
Jerome Mariette's avatar
Jerome Mariette committed
206
207
208
209
210
211
212
    def __init__(self, outputs, format=Formats.ANY):
        self.format = format
        if outputs.__class__.__name__ == "str":
            return list.__init__(self, [outputs])
        elif outputs.__class__.__name__ == "list":
            return list.__init__(self, outputs)
        else:
213
            raise IOError(outputs.__class__.__name__+" cannot be used as OutputFileList")
Jerome Mariette's avatar
Jerome Mariette committed
214

Jerome Mariette's avatar
Jerome Mariette committed
215
    def check(self):
Jerome Mariette's avatar
Jerome Mariette committed
216
        return "TODO: check output file list"
217
218
219
220
221
222
223
224
225
226

class OutputDirectory(str):
    
    def __new__(self, output):
        if output.__class__.__name__ == "str":
            return str.__new__(self, output)
        else:
            raise IOError(output.__class__.__name__+" cannot be used as OutputDirectory")
    
    def check(self):
Jerome Mariette's avatar
Jerome Mariette committed
227
228
229
230
231
232
233
234
235
236
237
238
239
        return "TODO: check output directory"

class OutputDirectoryList(list):

    def __init__(self, outputs):
        if outputs.__class__.__name__ == "str":
            return list.__init__(self, [outputs])
        elif outputs.__class__.__name__ == "list":
            return list.__init__(self, outputs)
        else:
            raise IOError(outputs.__class__.__name__+" cannot be used as OutputDirectoryList")

    def check(self):
240
241
        return "TODO: check output directory list"