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-2008 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   
 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   
49 -class DeferredDeviceError(WURFLException):
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
59 -class DeviceHandler(object):
60 """ 61 Base class for DeviceHandler objects 62 """ 63
64 - def __init__(self, device):
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
82 -class WurflProcessor(object):
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
127 - def process_options(self):
128 """ 129 Hook called to process any additional options. 130 """ 131 pass
132
133 - def start_process(self):
134 """ 135 Hook called in before any processing is done. 136 """ 137 pass
138
139 - def end_process(self):
140 """ 141 Hook called when processing is done. 142 """ 143 pass
144
145 - def handle_device(self, devobj):
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
154 - def process_deferred(self):
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
173 - def process_device(self, devobj):
174 """ 175 Hook called after a new device object has been instantiated. 176 """ 177 pass
178
179 - def process_group(self, devobj, group):
180 """ 181 Hook called when a new WURFL group is encountered. 182 """ 183 pass
184
185 - def process_capability(self, devobj, group, capability):
186 """ 187 Hook called when a new WURFL capability is encountered. 188 """ 189 pass
190
191 - def process_new_deferred(self, devobj):
192 """ 193 Hook called when a device is initially deferred. 194 """ 195 pass
196
197 - def process(self):
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