fix git support for v1.5.3 (or higher) by setting "--work-tree"
[translate_toolkit.git] / storage / factory.py
blob7bce08735ba94868672dcdb3b0792a1d983b927a
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 #
4 # Copyright 2006 Zuza Software Foundation
5 #
6 # This file is part of translate.
8 # translate 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.
13 # translate 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.
18 # You should have received a copy of the GNU General Public License
19 # along with translate; if not, write to the Free Software
20 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 """factory methods to build real storage objects that conform to base.py"""
24 import os
25 from gzip import GzipFile
26 try:
27 # bz2 is not available on python 2.3
28 from bz2 import BZ2File
29 except ImportError:
30 BZ2File = None
31 import sys
33 from translate.storage import base
34 from translate.storage import csvl10n
35 from translate.storage import mo
36 from translate.storage import po
37 from translate.storage import qm
38 from translate.storage import wordfast
39 #Let's try to import the XML formats carefully. They might fail if the user
40 #doesn't have lxml installed. Let's try to continue gracefully, but print an
41 #informative warning.
42 try:
43 #Although poxliff is unused in this module, it is referenced in test_factory
44 from translate.storage import poxliff
45 from translate.storage import tbx
46 from translate.storage import tmx
47 from translate.storage import xliff
48 support_xml = True
49 except ImportError, e:
50 print >> sys.stderr, str(e)
51 support_xml = False
54 #TODO: Monolingual formats (with template?)
56 classes = {
57 "csv": csvl10n.csvfile,
58 "po": po.pofile, "pot": po.pofile,
59 "mo": mo.mofile, "gmo": mo.mofile,
60 "qm": qm.qmfile,
61 "_wftm": wordfast.WordfastTMFile,
63 """Dictionary of file extensions and their associated class.
65 _ext is a pseudo extension, that is their is no real extension by that name."""
67 if support_xml:
68 classes.update({
69 "tbx": tbx.tbxfile,
70 "tmx": tmx.tmxfile,
71 "xliff": xliff.xlifffile, "xlf": xliff.xlifffile,
74 decompressclass = {
75 'gz': GzipFile,
77 if BZ2File:
78 decompressclass['bz2'] = BZ2File
80 def _examine_txt(storefile):
81 """Determine the true filetype for a .txt file"""
82 if isinstance(storefile, basestring) and os.path.exists(storefile):
83 storefile = open(storefile)
84 try:
85 start = storefile.read(600).strip()
86 except AttributeError:
87 raise ValueError("Need to read object to determine type")
88 # Some encoding magic for Wordfast
89 if wordfast.TAB_UTF16 in start.split("\n")[0]:
90 encoding = 'utf-16'
91 else:
92 encoding = 'iso-8859-1'
93 start = start.decode(encoding).encode('utf-8')
94 if '%Wordfast TM' in start:
95 pseudo_extension = '_wftm'
96 else:
97 raise ValueError("Failed to guess file type.")
98 storefile.seek(0)
99 return pseudo_extension
101 hiddenclasses = {"txt": _examine_txt}
103 def _guessextention(storefile):
104 """Guesses the type of a file object by looking at the first few characters.
105 The return value is a file extention ."""
106 start = storefile.read(300).strip()
107 if '<xliff ' in start:
108 extention = 'xlf'
109 elif 'msgid "' in start:
110 extention = 'po'
111 elif '%Wordfast TM' in start:
112 extention = 'txt'
113 else:
114 raise ValueError("Failed to guess file type.")
115 storefile.seek(0)
116 return extention
118 def _getdummyname(storefile):
119 """Provides a dummy name for a file object without a name attribute, by guessing the file type."""
120 return 'dummy.' + _guessextention(storefile)
122 def _getname(storefile):
123 """returns the filename"""
124 if storefile is None:
125 raise ValueError("This method cannot magically produce a filename when given None as input.")
126 if not isinstance(storefile, basestring):
127 if not hasattr(storefile, "name"):
128 storefilename = _getdummyname(storefile)
129 else:
130 storefilename = storefile.name
131 else:
132 storefilename = storefile
133 return storefilename
135 def getclass(storefile, ignore=None):
136 """Factory that returns the applicable class for the type of file presented.
137 Specify ignore to ignore some part at the back of the name (like .gz). """
138 storefilename = _getname(storefile)
139 if ignore and storefilename.endswith(ignore):
140 storefilename = storefilename[:-len(ignore)]
141 root, ext = os.path.splitext(storefilename)
142 ext = ext[len(os.path.extsep):].lower()
143 decomp = None
144 if ext in decompressclass:
145 decomp = ext
146 root, ext = os.path.splitext(root)
147 ext = ext[len(os.path.extsep):].lower()
148 if ext in hiddenclasses:
149 guesserfn = hiddenclasses[ext]
150 if decomp:
151 ext = guesserfn(decompressclass[decomp](storefile))
152 else:
153 ext = guesserfn(storefile)
154 try:
155 storeclass = classes[ext]
156 except KeyError:
157 raise ValueError("Unknown filetype (%s)" % storefilename)
158 return storeclass
160 def getobject(storefile, ignore=None):
161 """Factory that returns a usable object for the type of file presented.
163 @type storefile: file or str
164 @param storefile: File object or file name.
166 Specify ignore to ignore some part at the back of the name (like .gz).
169 if isinstance(storefile, base.TranslationStore):
170 return storefile
171 if isinstance(storefile, basestring):
172 if os.path.isdir(storefile) or storefile.endswith(os.path.sep):
173 from translate.storage import directory
174 return directory.Directory(storefile)
175 storefilename = _getname(storefile)
176 storeclass = getclass(storefile, ignore)
177 if os.path.exists(storefilename) or not getattr(storefile, "closed", True):
178 name, ext = os.path.splitext(storefilename)
179 ext = ext[len(os.path.extsep):].lower()
180 if ext in decompressclass:
181 storefile = decompressclass[ext](storefilename)
182 store = storeclass.parsefile(storefile)
183 else:
184 store = storeclass()
185 return store