Author: duncan
Date: Tue Sep 25 12:58:53 2007
New Revision: 9900

Log:
The real files


Added:
   branches/rel-1/freevo/src/plugins/oneclick.py   (contents, props changed)
   branches/rel-1/freevo/src/plugins/weatherdata.py   (contents, props changed)

Added: branches/rel-1/freevo/src/plugins/oneclick.py
==============================================================================
--- (empty file)
+++ branches/rel-1/freevo/src/plugins/oneclick.py       Tue Sep 25 12:58:53 2007
@@ -0,0 +1,1096 @@
+# -*- coding: iso-8859-1 -*-
+# -----------------------------------------------------------------------
+# oneclick.py - a plugin to obtain detailed weather forecast information
+# -----------------------------------------------------------------------
+# $Id$
+#
+# Notes:
+#
+# Todo:
+#   X pull down weather on demand MENU_SELECT (need to fix popup behavior)
+#   X Ability to specify custom location name in ONECLICK_LOCATIONS
+#   - get location name back onto details screen
+#   - i18n support
+#   - a freevo helper to grab weather data behind the scenes
+#
+# activate:
+#
+#    plugin.activate('oneclick', level=45)
+#    ONECLICK_LOCATIONS = [ ("USNC0559", "", "Home sweet home", 0) ]
+#
+# -----------------------------------------------------------------------
+# Freevo - A Home Theater PC framework
+# Copyright (C) 2003 Krister Lagerstrom, et al.
+# Please see the file freevo/Docs/CREDITS for a complete list of authors.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# -----------------------------------------------------------------------
+
+#python modules
+import os, stat, re, copy
+import sys
+
+# date/time
+import time
+
+#regular expression
+import re
+
+# rdf modules
+from xml.dom.ext.reader import Sax2
+import urllib, urllib2
+
+import cElementTree as ET
+
+#freevo modules
+import config, menu, rc, plugin, skin, osd, util
+from gui.PopupBox import PopupBox
+from item import Item
+
+from weatherdata import WeatherData
+
+GUI = True
+if __name__ == '__main__':
+    GUI = False
+
+#get the singletons so we get skin info and access the osd
+skin = skin.get_singleton()
+osd = osd.get_singleton()
+
+#check every 1 hour
+WEATHER_AGE = 3600
+WEATHER_AGE = 3600 * 24
+WEATHER_DIR = os.path.join(config.SHARE_DIR, 'images', 'weather')
+WEATHER_DIR = '/sources/svn/freevo-1.x/testing/Duncan/weather/1click/images'
+
+#FIXME Not sure that all of these are correctly named
+WEATHER_ICONS = {
+#  icon      twc.com      image               fallback
+     '0': ( 'twc/0.png', 'thunderstorm.png', 'thunshowers.png'),
+     '1': ( 'twc/1.png', 'thunderstorm.png', 'thunshowers.png'),
+     '2': ( 'twc/2.png', 'thunderstorm.png', 'thunshowers.png'),
+     '3': ( 'twc/3.png', 'thunderstorm.png', 'thunshowers.png'),
+     '4': ( 'twc/4.png', 'thunderstorm.png', 'thunshowers.png'),
+     '5': ( 'twc/5.png', 'sleet.png', 'rainsnow.png'),
+     '6': ( 'twc/6.png', 'hail.png', 'rainsnow.png'),
+     '7': ( 'twc/7.png', 'mixed.png', 'rainsnow.png'),
+     '8': ( 'twc/8.png', 'freezingfog.png', 'fog.png'),
+     '9': ( 'twc/9.png', 'drizzle.png', 'fog.png'),
+    '10': ('twc/10.png', 'freezingrain.png', 'rainsnow.png'),
+    '11': ('twc/11.png', 'lightrain.png', 'lshowers.png'),
+    '12': ('twc/12.png', 'rain.png', 'showers.png'),
+    '13': ('twc/13.png', 'lightsnowshowers.png', 'flurries.png'),
+    '14': ('twc/14.png', 'mediumsnowshowers.png', 'flurries.png'),
+    '15': ('twc/15.png', 'freshsnow.png', 'flurries.png'),
+    '16': ('twc/16.png', 'snow.png', 'flurries.png'),
+    '17': ('twc/17.png', 'thunderstorm.png', 'thunshowers.png'),
+    '18': ('twc/18.png', 'drizzle.png', 'showers.png'),
+    '19': ('twc/19.png', 'dust.png', 'fog.png'),
+    '20': ('twc/20.png', 'mist.png', 'fog.png'),
+    '21': ('twc/21.png', 'haze.png', 'fog.png'),
+    '22': ('twc/22.png', 'smoke.png', 'fog.png'),
+    '23': ('twc/23.png', 'windy.png', 'pcloudy.png'),
+    '24': ('twc/24.png', 'windy.png', 'pcloudy.png'),
+    '25': ('twc/25.png', 'freezing.png', 'pcloudy.png'),
+    '26': ('twc/26.png', 'cloudy-n.png', 'pcloudy.png'),
+    '27': ('twc/27.png', 'mostlycloudy-n.png', 'mcloudy.png'),
+    '28': ('twc/28.png', 'mostlycloudy.png', 'mcloudy.png'),
+    '29': ('twc/29.png', 'partlycloudy-n.png', 'pcloudy.png'),
+    '30': ('twc/30.png', 'partlycloudy.png', 'pcloudy.png'),
+    '31': ('twc/31.png', 'clear-n.png', 'sunny.png'),
+    '32': ('twc/32.png', 'sunny.png', 'sunny.png'),
+    '33': ('twc/33.png', 'mostlyclear.png', 'sunny.png'),
+    '34': ('twc/34.png', 'mostlysunny.png', 'sunny.png'),
+    '35': ('twc/35.png', 'thunderstorm.png', 'thunshowers.png'),
+    '36': ('twc/36.png', 'hotandsunny.png', 'sunny.png'),
+    '37': ('twc/37.png', 'isolatedthunderstorms.png', 'thunshowers.png'),
+    '38': ('twc/38.png', 'scatteredthunderstorms.png', 'thunshowers.png'),
+    '39': ('twc/39.png', 'sunnyintervals.png', 'showers.png'),
+    '40': ('twc/40.png', 'heavyrain.png', 'showers.png'),
+    '41': ('twc/41.png', 'snowshowers.png', 'snowshow.png'),
+    '42': ('twc/42.png', 'snow.png', 'rainsnow.png'),
+    '43': ('twc/43.png', 'snow.png', 'rainsnow.png'),
+    '44': ('twc/44.png', 'na.png', 'unknown.png'),
+    '45': ('twc/45.png', 'rainshowers-n.png', 'rainsnow.png'),
+    '46': ('twc/46.png', 'snowshowers-n.png', 'snowshow.png'),
+    '47': ('twc/47.png', 'scatteredthunderstorms-n.png', 'thunshowers.png'),
+    'na': ('twc/na.png', 'na.png', 'unknown.png'),
+}
+
+
+def wget(url):
+    ''' get a file from the url '''
+    _debug_('wget(%s)' % (url), 2)
+    txdata = None
+    txheaders = {
+        'User-Agent' : 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; 
rv:1.8.1.7) Gecko/20070914 Firefox/2.0.0.7'
+    }
+    req = urllib2.Request(url, txdata, txheaders)
+    try:
+        t1 = time.time()
+        response = urllib2.urlopen(req)
+        try:
+            data = response.read()
+        finally:
+            response.close()
+            t2 = time.time()
+        if response.msg == 'OK':
+            return data
+        _debug_('Downloaded "%s" in %.1f seconds' % (url, t2 - t1))
+    except urllib2.HTTPError, error:
+        print 'getting %r failed: %s' % (url, error)
+    except ValueError, error:
+        try:
+            fd = open(url)
+            data = fd.read()
+            fd.close()
+            return data
+        except:
+            print 'invalid url %r failed: %s' % (url, error)
+    return None
+
+
+def toCelcius(fTemp):
+    _debug_('toCelcius(fTemp)', 2)
+    try:
+        tTemp = float (fTemp )
+    except ValueError:
+        tTemp = 0.0
+    nTemp = (5.0/9.0)*(tTemp - 32.0)
+    return "%d" % (nTemp,)
+
+def toKilometers(miles):
+    _debug_('toKilometers(miles)', 2)
+    try:
+        tTemp = float(miles)
+    except ValueError:
+        tTemp = 0.0
+    nTemp = tTemp*1.6
+    return "%d" % (int(nTemp),)
+
+def toBarometer(baro):
+    _debug_('toBarometer(baro)', 2)
+    try:
+        tTemp = float(baro)
+    except ValueError:
+        tTemp = 0.0
+    nTemp = tTemp*3.386
+    return "%.1f" % (nTemp,)
+
+
+class PluginInterface(plugin.MainMenuPlugin):
+    '''
+    A plugin to obtain more detailed weather forecast information
+
+    To activate, put the following lines in local_conf.py:
+
+    plugin.activate('oneclick', level=45)
+    ONECLICK_LOCATIONS = [
+      ("<loc>", [metric], [mapuri], [location name]),
+      ("<loc>", [metric], [mapuri], [location name]),
+    ...
+    ]
+
+    where:
+    <loc> is a zipcode or an airport code
+    [metric] (1 == convert to SI Units; 0 == do not convert)
+    [mapuri] is the map's url, doesn't parse the page for a map url
+    [location name] is a custom name you wish to use for this location
+    '''
+    def __init__(self):
+        '''
+        '''
+        _debug_('PluginInterface.__init__()', 2)
+        if not hasattr(config, 'ONECLICK_LOCATIONS'):
+            self.reason = 'ONECLICK_LOCATIONS not defined'
+            return
+        plugin.MainMenuPlugin.__init__(self)
+
+    def config(self):
+        '''
+        '''
+        _debug_('config()', 2)
+        return [
+            ('ONECLICK_LOCATIONS', [('USNC0559', 0)], 'Location codes for 
current conditions and forecasts'),
+            ('ONECLICK_URL_CURC', 
'http://ff.1click.weather.com/weather/local/%s?cc=*%s', 'Current Conditions 
URL'),
+            ('ONECLICK_URL_DAYF', 
'http://ff.1click.weather.com/weather/local/%s?dayf=5%s', 'Day Forecast URL'),
+            ('ONECLICK_URL_ELOC', 
'http://ff.1click.weather.com/weather/local/%s?eloc=st', 'Extended Location 
URL'),
+            ('ONECLICK_URL_MAP',  
'http://www.weather.com/weather/map/%s?from=LAPmaps', 'Radar Map URL')
+        ]
+
+    def items(self, parent):
+        '''
+        '''
+        _debug_('items(self, parent)', 2)
+        return [ WeatherMainMenu(parent) ]
+
+
+class WeatherItem(Item):
+    '''
+    Item for the menu for one feed
+    '''
+    def __init__(self, parent, location):
+        _debug_('WeatherItem.__init__(parent=%r, location=%r)' % (parent, 
location), 2)
+        Item.__init__(self, parent)
+
+        self.parent = parent
+
+        # Flag to indicate whether this item is able to be displayed
+        self.error = 0
+
+        self.location = None
+        self.ismetric = False
+        self.name = None
+        self.city = None
+        self.state = None
+        self.tm = None
+        self.latitude = None
+        self.longitude = None
+        self.sunrise = None
+        self.sunset = None
+
+        self.unit_t = None
+        self.unit_d = None
+        self.unit_s = None
+        self.unit_p = None
+        self.unit_r = None
+        self.country = None
+
+        self.updated = 0.0
+        self.observation_station = None
+        self.temperature = None
+        self.feeling = None
+        self.current_conditions = None
+        self.icon = None
+        self.pressure = None
+        self.pressure_change = None
+        self.wind_speed = None
+        self.wind_direction = None
+        self.humidity = None
+        self.visibility = None
+        self.uv_index = None
+        self.uv_type = None
+        self.dew_point = None
+        self.moon_icon = None
+        self.moon_phase = None
+
+        self.description = None
+        self.forecastData = None
+        self.pastTime = 0
+        self.date = []
+        self.weatherIcon = []
+        self.highTemp = []
+        self.lowTemp = []
+        self.weatherType = []
+        self.wdata = []
+        self.popupParam = None
+        self.mapuri = None
+
+        if isinstance(location, tuple):
+            self.location = location[0]
+            if len(location) > 1:
+                self.ismetric = bool(location[1])
+            if len(location) > 2:
+                self.mapuri = str(location[2])
+            if len(location) > 3:
+                self.name = str(location[3])
+        else:
+            self.location = location
+            self.ismetric = False
+
+        self.popupParam = Unicode(self.location)
+        if self.name:
+            self.popupParam = Unicode(self.name)
+
+        self.units = self.ismetric and '&unit=m' or ''
+        self.url_curc = config.ONECLICK_URL_CURC % 
(urllib.quote(self.location), self.units)
+        self.url_dayf = config.ONECLICK_URL_DAYF % 
(urllib.quote(self.location), self.units)
+        self.url_eloc = config.ONECLICK_URL_ELOC % 
(urllib.quote(self.location))
+        self.mapurl = config.ONECLICK_URL_MAP % (self.location,)
+        self.weatherData = None
+        self.weatherMapData = None
+
+        self.cacheDir = '%s/weather_%s' % (config.FREEVO_CACHEDIR, 
self.location)
+        self.cacheElocation = '%s/location.pickle' % (self.cacheDir)
+        self.cacheCurrent = '%s/current.pickle' % (self.cacheDir)
+        self.cacheForecast = '%s/forecast.pickle' % (self.cacheDir)
+        self.mapFile = '%s/map.jpeg' % (self.cacheDir)
+        self.mapPage1 = '%s/mappage1.html' % (self.cacheDir)
+        self.mapPage2 = '%s/mappage2.html' % (self.cacheDir)
+        if not os.path.isdir(self.cacheDir):
+            os.mkdir(self.cacheDir, 
stat.S_IMODE(os.stat(config.FREEVO_CACHEDIR)[stat.ST_MODE]))
+        self.last_update = 0
+
+        #get forecast data
+        self.getForecast()
+
+    def getForecast(self, force=0):
+        '''grab the forecast, updating for the website if needed'''
+        _debug_('getForecast(force=%s)' % (force), 2)
+
+        # check cache
+        try:
+            if force or self.needsRefresh():
+                self.updateData()
+                self.updateMap()
+            else:
+                self.loadFromCache()
+        except IOError, e:
+            self.error = 1
+            print "failed to update data for '%s': %s" % (self.location, e)
+        else:
+            # set the last update timestamp
+            self.last_update = os.path.getmtime(self.cacheCurrent)
+
+            # now convert the self.weatherData structure to parsable 
information
+            self.convertWeatherData()
+            try:
+                self.convertWeatherData()
+            except Exception, error:
+                print 'Failed to convert data for %s: %s' % (self.location, 
error)
+
+
+    def needsRefresh(self):
+        '''is the cache too old?'''
+        _debug_('needsRefresh()', 2)
+        if (os.path.isfile(self.cacheCurrent) == 0 or \
+            (abs(time.time() - os.path.getmtime(self.cacheCurrent)) > 
WEATHER_AGE)):
+            return 1
+        else:
+            return 0
+
+    def updateData(self):
+        '''update the cache data from the 1click service
+        @notes the elocation is not updated as it is static
+        '''
+        _debug_('updateData()', 2)
+        if GUI:
+            popup = PopupBox(text=_('Fetching Weather for %s...') % 
self.popupParam)
+            popup.show()
+
+        if not os.path.isfile(self.cacheElocation):
+            try:
+                elocationData = wget(self.url_eloc)
+                self.elocationData = elocationData
+            except Exception, error:
+                print 'Failed to get extended location data for %s: %s' % 
(self.location, error)
+        else:
+            self.elocationData = util.read_pickle(self.cacheElocation)
+
+        try:
+            self.currentData = wget(self.url_curc)
+            #print 'currentData:', self.currentData
+        except Exception, error:
+            print 'Failed to get the current conditions data for %s: %s' % 
(self.location, error)
+            if os.path.isfile(self.cacheCurrent):
+                self.currentData = util.read_pickle(self.cacheCurrent)
+            else:
+                self.currentData = None
+        try:
+            self.forecastData = wget(self.url_dayf)
+            #print 'forecastData:', self.forecastData
+        except Exception, error:
+            print 'Failed to get the forecast data for %s: %s' % 
(self.location, error)
+            if os.path.isfile(self.cacheForecast):
+                self.forecastData = util.read_pickle(self.cacheForecast)
+            else:
+                self.forecastData = None
+
+        if GUI:
+            popup.destroy()
+
+        if not self.currentData or not self.forecastData:
+            # raise an error
+            return
+
+        self.saveToCache()
+        return
+
+
+    def updateMap(self):
+        ''' Update the weather map '''
+        _debug_('updateMap()', 2)
+        # obtain radar map
+        if self.mapuri:
+            try:
+                if GUI:
+                    popup = PopupBox(text=_('Fetching Radar Map for %s...') % 
self.popupParam)
+                    popup.show()
+                try:
+                    self.weatherMapData = wget(self.mapuri)
+                    self.saveMapToCache()
+                except Exception, error:
+                    print 'Cannot download the map for "%s" from %s: %s' % 
(self.location, self.mapuri, error)
+                return
+            finally:
+                if GUI:
+                    popup.destroy()
+
+        try:
+            if GUI:
+                popup = PopupBox(text=_('Fetching Radar Map for %s...') % 
self.popupParam)
+                popup.show()
+            # get the first web page
+            weatherPage = wget(self.mapurl)
+            if config.DEBUG:
+                f = open(self.mapPage1, 'w')
+                f.write(weatherPage)
+                f.close()
+            try:
+                # find link to map page
+                regexp = re.compile ('if \(isMinNS4\) var mapNURL = 
"([^"]*)";', re.IGNORECASE)
+                results = regexp.search(weatherPage)
+                print 'weatherPage=%r' % (results.groups())
+                weatherPage2 = "http://www.weather.com/%s"; % 
(results.groups()[0])
+
+                mapPage = wget(weatherPage2)
+                if config.DEBUG:
+                    f = open(self.mapPage2, 'w')
+                    f.write(weatherPage)
+                    f.close()
+                # find a link to the real weather map
+                regexp = re.compile('<img NAME="mapImg" 
SRC="(http://image.weather.com[^"]*jpg)"', re.IGNORECASE)
+                results = regexp.search(mapPage)
+                print 'mapPage=%r' % (results.groups())
+                self.mapuri = results.groups()[0]
+                self.weatherMapData = wget(self.mapuri)
+                self.saveMapToCache()
+                return
+            except Exception, error:
+                print 'Cannot download the map for "%s" from %s: %s' % 
(self.location, self.mapurl, error)
+
+        finally:
+            if GUI:
+                popup.destroy()
+
+    def saveToCache(self):
+        _debug_('saveToCache()', 2)
+        util.save_pickle(self.elocationData, self.cacheElocation)
+        util.save_pickle(self.currentData, self.cacheCurrent)
+        util.save_pickle(self.forecastData, self.cacheForecast)
+
+    def saveMapToCache(self):
+        ''' save weather map to the cache '''
+        try:
+            if self.weatherMapData is not None:
+                imgfd = os.open(self.mapFile, os.O_CREAT|os.W_OK)
+                os.write(imgfd, self.weatherMapData)
+                os.close(imgfd)
+        except Exception, error:
+            print 'failed saving weather map to cache "%s": %s' % 
(self.mapFile, error)
+
+    def loadFromCache(self):
+        ''' load the data and the map from the cache '''
+        _debug_('loadFromCache()', 2)
+        self.elocationData = util.read_pickle(self.cacheElocation)
+        self.currentData = util.read_pickle(self.cacheCurrent)
+        self.forecastData = util.read_pickle(self.cacheForecast)
+
+        try:
+            size = int(os.stat(self.mapFile)[6])
+        except Exception, error:
+            _debug_('failed loading weather map for "%s" from cache: %s' % 
(self.location, error), config.DWARNING)
+            pass
+        else:
+            imgfd = os.open(self.mapFile, os.R_OK)
+            self.weatherMapData = os.read(imgfd, size)
+            os.close(imgfd)
+
+    def actions(self):
+        ''' return a list of actions for this item '''
+        _debug_('actions()', 2)
+        return [ (self.start_detailed_interface, _('Show Weather Details')) ]
+
+    def start_detailed_interface(self, arg=None, menuw=None):
+        ''' detail handler '''
+        _debug_('start_detailed_interface(arg=%r, menuw=%r)' % (arg, menuw), 2)
+        WeatherDetailHandler(arg, menuw, self)
+
+    def isValid(self):
+        ''' reports is an error was detected '''
+        _debug_('isValid()', 2)
+        return not self.error
+
+    def getLastUpdated(self):
+        ''' parse the lsup time
+        @notes there seems to be a problem with AM/PM not parsing correctly
+        '''
+        _debug_('getLastUpdated() "%s"' % self.updated, 2)
+        try:
+            value = time.strptime(self.updated.replace(' AM Local Time', ''), 
'%m/%d/%y %H:%M')
+            return time.strftime("%c", time.localtime(time.mktime(value)))
+        except ValueError, e:
+            try:
+                value = time.strptime(self.updated.replace(' PM Local Time', 
''), '%m/%d/%y %H:%M')
+                (year, mon, day, hour, min, sec, weekday, yearday, saving) = 
value
+                value = (year, mon, day, hour+12, min, sec, weekday, yearday, 
saving)
+                return time.strftime("%c", time.localtime(time.mktime(value)))
+            except ValueError, error:
+                print error
+                return self.updated.replace(' Local Time', '')
+        #if self.ismetric:
+        #    return time.strftime("%d/%m/%Y %H:%M:%S", 
time.localtime(self.updated))
+        #else:
+        #    return time.strftime("%m/%d/%Y %I:%M:%S %p", 
time.localtime(self.updated))
+
+    def getObservationStation(self):
+        ''' get the observation station '''
+        _debug_('getObservationStation()', 2)
+        return "%s" % (self.observation_station)
+
+    def getTemperature(self):
+        _debug_('getTemperature()', 2)
+        return u"%s\xb0%s" % (self.temperature, self.unit_t)
+
+    def getFeeling(self):
+        _debug_('getFeeling()', 2)
+        return u"%s\xb0%s" % (self.feeling, self.unit_t)
+
+    def getCurrentCondition(self):
+        ''' gets the current conditions '''
+        _debug_('getCurrentCondition()', 2)
+        return "%s" % (self.current_conditions)
+
+    def getIcon(self):
+        ''' gets the current conditions icon '''
+        _debug_('getIcon()', 2)
+        return "%s" % (self.icon)
+
+    def getPressure(self):
+        _debug_('getPressure()', 2)
+        if self.pressure_change == 'N/A':
+            return "%s %s" % (self.pressure, self.unit_p)
+        return "%s %s %s %s" % (self.pressure, self.unit_p, _('and'), 
self.pressure_change)
+
+    def getPressureValue(self):
+        _debug_('getPressureValue()', 2)
+        return "%s %s" % (self.pressure, self.unit_p)
+
+    def getPressureChange(self):
+        _debug_('getPressureChange()', 2)
+        return "%s" % (self.pressure_change)
+
+    def getWind(self):
+        _debug_('getWind()', 2)
+        if self.wind_direction == 'CALM':
+            return "%s" % (self.wind_speed)
+        elif self.wind_direction == 'VAR':
+            return "%s %s %s %s" % (_('Variable'), _('at'), self.wind_speed, 
self.unit_s)
+        return "%s %s %s %s" % (self.wind_direction, _('at'), self.wind_speed, 
self.unit_s)
+
+    def getWindDir(self):
+        _debug_('getWindDir()', 2)
+        return "%s" % (self.wind_direction)
+
+    def getWindSpeed(self):
+        _debug_('getWindSpeed()', 2)
+        return "%s %s" % (self.wind_speed, self.unit_s)
+
+    def getHumidity(self):
+        _debug_('getHumidity()', 2)
+        return "%s%%" % (self.humidity)
+
+    def getVisibility(self):
+        _debug_('getVisibility()', 2)
+        return "%s %s" % (self.visibility, self.unit_d)
+
+    def getUvIndex(self):
+        _debug_('getUvIndex()', 2)
+        return "%s" % (self.uv_index)
+
+    def getUvType(self):
+        _debug_('getUvType()', 2)
+        return "%s" % (self.uv_type)
+
+    def getDewPoint(self):
+        _debug_('getDewPoint()', 2)
+        return u"%s\xb0%s" % (self.dew_point, self.unit_t)
+
+    def getMoonIcon(self):
+        _debug_('getMoonIcon()', 2)
+        return "%s" % (self.moon_icon)
+
+    def getMoonPhase(self):
+        _debug_('getMoonPhase()', 2)
+        return "%s" % (self.moon_phase)
+
+    def getSunrise(self):
+        _debug_('getSunrise()', 2)
+        return "%s" % (self.sunrise)
+
+    def getSunset(self):
+        _debug_('getSunset()', 2)
+        return "%s" % (self.sunset)
+
+
+    def convertWeatherData(self):
+        '''
+        convert the xml weather information for the skin
+        '''
+        _debug_('convertWeatherData()', 2)
+        #print self.elocationData
+        #print self.currentData
+        #print self.forecastData
+        elocation = WeatherData(ET.XML(self.elocationData))
+        current = WeatherData(ET.XML(self.currentData))
+        forecast = WeatherData(ET.XML(self.forecastData))
+
+        if not self.name:
+            self.name = elocation.loc.dnam
+
+        dnam = elocation.loc.dnam.split(', ')
+        ctry = elocation.eloc.ctry
+        if ctry in ('US'):
+            self.city = dnam[0]
+            self.state = dnam[1]
+            self.country = ctry
+        else:
+            self.city = dnam[0]
+            self.state = ''
+            self.country = dnam[1]
+        print 'city=%s, state=%s, country=%s' % (self.city, self.state, 
self.country)
+
+        # reset variables
+        self.date = []
+        self.weatherIcon = []
+        self.highTemp = []
+        self.lowTemp = []
+        self.weatherType = []
+
+        self.unit_t = current.head.ut
+        self.unit_d = current.head.ud
+        self.unit_s = current.head.us
+        self.unit_p = current.head.up
+        self.unit_r = current.head.ur
+
+        self.tm = current.loc.tm
+        self.latitude = current.loc.lat
+        self.longitude = current.loc.lon
+        self.sunrise = current.loc.sunr
+        self.sunset = current.loc.suns
+        self.zone = current.loc.zone
+
+        self.updated = current.cc.lsup
+        self.observation_station = current.cc.obst
+        self.temperature = current.cc.tmp
+        self.feeling = current.cc.flik
+        self.current_conditions = current.cc.t
+        self.icon = current.cc.icon
+        self.pressure = current.cc.bar.r
+        self.pressure_change = current.cc.bar.d
+        self.wind_speed = current.cc.wind.s
+        self.wind_direction = current.cc.wind.t
+        self.humidity = current.cc.hmid
+        self.visibility = current.cc.vis
+        self.uv_index = current.cc.uv.i
+        self.uv_type = current.cc.uv.t
+        self.dew_point = current.cc.dewp
+        self.moon_icon = current.cc.moon.icon
+        self.moon_phase = current.cc.moon.t
+
+        self.description = '%s %s %s' % (self.current_conditions, _("at"), 
self.getTemperature())
+        self.image = self.getDayImage(self.icon)
+
+        # skip today in the days
+        for day in forecast.dayf.days[1:]:
+            self.date.append(day.t)
+            self.highTemp.append(day.hi)
+            self.lowTemp.append(day.low)
+            for part in day.parts:
+                if part.p == 'd':
+                    self.weatherIcon.append(self.getDayImage(part.icon))
+                    self.weatherType.append(part.t)
+
+
+    def getDayImage(self, num):
+        '''obtain the weather icons for multiple day forecast'''
+        _debug_('getDayImage()', 2)
+
+        icon = os.path.join(WEATHER_DIR, WEATHER_ICONS[num][1])
+        if not os.path.isfile(icon):
+            icon = os.path.join(WEATHER_DIR, WEATHER_ICONS[num][2])
+            if not os.path.isfile(icon):
+                icon = os.path.join(WEATHER_DIR, WEATHER_ICONS[num][0])
+        if not os.path.isfile(icon):
+            icon = os.path.join(WEATHER_DIR, 'na.png')
+        print '%s: %s %s' % (num, icon, 
os.path.split(WEATHER_ICONS[num][1])[1])
+        return icon
+
+
+    def getMoonImage(self, num):
+        '''obtain the weather icons for multiple day forecast'''
+        _debug_('getMoonImage()', 2)
+
+        icon = os.path.join(WEATHER_DIR, 'moons', '%s.png' % (num))
+        print '%s: %s' % (num, icon)
+        return icon
+
+
+class WeatherMainMenu(Item):
+    '''
+    this is the item for the main menu and creates the list
+    of Weather Locations in a submenu.
+    '''
+    def __init__(self, parent):
+        _debug_('WeatherMainMenu.__init__(parent=%r)' % (parent), 2)
+        Item.__init__(self, parent, skin_type='oneclick')
+        self.parent = parent
+        self.name = _('Weather')
+
+    def actions(self):
+        ''' return a list of actions for this item '''
+        _debug_('actions()', 2)
+        items = [ (self.create_locations_menu , _('Locations')) ]
+        return items
+
+    def __call__(self, arg=None, menuw=None):
+        ''' call first action in the actions list '''
+        _debug_('__call__(arg=%r, menuw=%r)' % (arg, menuw), 2)
+        if self.actions():
+            return self.actions()[0][0](arg=arg, menuw=menuw)
+
+    def create_locations_menu(self, arg=None, menuw=None):
+        ''' '''
+        _debug_('create_locations_menu(arg=%r, menuw=%r)' % (arg, menuw), 2)
+        locations = []
+        autoselect = 0
+        # create menu items
+        for location in config.ONECLICK_LOCATIONS:
+            weather_item = WeatherItem(self, location)
+            # Only display this entry if no errors were found
+            if weather_item.isValid():
+                locations.append (weather_item)
+
+        # if only 1 valid location, autoselect it and go right to the detail 
screen
+        if locations.__len__() == 1:
+            autoselect = 1
+            menuw.hide(clear=False)
+
+        # if no locations were found, add a menu entry indicating that
+        if not locations:
+            nolocation = menu.MenuItem(_('No locations specified'), 
menuw.goto_prev_page, 0)
+            locations.append(nolocation)
+
+        # if only 1 valid menu entry present, autoselect it
+        if autoselect:
+            locations[0](menuw=menuw)
+        else:
+            # create menu
+            weather_site_menu = menu.Menu(_('Locations'), locations)
+            menuw.pushmenu(weather_site_menu)
+            menuw.refresh()
+
+class WeatherDetailHandler:
+    '''
+    A handler class to display several detailed forecast screens and catch 
events
+    '''
+    def __init__(self, arg=None, menu=None, weather=None):
+        ''' '''
+        _debug_('WeatherDetailHandler.__init__(arg=%r, menu=%r, weather=%r)' % 
(arg, menu, weather), 2)
+        self.arg = arg
+        self.menuw = menu
+        self.weather = weather
+        self.menuw.hide(clear=False)
+        rc.app(self)
+
+        self.skins = ('day', 'forecast', 'week', 'map')
+
+        self.skin_num = 0
+        self.subtitles = (_('Current Conditions'), _('Today\'s Forecast'),
+                          _('Extended Forecast'), _('Radar Map'))
+
+        self.title = ''
+        self.subtitle = self.getSubtitle(self.skin_num)
+
+        # Fire up splashscreen and load the plugins
+        skin.draw('oneclick', self)
+
+    def prevSkin(self):
+        '''decrements the skin number round to the last skin'''
+        _debug_('prevSkin()', 2)
+        self.skin_num -= 1
+
+        # out of bounds check, reset to size of skins array
+        if self.skin_num < 0:
+            self.skin_num = len(self.skins)-1
+        self.subtitle = self.getSubtitle(self.skin_num)
+
+    def nextSkin(self):
+        '''increment the skin number round to the first skin'''
+        _debug_('nextSkin()', 2)
+        self.skin_num += 1
+
+        # out of bounds check, reset to 0
+        if self.skin_num >= len(self.skins):
+            self.skin_num = 0
+        self.subtitle = self.getSubtitle(self.skin_num)
+
+    def getSubtitle(self, num):
+        ''' returns the subtitle for a skin number '''
+        _debug_('getSubtitle(num=%s)' % (num), 2)
+        return '%s %s %s' % (self.subtitles[num], _('for'), self.weather.name)
+
+    def eventhandler(self, event, menuw=None):
+        '''eventhandler'''
+        _debug_('eventhandler(event=%s, menuw=%r)' % (event, menuw), 2)
+        if event == 'MENU_BACK_ONE_MENU':
+            rc.app(None)
+            self.menuw.show()
+            return True
+
+        elif event == 'MENU_SELECT':
+            self.weather.getForecast(force=1)
+            skin.clear()
+            skin.draw('oneclick', self)
+            return True
+
+        elif event in ('MENU_DOWN', 'MENU_RIGHT'):
+            self.nextSkin()
+            skin.draw('oneclick', self)
+            return True
+
+        elif event in ('MENU_UP', 'MENU_LEFT'):
+            self.prevSkin()
+            skin.draw('oneclick', self)
+            return True
+
+        return False
+
+if __name__ == '__main__':
+    for location in config.ONECLICK_LOCATIONS:
+        print location
+        weather_item = WeatherItem(None, location)
+        print weather_item
+    import sys
+    sys.exit(1)
+
+class WeatherBaseScreen(skin.Area):
+    ''' A base class for weather screens to inherit from, provides common 
members+methods '''
+    def __init__(self):
+        _debug_('WeatherBaseScreen.__init__()', 2)
+        skin.Area.__init__(self, 'content')
+
+        # Weather display fonts
+        self.key_font = skin.get_font('medium0')
+        self.val_font = skin.get_font('medium1')
+        self.small_font = skin.get_font('small0')
+        self.big_font = skin.get_font('huge0')
+
+        # set the multiplier to be used in all screen drawing
+        self.xmult = float(osd.width  - 
(config.OSD_OVERSCAN_LEFT+config.OSD_OVERSCAN_RIGHT)) / 800
+        self.ymult = float(osd.height - 
(config.OSD_OVERSCAN_TOP+config.OSD_OVERSCAN_BOTTOM)) / 600
+
+        self.update_functions = (self.update_day, self.update_forecast,
+                                 self.update_week, self.update_map)
+
+    def update_day(self):
+        '''
+        '''
+        _debug_('update_day()', 2)
+        # display data
+        text = _('Humidity')
+        value = self.parent.weather.getHumidity()
+
+        x_col1 = self.content.x + (50  * self.xmult)
+        x_col2 = self.content.x + (250 * self.xmult)
+        y_start = self.content.y + (60  * self.xmult)
+        y_inc = 40 * self.ymult
+
+        self.write_text(text, self.key_font, self.content,
+            x=x_col1, y=y_start, height=-1, align_h='left')
+        self.write_text(value, self.val_font, self.content,
+            x=x_col2, y=y_start, height=-1, align_h='left')
+
+        text = _('Pressure')
+        value = self.parent.weather.getPressure()
+        self.write_text(text, self.key_font, self.content,
+            x=x_col1, y=y_start+y_inc, height=-1, align_h='left')
+        self.write_text(value, self.val_font, self.content,
+            x=x_col2, y=y_start+y_inc, height=-1, align_h='left')
+
+        text = _('Wind')
+        value = '%s' % (self.parent.weather.getWind())
+        y_start   += y_inc
+        self.write_text(text, self.key_font, self.content,
+            x=x_col1, y=y_start+y_inc, height=-1, align_h='left')
+        self.write_text(value, self.val_font, self.content,
+            x=x_col2, y=y_start+y_inc, height=-1, align_h='left')
+
+        text = _('Wind Chill')
+        value = self.parent.weather.getFeeling()
+        y_start   += y_inc
+        self.write_text(text, self.key_font, self.content,
+            x=x_col1, y=y_start+y_inc, height=-1, align_h='left')
+        self.write_text(value, self.val_font, self.content,
+            x=x_col2, y=y_start+y_inc, height=-1, align_h='left')
+
+        text = _('Visibility')
+        value = self.parent.weather.getVisibility()
+        y_start   += y_inc
+        self.write_text(text, self.key_font, self.content,
+            x=x_col1, y=y_start+y_inc, height=-1, align_h='left')
+        self.write_text(value, self.val_font, self.content,
+            x=x_col2, y=y_start+y_inc, height=-1, align_h='left')
+
+        text = _('UV Index')
+        value = self.parent.weather.getUvType()
+        y_start   += y_inc
+        self.write_text(text, self.key_font, self.content,
+            x=x_col1, y=y_start+y_inc, height=-1, align_h='left')
+        self.write_text(value, self.val_font, self.content,
+            x=x_col2, y=y_start+y_inc, height=-1, align_h='left')
+
+        # draw current condition image
+        x_start = self.content.x + (450*self.xmult)
+        y_start = self.content.y + (40*self.ymult)
+        self.draw_image(self.parent.weather.image,
+            (x_start, y_start,
+              int(200*self.xmult), int(150*self.ymult)))
+
+        y_start = self.content.y + (200*self.ymult)
+        self.write_text(self.parent.weather.getCurrentCondition(),
+            self.key_font, self.content,
+            x=x_start, y=y_start,
+            width=200*self.xmult, height=-1, align_h='center')
+        y_start = self.content.y + (250*self.ymult)
+        self.write_text(self.parent.weather.getTemperature(),
+            self.big_font, self.content,
+            x=x_start, y=y_start,
+            width=200*self.xmult, height=-1, align_h='center')
+
+        x_start = self.content.x + (40*self.xmult)
+        y_start = self.content.y + (350*self.ymult)
+        self.write_text(self.parent.weather.getLastUpdated() ,
+            self.small_font, self.content,
+            x=x_start, y=y_start,
+            width=self.content.width, height=-1, align_h='left')
+
+
+    def update_forecast(self):
+        ''' this screen is taken from the 1click weather forecast of the 
firefox plug-in. '''
+        _debug_('update_forecast()', 2)
+        x_start = self.content.x + (20 * self.xmult)
+        y_start = self.content.y + (30 * self.xmult)
+        weather = self.parent.weather
+
+        lines = []
+        try:
+            lines.append('%s %s %s %s' %
+                (_('As of:'), weather.getLastUpdated(), _('in'), 
weather.getObservationStation()))
+            lines.append('  %s' % (weather.getCurrentCondition()))
+            lines.append('  %s %s' % (_('Temperature:'), 
weather.getTemperature()))
+            lines.append('  %s %s' % (_('Dew Point:'), weather.getDewPoint()))
+            lines.append('  %s %s' % (_('Humidity:'), weather.getHumidity()))
+            lines.append('  %s %s' % (_('Visibility:'), 
weather.getVisibility()))
+            lines.append('  %s %s' % (_('Pressure:'), weather.getPressure()))
+            lines.append('  %s %s' % (_('Winds:'), weather.getWind()))
+            lines.append('%s' % (_('Tonight:')))
+            lines.append('  %s %s' % (_('Sunset:'), weather.getSunset()))
+            lines.append('  %s %s' % (_('Moon Phase:'), 
weather.getMoonPhase()))
+        except Exception, error:
+            print error
+            import traceback, sys
+            output = apply(traceback.format_exception, sys.exc_info())
+            output = ''.join(output)
+            output = urllib.unquote(output)
+            print output
+
+        y = y_start
+        for line in lines:
+            self.write_text(line, self.key_font, self.content,
+            x=x_start, y=y, height=-1, align_h='left')
+            y += (30 * self.ymult)
+
+        try:
+            x_start = self.content.x + (500 * self.xmult)
+            y_start = self.content.y + (300 * self.ymult)
+            iconFile = weather.getMoonImage(weather.getMoonIcon())
+            #self.draw_image(iconFile,
+            #    (x_start, y_start, 90, 90))
+                #(x_start, y_start, int(60 * self.xmult), int(60 * 
self.ymult)))
+            print 'x_start=%s, y_start=%s, xmult=%s, ymult=%s' % (x_start, 
y_start, self.xmult, self.ymult)
+        except Exception, error:
+            print error
+
+
+    def update_week(self):
+        ''' update the weeks forecast
+        @remarks this can be improved
+        '''
+        _debug_('update_week()', 2)
+
+        x_start = self.content.x + (10  * self.xmult)
+        y_start = self.content.y + (10  * self.xmult)
+
+        day = 0
+        for x in (0, 180, 360, 540):
+
+            x2_start = x_start + (x *self.xmult)
+            y2_start = y_start
+
+            self.write_text(Unicode(self.parent.weather.date[day]),
+                self.key_font, self.content,
+                x=x2_start, y=y2_start,
+                width=150*self.xmult, height=-1, align_h='center')
+
+            iconFile = os.path.join(WEATHER_DIR, 
self.parent.weather.weatherIcon[day])
+            self.draw_image(iconFile,
+                (x2_start, y2_start + (50*self.ymult), int(160*self.xmult), 
int(120*self.ymult)))
+            self.write_text(self.parent.weather.weatherType[day],
+                self.small_font, self.content,
+                x=x2_start, y=y2_start + (200*self.ymult),
+                width=160*self.xmult, height=-1, align_h='center')
+            self.write_text(_("LO"),
+                self.val_font, self.content,
+                x=x2_start, y=y2_start + (260*self.ymult),
+                width=90*self.xmult, height=-1, align_h='center')
+            self.write_text(self.parent.weather.lowTemp[day],
+                self.key_font, self.content,
+                x=x2_start, y=y2_start + (300*self.ymult),
+                width=90*self.xmult, height=-1, align_h='center')
+            self.write_text(_("HI"),
+                self.val_font, self.content,
+                x=x2_start+(70*self.xmult), y=y2_start + (260*self.ymult),
+                width=90*self.xmult, height=-1, align_h='center')
+            self.write_text(self.parent.weather.highTemp[day],
+                self.key_font, self.content,
+                x=x2_start+(70*self.xmult), y=y2_start + (300*self.ymult),
+                width=90*self.xmult, height=-1, align_h='center')
+            day += 1
+
+    def update_map(self):
+        ''' update the contents of the skin's doppler weather map '''
+        _debug_('update_map()', 2)
+        if not self.parent.weather.weatherMapData:
+            x_start = self.content.x + (10 * self.xmult)
+            y_start = self.content.y + (10 * self.xmult)
+            self.write_text(_("Error encountered while trying to download 
weather map"),
+                self.key_font, self.content, x=x_start, y=y_start,
+                width=self.content.width, height=-1, align_h='left')
+        else:
+            self.draw_image(self.parent.weather.mapFile,
+                (self.content.x-3, self.content.y+14, self.content.width, 
self.content.height))
+
+    def update_content(self):
+        ''' update the contents of the skin '''
+        _debug_('update_content()', 2)
+        self.parent = self.menu
+        self.content = self.calc_geometry(self.layout.content, 
copy_object=True)
+        self.update_functions[self.menu.skin_num]()
+
+
+# create one instance of the WeatherType class
+skin.register ('oneclick', ('screen', 'subtitle', 'title', 'plugin', 
WeatherBaseScreen()))

Added: branches/rel-1/freevo/src/plugins/weatherdata.py
==============================================================================
--- (empty file)
+++ branches/rel-1/freevo/src/plugins/weatherdata.py    Tue Sep 25 12:58:53 2007
@@ -0,0 +1,460 @@
+#!/usr/bin/env python
+#
+# using Firefox 1click weather
+# wget 'http://ff.1click.weather.com/weather/local/SZXX0033?dayf=5&unit=m'
+# wget 'http://ff.1click.weather.com/weather/local/SZXX0033?cc=*&unit=m'
+
+import cElementTree as ET
+import cPickle, pickle
+from pprint import pprint
+
+
+class WeatherData:
+    """Main weather data class
+    """
+    def __init__(self, tree):
+        self.tree = tree
+        self.head = None
+        self.loc = None
+        self.eloc = None
+        self.cc = None
+        self.dayf = None
+        self.TREE = {
+            'head' : 'WeatherData.Head',
+            'loc'  : 'WeatherData.Loc',
+            'eloc' : 'WeatherData.Eloc',
+            'cc'   : 'WeatherData.Cc',
+            'dayf' : 'WeatherData.DayF',
+        }
+        parse(self)
+
+    def __str__(self):
+        return 'WeatherData'
+
+
+#391 lines
+    class Loc:
+        """ Location information
+        <loc id="SZXX0033">
+          <dnam>Zurich, Switzerland</dnam>
+          <tm>7:46 AM</tm>
+          <lat>47.38</lat>
+          <lon>8.54</lon>
+          <sunr>6:57 AM</sunr>
+          <suns>7:47 PM</suns>
+          <zone>2</zone>
+        </loc>
+        """
+        def __init__(self, tree):
+            self.tree = tree
+            self.id = None
+            self.dnam = None
+            self.tm = None
+            self.lat = None
+            self.lon = None
+            self.sunr = None
+            self.suns = None
+            self.zone = None
+            self.TREE = {
+                'dnam'    : 'dnam',
+                'tm'      : 'tm',
+                'lat'     : 'lat',
+                'lon'     : 'lon',
+                'sunr'    : 'sunr',
+                'suns'    : 'suns',
+                'zone'    : 'zone',
+            }
+            parse(self)
+
+
+        def __str__(self):
+            return 'Loc'
+
+    class Head:
+        """ Header information
+        <head>
+          <locale>en_US</locale>
+          <form>MEDIUM</form>
+          <ut>C</ut>
+          <ud>km</ud>
+          <us>km/h</us>
+          <up>mb</up>
+          <ur>mm</ur>
+        </head>
+        """
+
+        def __init__(self, tree):
+            self.tree = tree
+            self.locale = None
+            self.form = None
+            self.ut = None
+            self.ud = None
+            self.us = None
+            self.mb = None
+            self.mm = None
+            self.TREE = {
+                'locale' : 'locale',
+                'form'   : 'form',
+                'ut'     : 'ut',
+                'ud'     : 'ud',
+                'us'     : 'us',
+                'up'     : 'up',
+                'ur'     : 'ur',
+            }
+            parse(self)
+
+        def __str__(self):
+            return 'Head'
+
+
+    class Eloc:
+        """ Extended location
+        <eloc id="SZXX0033">
+          <dma>N/A</dma>
+          <rgn4>N/A</rgn4>
+          <rgn9>N/A</rgn9>
+          <st>*</st>
+          <ctry>SZ</ctry>
+          <zip>N/A</zip>
+        </eloc>
+        """
+        def __init__(self, tree):
+            self.tree = tree
+            self.id = None
+            self.dma = None
+            self.rgn4 = None
+            self.rgn9 = None
+            self.st = None
+            self.ctry = None
+            self.zip = None
+            self.TREE = {
+                'id' : 'id',
+                'dma' : 'dma',
+                'rgn4' : 'rgn4',
+                'rgn9' : 'rgn9',
+                'st' : 'st',
+                'ctry' : 'ctry',
+                'zip' : 'zip',
+            }
+            parse(self)
+
+        def __str__(self):
+            return 'Eloc'
+
+    class Cc:
+        """ Current conditions
+        <cc>
+          <lsup>9/11/07 7:20 AM Local Time</lsup>
+          <obst>Zurich, Switzerland</obst>
+          <tmp>9</tmp>
+          <flik>9</flik>
+          <t>Partly Cloudy</t>
+          <icon>30</icon>
+          <bar>
+          </bar>
+          <wind>
+          </wind>
+          <hmid>93</hmid>
+          <vis>10.0</vis>
+          <uv>
+          </uv>
+          <dewp>8</dewp>
+          <moon>
+          </moon>
+        </cc>
+        """
+        def __init__(self, tree):
+            self.tree = tree
+            self.lsup = None
+            self.obst = None
+            self.tmp = None
+            self.flik = None
+            self.t = None
+            self.icon = None
+            self.bar = None
+            self.wind = None
+            self.hmid = None
+            self.vis = None
+            self.uv = None
+            self.dewp = None
+            self.moon = None
+            self.TREE = {
+                'lsup' : 'lsup',
+                'obst' : 'obst',
+                'tmp' : 'tmp',
+                'flik' : 'flik',
+                't' : 't',
+                'icon' : 'icon',
+                'bar' : 'WeatherData.Bar',
+                'wind' : 'WeatherData.Wind',
+                'hmid' : 'hmid',
+                'vis' : 'vis',
+                'uv' : 'WeatherData.Uv',
+                'dewp' : 'dewp',
+                'moon' : 'WeatherData.Moon',
+            }
+            parse(self)
+
+        def __str__(self):
+            return 'Cc'
+
+
+    class Bar:
+        """
+        <bar>
+          <r>1020.0</r>
+          <d>rising</d>
+        </bar>
+        """
+        def __init__(self, tree):
+            self.tree = tree
+            self.r = None
+            self.d = None
+            self.TREE = {
+                'r' : 'r',
+                'd' : 'd',
+            }
+            parse(self)
+
+        def __str__(self):
+            return 'Bar'
+
+
+    class Uv:
+        """
+        <uv>
+          <i>0</i>
+          <t>Low</t>
+        </uv>
+        """
+        def __init__(self, tree):
+            self.tree = tree
+            self.i = None
+            self.t = None
+            self.TREE = {
+                'i' : 'i',
+                't' : 't',
+            }
+            parse(self)
+
+        def __str__(self):
+            return 'Uv'
+
+
+    class Moon:
+        """
+        <moon>
+          <icon>29</icon>
+          <t>New</t>
+        </moon>
+        """
+        def __init__(self, tree):
+            self.tree = tree
+            self.icon = None
+            self.t = None
+            self.TREE = {
+                'icon' : 'icon',
+                't' : 't',
+            }
+            parse(self)
+
+        def __str__(self):
+            return 'Moon'
+
+
+    class DayF:
+        """ Day forecast
+        <dayf>
+          <lsup>9/11/07 2:27 AM Local Time</lsup>
+          <day d="0" t="Tuesday" dt="Sep 11">
+          </day>
+        </dayf>
+        """
+        def __init__(self, tree):
+            self.tree = tree
+            self.lsup = None
+            self.day = None
+            self.TREE = {
+                'lsup' : 'lsup',
+                'day'  : 'WeatherData.Day',
+            }
+            parse(self)
+
+        def __str__(self):
+            return 'DayF'
+
+    class Day:
+        """ Day information
+        <day d="4" t="Saturday" dt="Sep 15">
+          <hi>19</hi>
+          <low>12</low>
+          <sunr>7:03 AM</sunr>
+          <suns>7:39 PM</suns>
+          <part p="d">
+          </part>
+        </day>
+        """
+        def __init__(self, tree):
+            self.tree = tree
+            self.d = None
+            self.t = None
+            self.dt = None
+            self.hi = None
+            self.low = None
+            self.sunr = None
+            self.suns = None
+            self.parts = None
+            self.TREE = {
+                'd' : 'd',
+                't' : 't',
+                'dt' : 'dt',
+                'hi' : 'hi',
+                'low' : 'low',
+                'sunr' : 'sunr',
+                'suns' : 'suns',
+                'part' : 'WeatherData.Part',
+            }
+            parse(self)
+
+        def __str__(self):
+            return 'Day'
+
+    class Part:
+        """ Part of a day information
+        <part p="n">
+          <icon>29</icon>
+          <t>Partly Cloudy</t>
+          <wind>
+          </wind>
+          <bt>P Cloudy</bt>
+          <ppcp>10</ppcp>
+          <hmid>82</hmid>
+        </part>
+        """
+        def __init__(self, tree):
+            self.tree = tree
+            self.p = None
+            self.icon = None
+            self.t = None
+            self.wind = None
+            self.bt = None
+            self.ppcp = None
+            self.hmid = None
+            self.TREE = {
+                'icon' : 'icon',
+                't' : 't',
+                'wind' : 'WeatherData.Wind',
+                'bt' : 'bt',
+                'ppcp' : 'ppcp',
+                'hmid' : 'hmid',
+            }
+            parse(self)
+
+        def __str__(self):
+            return 'Part'
+
+    class Wind:
+        """ Wind information
+        <wind>
+          <s>6</s>
+          <gust>N/A</gust>
+          <d>109</d>
+          <t>ESE</t>
+        </wind>
+        """
+        def __init__(self, tree):
+            self.tree = tree
+            self.s = None
+            self.gust = None
+            self.d = None
+            self.t = None
+            self.TREE = {
+                's' : 's',
+                'gust' : 'gust',
+                'd' : 'd',
+                't' : 't',
+            }
+            parse(self)
+
+        def __str__(self):
+            return 'Wind'
+
+
+def parse(obj):
+    """ Parse an object using the tree information and build a class hierarchy.
+    For list items add to a list of the name with a 's' appended
+
+    This code is a little bit complex :)
+    """
+    if hasattr(obj.tree, 'items'):
+        for k,v in obj.tree.items():
+            code = 'obj.%s = "%s"' % (k, v)
+            exec code
+
+    for k,v in obj.TREE.items():
+        elements = obj.tree.findall(k)
+        if not elements:
+            continue
+
+        # just one element
+        if len(elements) == 1:
+            for element in elements:
+                children = element.getchildren()
+                if children:
+                    code = 'obj.%s = %s(element)' % (k, v)
+                else:
+                    code = 'obj.%s = element.text.strip()' % (k)
+                exec code
+            continue
+
+        # list of elements
+        code = 'obj.%ss = []' % k
+        exec code
+        for element in elements:
+            children = element.getchildren()
+            if children:
+                code = '%s = %s(element)' % (k, v)
+            else:
+                code = 'obj.%s = element.text.strip()' % (k)
+            exec code
+            code = 'obj.%ss.append(%s)' % (k, k)
+            exec code
+        continue
+
+    return obj
+
+
+if __name__ == '__main__':
+    location_tree=ET.parse('SZXX0033-eloc.xml')
+    location = WeatherData(location_tree)
+    conditions_tree=ET.parse('SZXX0033-cc.xml')
+    conditions = WeatherData(conditions_tree)
+    forecast_tree=ET.parse('SZXX0033-dayf5.xml')
+    forecast = WeatherData(forecast_tree)
+    print dir(forecast)
+    for i in dir(forecast):
+        item = eval('forecast.%s' % (i))
+        #print i, type(item), item
+    #pprint(forecast)
+    f = open('forecast.pickle', 'w')
+    #pickle.dump(forecast, f, pickle.HIGHEST_PROTOCOL)
+    #pickle.dump(forecast_tree, f, pickle.HIGHEST_PROTOCOL)
+    f.close()
+
+    print dir(forecast.loc)
+    print forecast.loc.id
+    print dir(forecast.dayf)
+    print forecast.dayf.lsup
+    print dir(forecast.dayf.day)
+    print type(forecast.dayf.days)
+    print forecast.dayf.days
+    for day in forecast.dayf.days:
+        print dir(day)
+        print day.dt
+        print type(day.parts)
+        for part in day.parts:
+            print dir(part)
+            print dir(part.wind)
+            print part.wind.s, part.wind.t
+
+    print location.eloc.ctry

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Freevo-cvslog mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/freevo-cvslog

Reply via email to