1 """
2 Holds the TypeConverter class
3
4 Copyright: John Stowers, 2006
5 License: GPLv2
6 """
7 import traceback
8 import logging
9 log = logging.getLogger("TypeConverter")
10
11 import conduit.Exceptions as Exceptions
12 import conduit.utils as Utils
13
16
18 """
19 Maintains a dictionary of dictionaries, indexed by the type converted FROM which
20 maps to a list of types that can be converted TO
21
22 An example statically constructed conversion dictionary is::
23
24 self.convertables = {
25 "from1" :
26 {
27 "to1":from1_to_to1_converter,
28 "to2":from1_to_to2_converter
29 },
30 "from2" :
31 {
32 "to3":from2_to_to3_converter,
33 "to1":from2_to_to1_converter
34 },
35 "from3" :
36 {
37 "to5":from3_to_to5_converter
38 }
39 }
40
41
42 @ivar convertables: The name of the contained module
43 @type convertables: C{dict of dicts}, see description
44 in L{conduit.TypeConverter.TypeConverter}
45 """
46
48 """
49 Builds the conversion dictionary
50
51 @param dynamic_modules: The dynamically loaded converters
52 """
53
54 self.convertables = {}
55
56 moduleManager.make_modules_callable("converter")
57 dynamic_modules = moduleManager.get_modules_by_type("converter")
58 for d in dynamic_modules:
59 self._add_converter(d)
60
62 conv = getattr(converterWrapper.module,"conversions", {})
63 for c in conv:
64 try:
65
66 fromtype = c.split(',')[0]
67 totype = c.split(',')[1]
68
69
70 if not self.convertables.has_key(fromtype):
71 self.convertables[fromtype] = {totype:conv[c]}
72
73
74 else:
75 self.convertables[fromtype][totype] = conv[c]
76 except IndexError:
77 log.warn("Conversion dict (%s) wrong format. Should be fromtype,totype" % c)
78 except KeyError, err:
79 log.warn("Could not add conversion function from %s to %s\n%s" % (fromtype,totype,err))
80 except Exception:
81 log.warn("BAD PROGRAMMER")
82
84 """
85 Retains the original datatype properties through a type conversion.
86 Properties retained include;
87 - gnome-open'able URI
88 - modification time
89 - original UID
90 Call this function from a typeconverter
91 """
92 if todata == None:
93 log.warn("Conversion from %s returned None" % (fromdata))
94 else:
95 todata.set_mtime(fromdata.get_mtime())
96 todata.set_open_URI(fromdata.get_open_URI())
97 todata.set_UID(fromdata.get_UID())
98 return todata
99
101 """
102 Returns the conversions required fromtype -> totype. Considers if fromtype and/or
103 totype are super/subclasses of each other. The args string is always taken from the
104 destination, i.e. the totype.
105
106 Does not check if the conversion actually exists.
107
108 @returns: list of (fromtype, totype, args) tuples
109 """
110 conversions = []
111 args = {}
112 fromType = from_type
113 toType = to_type
114
115
116 try:
117 fromType = from_type.split("?")[0]
118 except ValueError: pass
119
120
121 try:
122 toType,argString = to_type.split("?")
123 args = Utils.decode_conversion_args(argString)
124 except ValueError: pass
125
126 if fromType != toType:
127
128 if self._conversion_exists(fromType, toType):
129 conversions.append( (fromType, toType, args) )
130 else:
131 froms = fromType.split("/")
132 tos = toType.split("/")
133 if froms[0] == tos[0]:
134
135
136
137 conversions.append( (froms[0],"/".join(tos),args) )
138 else:
139
140
141 if len(tos) > 1:
142
143
144 conversions.append( (froms[0], tos[0], {}) )
145 conversions.append( (tos[0],"/".join(tos),args) )
146 else:
147
148 conversions.append( (froms[0], tos[0], args) )
149 else:
150 conversions.append( (fromType, toType, args) )
151
152 return conversions
153
155 if self.convertables.has_key(from_type):
156 if self.convertables[from_type].has_key(to_type):
157 return True
158 return False
159
161 if len(conversions) > 0:
162 from_type, to_type, args = conversions[0]
163 message = "Converting"
164 if from_type == to_type:
165 message = "Transcoding"
166
167 if args == {} or not self._conversion_exists(from_type, to_type):
168
169 log.debug("Skipping %s -> %s" % (from_type, to_type))
170 return self._convert(conversions[1:],data)
171
172 log.debug("%s %s -> %s (args: %s)" % (message, from_type, to_type, args))
173 try:
174
175 return self._convert(
176 conversions[1:],
177 self.convertables[from_type][to_type](data, **args)
178 )
179 except Exception:
180 log.debug(traceback.format_exc())
181 raise Exceptions.ConversionError(from_type, to_type)
182 else:
183 return data
184
186 """
187 Checks if all conversion(s) exists to convert from from_type
188 into to_type
189 """
190 for f,t,a in self._get_conversions(from_type, to_type):
191 if f != t and not self._conversion_exists(f,t):
192 log.debug("Conversions %s -> %s doesnt exist" % (f,t))
193 return False
194 return True
195
196 - def convert(self, from_type, to_type, data):
197 """
198 Converts a L{conduit.DataType.DataType} (or derived) of type
199 from_type into to_type and returns that newly converted type. If no
200 conversion is needed, the original data is returned.
201
202 @param from_type: The name of the type converted from
203 @type from_type: C{string}
204 @param to_type: The name of the type to convert to
205 @type to_type: C{string}
206 @param data: The DataType to convert
207 @type data: L{conduit.DataType.DataType}
208 """
209 conversions = self._get_conversions(from_type, to_type)
210 log.debug("Convert %s -> %s using %s" % (from_type, to_type, conversions))
211
212 if self.conversion_exists(from_type, to_type):
213
214 newdata = self._convert(conversions, data)
215 else:
216 raise Exceptions.ConversionDoesntExistError(from_type, to_type)
217
218 return self._retain_info_in_conversion(fromdata=data, todata=newdata)
219
221 """
222 Returns a list of 2-tuples specifying conversions (from->to)
223 """
224 l = []
225 for froms in self.convertables:
226 for tos in self.convertables[froms]:
227 l.append( (froms, tos) )
228 return l
229