pywurfl.wurflprocessor

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