1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 __doc__ = \
21 """
22 WURFL processing utility.
23 """
24
25
26 import sys
27 from optparse import OptionParser
28
29 try:
30 from xml.etree.ElementTree import parse
31 except ImportError:
32 try:
33 from cElementTree import parse
34 except ImportError:
35 from elementtree.ElementTree import parse
36
37 from pywurfl.exceptions import WURFLException
38
39
40 __author__ = "Armand Lynch <lyncha@users.sourceforge.net>"
41 __contributors__ = "Pau Aliagas <pau@newtral.org>"
42 __copyright__ = "Copyright 2004-2008, Armand Lynch"
43 __license__ = "LGPL"
44 __url__ = "http://celljam.net/"
45 __all__ = ['DeferredDeviceError', 'DeviceHandler', 'WurflProcessor', 'main',
46 'op']
47
48
50 """
51 Deferred Device Error Exception
52
53 Raised when all devices have been processed and there are still deferred
54 devices.
55 """
56 pass
57
58
60 """
61 Base class for DeviceHandler objects
62 """
63
65 """
66 @param device: An elementtree.Element instance of a device element in
67 a WURFL xml file.
68 @type device: elementtree.Element
69 """
70
71 self.devua = device.attrib["user_agent"]
72 self.devid = device.attrib["id"]
73 self.parent = device.attrib["fall_back"]
74 if ("actual_device_root" in device.attrib and
75 device.attrib['actual_device_root'].lower() == "true"):
76 self.actual_device_root = True
77 else:
78 self.actual_device_root = False
79 self.capabilities = {}
80
81
83 """
84 WURFL Processing Class
85 """
86
87 - def __init__(self, wurflxml, device_handler=None, options=None):
88 """
89 @param wurflxml: A filename of the WURFL.xml file to process. The
90 filename can be a regular, zip, bzip2 or gzipped file.
91 @type wurflxml: string
92 @param device_handler: A reference to a subclass of DeviceHandler.
93 @type device_handler: DeviceHandler
94 @param options: A dictionary of additional user specified options.
95 @type options: dict
96 """
97 self.wurflxml = wurflxml
98 if wurflxml.endswith(".gz"):
99 import gzip
100 file_handle = gzip.open(wurflxml, "rb")
101 elif wurflxml.endswith(".bz2"):
102 from bz2 import BZ2File
103 file_handle = BZ2File(wurflxml)
104 elif wurflxml.endswith(".zip"):
105 from zipfile import ZipFile
106 from cStringIO import StringIO
107 zipfile = ZipFile(wurflxml)
108 file_handle = StringIO(zipfile.read(zipfile.namelist()[0]))
109 else:
110 file_handle = file(wurflxml,"rb")
111 self.file_handle = file_handle
112
113 self.tree = parse(self.file_handle)
114 self.root = self.tree.getroot()
115
116 if options is not None:
117 for key in options:
118 self.__setattr__(key, options[key])
119
120 self.process_options()
121
122 self.device_handler = device_handler
123 self.deferred = {}
124 self.deferred_len = 0
125 self.done = {}
126
128 """
129 Hook called to process any additional options.
130 """
131 pass
132
134 """
135 Hook called in before any processing is done.
136 """
137 pass
138
140 """
141 Hook called when processing is done.
142 """
143 pass
144
146 """
147 Hook called to handle a device.
148
149 This hook is called when all of the capabilities of a device have been
150 processed and its fall_back has already been processed.
151 """
152 pass
153
155 """
156 Hook called to handle deferred device objects.
157
158 This hook is called to process any deferred devices (devices that have
159 been defined in the WURFL before their fall_back has been defined). It
160 is called after any device has been handled and also called in a loop
161 after all device definitions in the WURFL have been exhausted.
162 """
163 todel = []
164 for parent in self.deferred:
165 if parent in self.done:
166 for devobj in self.deferred[parent]:
167 self.done[devobj.devid] = devobj
168 self.handle_device(devobj)
169 todel.append(parent)
170 for handled_device in todel:
171 del(self.deferred[handled_device])
172
174 """
175 Hook called after a new device object has been instantiated.
176 """
177 pass
178
180 """
181 Hook called when a new WURFL group is encountered.
182 """
183 pass
184
186 """
187 Hook called when a new WURFL capability is encountered.
188 """
189 pass
190
192 """
193 Hook called when a device is initially deferred.
194 """
195 pass
196
198 """
199 Main WURFL processing method.
200 """
201
202 self.deferred = {}
203 self.done = {}
204
205 self.start_process()
206
207 for device in self.root.find("devices"):
208 if self.device_handler:
209 devobj = self.device_handler(device)
210 else:
211 devobj = None
212 self.process_device(devobj)
213 for group in device:
214 self.process_group(devobj, group)
215 for capability in group:
216 self.process_capability(devobj, group, capability)
217 if devobj:
218 if devobj.parent != "root" and (devobj.parent not in self.done):
219 if devobj.parent not in self.deferred:
220 self.deferred[devobj.parent] = []
221 self.deferred[devobj.parent].append(devobj)
222 self.process_new_deferred(devobj)
223 else:
224 self.done[devobj.devid] = devobj
225 self.handle_device(devobj)
226 self.process_deferred()
227 try:
228 while self.deferred:
229 deferred_len = len(self.deferred)
230 self.process_deferred()
231 if deferred_len == len(self.deferred):
232 raise DeferredDeviceError("%s devices still deferred: %s" %
233 (deferred_len,
234 self.deferred.keys()))
235 finally:
236 self.end_process()
237
238
239 -def main(processor_class, device_handler_class, option_parser):
240 """
241 Main utility function
242
243 Function to help instantiate a WurflProcessor class or subclass with
244 additional command line options.
245
246 @param processor_class: The WurflProcessor class or a subclass.
247 @type processor_class: WurflProcessor
248 @param device_handler_class: A reference to a subclass of DeviceHandler.
249 @type device_handler_class: DeviceHandler
250 @param option_parser: An instance of OptionParser. The dictionary from
251 this object will be passed to processor_class in
252 the keyword 'option'.
253 @type option_parser: OptionParser.OptionParser
254 """
255 options, args = option_parser.parse_args()
256
257 if args:
258 wurflxml = args[0]
259 else:
260 print >> sys.stderr, op.get_usage()
261 sys.exit(1)
262
263 wurfl = processor_class(wurflxml, device_handler=device_handler_class,
264 options=options.__dict__)
265 wurfl.process()
266
267
268 usage = "usage: %prog [options] WURFL_XML_FILE"
269 op = OptionParser(usage=usage)
270 op.add_option("-l", "--logfile", dest="logfile", default=sys.stderr,
271 help="where to write log messages")
272
273
274 if __name__ == "__main__":
275 main(WurflProcessor, None, op)
276