Package pywurfl :: Module wurflprocessor
[hide private]
[frames] | no frames]

Source Code for Module pywurfl.wurflprocessor

  1  # WURFL Processor - Wireless Universal Resource File Processor in Python 
  2  # Copyright (C) 2004-2011 Armand Lynch 
  3  # 
  4  # This library is free software; you can redistribute it and/or modify it 
  5  # under the terms of the GNU Lesser General Public License as published by the 
  6  # Free Software Foundation; either version 2.1 of the License, or (at your 
  7  # option) any later version. 
  8  # 
  9  # This library is distributed in the hope that it will be useful, but WITHOUT 
 10  # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
 11  # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 
 12  # details. 
 13  # 
 14  # You should have received a copy of the GNU Lesser General Public License 
 15  # along with this library; if not, write to the Free Software Foundation, Inc., 
 16  # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
 17  # 
 18  # Armand Lynch <lyncha@users.sourceforge.net> 
 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-2011, Armand Lynch" 
 36  __license__ = "LGPL" 
 37  __url__ = "http://celljam.net/" 
 38  __all__ = ['DeferredDeviceError', 'DeviceHandler', 'WurflProcessor', 'main', 
 39             'op'] 
 40   
 41   
42 -class DeferredDeviceError(WURFLException):
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
52 -class DeviceHandler(object):
53 """ 54 Base class for DeviceHandler objects 55 """ 56
57 - def __init__(self, device):
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
75 -class WurflProcessor(object):
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
120 - def process_options(self):
121 """ 122 Hook called to process any additional options. 123 """ 124 pass
125
126 - def start_process(self):
127 """ 128 Hook called in before any processing is done. 129 """ 130 pass
131
132 - def end_process(self):
133 """ 134 Hook called when processing is done. 135 """ 136 pass
137
138 - def handle_device(self, devobj):
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
147 - def process_deferred(self):
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
166 - def process_device(self, devobj):
167 """ 168 Hook called after a new device object has been instantiated. 169 """ 170 pass
171
172 - def process_group(self, devobj, group):
173 """ 174 Hook called when a new WURFL group is encountered. 175 """ 176 pass
177
178 - def process_capability(self, devobj, group, capability):
179 """ 180 Hook called when a new WURFL capability is encountered. 181 """ 182 pass
183
184 - def process_new_deferred(self, devobj):
185 """ 186 Hook called when a device is initially deferred. 187 """ 188 pass
189
190 - def process(self):
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