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-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