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  import tempfile 
 25   
 26  from translate.convert import prop2po, po2prop, odf2xliff, xliff2odf 
 27   
 28   
 29  __all__ = ['converters', 'convertfile', 'UnknownExtensionError', 'UnsupportedConversionError'] 
 30   
 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 - def __init__(self, afile):
43 self.file = afile
44
45 - def __str__(self):
46 return 'Unable to find extension for file: %s' % (self.file)
47
48 - def __unicode__(self):
49 return unicode(str(self))
50
51 -class UnsupportedConversionError(Exception):
52 - def __init__(self, in_ext=None, out_ext=None, templ_ext=None):
53 self.in_ext = in_ext 54 self.out_ext = out_ext 55 self.templ_ext = templ_ext
56
57 - def __str__(self):
58 msg = "Unsupported conversion from %s to %s" % (self.in_ext, self.out_ext) 59 if self.templ_ext: 60 msg += ' with template %s' % (self.templ_ext) 61 return msg
62
63 - def __unicode__(self):
64 return unicode(str(self))
65 66
67 -def get_extension(filename):
68 path, fname = os.path.split(filename) 69 ext = fname.split(os.extsep)[-1] 70 if ext == fname: 71 return None 72 return ext
73
74 -def get_converter(in_ext, out_ext=None, templ_ext=None):
75 convert_candidates = None 76 if templ_ext: 77 if (in_ext, templ_ext) in converters: 78 convert_candidates = converters[(in_ext, templ_ext)] 79 else: 80 raise UnsupportedConversionError(in_ext, out_ext, templ_ext) 81 else: 82 if in_ext in converters: 83 convert_candidates = converters[in_ext] 84 elif (in_ext,) in converters: 85 convert_candidates = converters[(in_ext,)] 86 else: 87 raise UnsupportedConversionError(in_ext, out_ext) 88 89 convert_fn = None 90 if not out_ext: 91 out_ext, convert_fn = convert_candidates[0] 92 else: 93 for ext, func in convert_candidates: 94 if ext == out_ext: 95 convert_fn = func 96 break 97 98 if not convert_fn: 99 raise UnsupportedConversionError(in_ext, out_ext, templ_ext) 100 return convert_fn
101
102 -def get_output_extensions(ext):
103 """Compiles a list of possible output extensions for the given input extension.""" 104 out_exts = [] 105 for key in converters: 106 in_ext = key 107 if isinstance(key, tuple): 108 in_ext = key[0] 109 if in_ext == ext: 110 for out_ext, convert_fn in converters[key]: 111 out_exts.append(out_ext) 112 return out_exts
113
114 -def convert(inputfile, template=None, options=None, convert_options=None):
115 """Convert the given input file to an appropriate output format, optionally 116 using the given template file and further options. 117 118 If the output extension (format) cannot be inferred the first converter 119 that can handle the input file (and the format/extension it gives as 120 output) is used. 121 122 @type inputfile: file 123 @param inputfile: The input file to be converted 124 @type template: file 125 @param template: Template file to use during conversion 126 @type options: dict (default: None) 127 @param options: Valid options are: 128 - in_ext: The extension (format) of the input file. 129 - out_ext: The extension (format) to use for the output file. 130 - templ_ext: The extension (format) of the template file. 131 - in_fname: File name of the input file; used only to determine 132 the input file extension (format). 133 - templ_fname: File name of the template file; used only to 134 determine the template file extension (format). 135 @returns: a 2-tuple: The new output file (in a temporary directory) and 136 the extension (format) of the output file. The caller is 137 responsible for deleting the (temporary) output file.""" 138 in_ext, out_ext, templ_ext = None, None, None 139 140 # Get extensions from options 141 if options is None: 142 options = {} 143 else: 144 if 'in_ext' in options: 145 in_ext = options['in_ext'] 146 if 'out_ext' in options: 147 out_ext = options['out_ext'] 148 if template and 'templ_ext' in options: 149 templ_ext = options['templ_ext'] 150 151 # If we still do not have extensions, try and get it from the *_fname options 152 if not in_ext and 'in_fname' in options: 153 in_ext = get_extension(options['in_fname']) 154 if template and not templ_ext and 'templ_fname' in options: 155 templ_fname = get_extension(options['templ_fname']) 156 157 # If we still do not have extensions, get it from the file names 158 if not in_ext and hasattr(inputfile, 'name'): 159 in_ext = get_extension(inputfile.name) 160 if template and not templ_ext and hasattr(template, 'name'): 161 templ_ext = get_extension(template.name) 162 163 if not in_ext: 164 raise UnknownExtensionError(inputfile) 165 if template and not templ_ext: 166 raise UnknownExtensionError(template) 167 168 out_ext_candidates = get_output_extensions(in_ext) 169 if not out_ext_candidates: 170 # No converters registered for the in_ext we have 171 raise UnsupportedConversionError(in_ext=in_ext, templ_ext=templ_ext) 172 if out_ext and out_ext not in out_ext_candidates: 173 # If out_ext has a value at this point, it was given in options, so 174 # we just take a second to make sure that the conversion is supported. 175 raise UnsupportedConversionError(in_ext, out_ext, templ_ext) 176 177 if not out_ext and templ_ext in out_ext_candidates: 178 # If we're using a template, chances are (pretty damn) good that the 179 # output file will be of the same type 180 out_ext = templ_ext 181 else: 182 # As a last resort, we'll just use the first possible output format 183 out_ext = out_ext_candidates[0] 184 185 # XXX: We are abusing tempfile.mkstemp() below: we are only using it to 186 # obtain a temporary file name to use the normal open() with. This is 187 # done because a tempfile.NamedTemporaryFile simply gave too many 188 # issues when being closed (and deleted) by the rest of the toolkit 189 # (eg. TranslationStore.savefile()). Therefore none of mkstemp()'s 190 # security features are being utilised. 191 tempfd, tempfname = tempfile.mkstemp(prefix='ttk_convert', suffix=os.extsep+out_ext) 192 os.close(tempfd) 193 outputfile = open(tempfname, 'w') 194 195 if convert_options is None: 196 convert_options = {} 197 get_converter(in_ext, out_ext, templ_ext)(inputfile, outputfile, template, **convert_options) 198 if hasattr(outputfile, 'closed') and hasattr(outputfile, 'close') and not outputfile.closed: 199 outputfile.close() 200 return outputfile, out_ext
201