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