Package translate :: Package convert :: Module factory
[hide private]
[frames] | no frames]

Source Code for Module translate.convert.factory

  1  #!/usr/bin/env python 
  2  # -*- coding: utf-8 -*- 
  3  # 
  4  # Copyright 2010 Zuza Software Foundation 
  5  # 
  6  # This file is part of the Translate Toolkit. 
  7  # 
  8  # This program is free software; you can redistribute it and/or modify 
  9  # it under the terms of the GNU General Public License as published by 
 10  # the Free Software Foundation; either version 2 of the License, or 
 11  # (at your option) any later version. 
 12  # 
 13  # This program is distributed in the hope that it will be useful, 
 14  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 15  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 16  # GNU General Public License for more details. 
 17  # 
 18  # You should have received a copy of the GNU General Public License 
 19  # along with this program; if not, see <http://www.gnu.org/licenses/>. 
 20   
 21  """Factory methods to convert supported input files to supported translatable files.""" 
 22   
 23  import os 
 24   
 25  #from translate.convert import prop2po, po2prop, odf2xliff, xliff2odf 
 26   
 27   
 28  __all__ = ['converters', 'convertfile', 'UnknownExtensionError', 'UnsupportedConversionError'] 
 29   
 30  # Turn into property to support lazy loading of things? 
 31  converters = {} 
 32  #for module in (prop2po, po2prop, odf2xliff, xliff2odf): 
 33  #    if not hasattr(module, 'formats'): 
 34  #        continue 
 35  #    for extension in module.formats: 
 36  #        if extension not in converters: 
 37  #            converters[extension] = [] 
 38  #        converters[extension].append(module.formats[extension]) 
 39   
 40   
41 -class UnknownExtensionError(Exception):
42
43 - def __init__(self, afile):
44 self.file = afile
45
46 - def __str__(self):
47 return 'Unable to find extension for file: %s' % (self.file)
48
49 - def __unicode__(self):
50 return unicode(str(self))
51 52
53 -class UnsupportedConversionError(Exception):
54
55 - def __init__(self, in_ext=None, out_ext=None, templ_ext=None):
56 self.in_ext = in_ext 57 self.out_ext = out_ext 58 self.templ_ext = templ_ext
59
60 - def __str__(self):
61 msg = "Unsupported conversion from %s to %s" % (self.in_ext, self.out_ext) 62 if self.templ_ext: 63 msg += ' with template %s' % (self.templ_ext) 64 return msg
65
66 - def __unicode__(self):
67 return unicode(str(self))
68 69
70 -def get_extension(filename):
71 path, fname = os.path.split(filename) 72 ext = fname.split(os.extsep)[-1] 73 if ext == fname: 74 return None 75 return ext
76 77
78 -def get_converter(in_ext, out_ext=None, templ_ext=None):
79 convert_candidates = None 80 if templ_ext: 81 if (in_ext, templ_ext) in converters: 82 convert_candidates = converters[(in_ext, templ_ext)] 83 else: 84 raise UnsupportedConversionError(in_ext, out_ext, templ_ext) 85 else: 86 if in_ext in converters: 87 convert_candidates = converters[in_ext] 88 elif (in_ext,) in converters: 89 convert_candidates = converters[(in_ext,)] 90 else: 91 raise UnsupportedConversionError(in_ext, out_ext) 92 93 convert_fn = None 94 if not out_ext: 95 out_ext, convert_fn = convert_candidates[0] 96 else: 97 for ext, func in convert_candidates: 98 if ext == out_ext: 99 convert_fn = func 100 break 101 102 if not convert_fn: 103 raise UnsupportedConversionError(in_ext, out_ext, templ_ext) 104 return convert_fn
105 106
107 -def get_output_extensions(ext):
108 """Compiles a list of possible output extensions for the given input extension.""" 109 out_exts = [] 110 for key in converters: 111 in_ext = key 112 if isinstance(key, tuple): 113 in_ext = key[0] 114 if in_ext == ext: 115 for out_ext, convert_fn in converters[key]: 116 out_exts.append(out_ext) 117 return out_exts
118 119
120 -def convert(inputfile, template=None, options=None, convert_options=None):
121 """Convert the given input file to an appropriate output format, optionally 122 using the given template file and further options. 123 124 If the output extension (format) cannot be inferred the first converter 125 that can handle the input file (and the format/extension it gives as 126 output) is used. 127 128 @type inputfile: file 129 @param inputfile: The input file to be converted 130 @type template: file 131 @param template: Template file to use during conversion 132 @type options: dict (default: None) 133 @param options: Valid options are: 134 - in_ext: The extension (format) of the input file. 135 - out_ext: The extension (format) to use for the output file. 136 - templ_ext: The extension (format) of the template file. 137 - in_fname: File name of the input file; used only to determine 138 the input file extension (format). 139 - templ_fname: File name of the template file; used only to 140 determine the template file extension (format). 141 @returns: a 2-tuple: The new output file (in a temporary directory) and 142 the extension (format) of the output file. The caller is 143 responsible for deleting the (temporary) output file.""" 144 in_ext, out_ext, templ_ext = None, None, None 145 146 # Get extensions from options 147 if options is None: 148 options = {} 149 else: 150 if 'in_ext' in options: 151 in_ext = options['in_ext'] 152 if 'out_ext' in options: 153 out_ext = options['out_ext'] 154 if template and 'templ_ext' in options: 155 templ_ext = options['templ_ext'] 156 157 # If we still do not have extensions, try and get it from the *_fname options 158 if not in_ext and 'in_fname' in options: 159 in_ext = get_extension(options['in_fname']) 160 if template and not templ_ext and 'templ_fname' in options: 161 templ_fname = get_extension(options['templ_fname']) 162 163 # If we still do not have extensions, get it from the file names 164 if not in_ext and hasattr(inputfile, 'name'): 165 in_ext = get_extension(inputfile.name) 166 if template and not templ_ext and hasattr(template, 'name'): 167 templ_ext = get_extension(template.name) 168 169 if not in_ext: 170 raise UnknownExtensionError(inputfile) 171 if template and not templ_ext: 172 raise UnknownExtensionError(template) 173 174 out_ext_candidates = get_output_extensions(in_ext) 175 if not out_ext_candidates: 176 # No converters registered for the in_ext we have 177 raise UnsupportedConversionError(in_ext=in_ext, templ_ext=templ_ext) 178 if out_ext and out_ext not in out_ext_candidates: 179 # If out_ext has a value at this point, it was given in options, so 180 # we just take a second to make sure that the conversion is supported. 181 raise UnsupportedConversionError(in_ext, out_ext, templ_ext) 182 183 if not out_ext and templ_ext in out_ext_candidates: 184 # If we're using a template, chances are (pretty damn) good that the 185 # output file will be of the same type 186 out_ext = templ_ext 187 else: 188 # As a last resort, we'll just use the first possible output format 189 out_ext = out_ext_candidates[0] 190 191 # XXX: We are abusing tempfile.mkstemp() below: we are only using it to 192 # obtain a temporary file name to use the normal open() with. This is 193 # done because a tempfile.NamedTemporaryFile simply gave too many 194 # issues when being closed (and deleted) by the rest of the toolkit 195 # (eg. TranslationStore.savefile()). Therefore none of mkstemp()'s 196 # security features are being utilised. 197 import tempfile 198 tempfd, tempfname = tempfile.mkstemp(prefix='ttk_convert', suffix=os.extsep + out_ext) 199 os.close(tempfd) 200 outputfile = open(tempfname, 'w') 201 202 if convert_options is None: 203 convert_options = {} 204 get_converter(in_ext, out_ext, templ_ext)(inputfile, outputfile, template, **convert_options) 205 if hasattr(outputfile, 'closed') and hasattr(outputfile, 'close') and not outputfile.closed: 206 outputfile.close() 207 return outputfile, out_ext
208