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"