Author: duncan
Date: Tue Sep 11 15:38:44 2007
New Revision: 9867

Log:
Added 1click from firefox
This has a nice format but permission is needed to use the service


Added:
   branches/rel-1/testing/Duncan/weather/1click/
   branches/rel-1/testing/Duncan/weather/1click/1click.py
   branches/rel-1/testing/Duncan/weather/1click/SZXX0033-cc.xml
   branches/rel-1/testing/Duncan/weather/1click/SZXX0033-dayf5.xml
   branches/rel-1/testing/Duncan/weather/1click/parse.py   (contents, props 
changed)
Modified:
   branches/rel-1/testing/Duncan/weather/yahoo/yahoo.py

Added: branches/rel-1/testing/Duncan/weather/1click/1click.py
==============================================================================
--- (empty file)
+++ branches/rel-1/testing/Duncan/weather/1click/1click.py      Tue Sep 11 
15:38:44 2007
@@ -0,0 +1,1074 @@
+# -*- coding: iso-8859-1 -*-
+# -----------------------------------------------------------------------
+# weather.py - a plugin to obtain detailed weather forecast information
+# -----------------------------------------------------------------------
+# $Id: weather.py 9862 2007-09-10 15:36:28Z duncan $
+#
+# Notes:
+#
+# Todo:
+#   X pull down weather on demand MENU_SELECT (need to fix popup behavior)
+#   X Ability to specify custom location name in PLUGIN_WEATHER_LOCATIONS
+#   - get location name back onto details screen
+#   - i18n support
+#   - a freevo helper to grab weather data behind the scenes
+#
+# activate:
+#
+#    plugin.activate('weather', level=45)
+#    PLUGIN_WEATHER_LOCATIONS = [ ("USNC0559", 0, "en", "Home sweet home") ]
+#
+# -----------------------------------------------------------------------
+# 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
+
+# date/time
+import time
+
+#regular expression
+import re
+
+# rdf modules
+from xml.dom.ext.reader import Sax2
+import urllib
+
+#freevo modules
+import config, menu, rc, plugin, skin, osd, util
+from gui.PopupBox import PopupBox
+from item import Item
+
+#get the singletons so we get skin info and access the osd
+skin = skin.get_singleton()
+osd  = osd.get_singleton()
+
+#check every 2 hours
+WEATHER_AGE = 7200
+WEATHER_DIR = os.path.join(config.SHARE_DIR, 'images', 'weather')
+
+WEATHER_DATA = [
+    ('1', _('Cloudy'), 'cloudy.png'),
+    ('3', _('Mostly Cloudy'), 'mcloudy.png'),
+    ('4', _('Partly Cloudy'), 'pcloudy.png'),
+    ('13', _('Light Rain'), 'lshowers.png'),
+    ('14', _('Showers'), 'showers.png'),
+    ('16', _('Snow'), 'snowshow.png'),
+    ('18', _('Rain'), 'showers.png'),
+    ('19', _('AM Showers'), 'showers.png'),
+    ('20', _('Fog'), 'fog.png'),
+    ('21', _('Few Showers'), 'lshowers.png'),
+    ('22', _('Mostly Sunny'), 'sunny.png'),
+    ('24', _('Sunny'), 'sunny.png'),
+    ('25', _('Scattered Flurries'), 'flurries.png'),
+    ('26', _('AM Clouds/PM Sun'), 'pcloudy.png'),
+    ('27', _('Isolated T-Storms'), 'thunshowers.png'),
+    ('28', _('Scattered Thunderstorms'), 'thunshowers.png'),
+    ('29', _('PM Showers'), 'showers.png'),
+    ('30', _('PM Showers/Wind'), 'showers.png'),
+    ('31', _('Rain/Snow Showers'), 'rainsnow.png'),
+    ('32', _('Few Snow Showers'), 'flurries.png'),
+    ('33', _('Cloudy/Wind'), 'cloudy.png'),
+    ('34', _('Flurries/Wind'), 'flurries.png'),
+    ('35', _('Mostly Cloudy/Windy'), 'mcloudy.png'),
+    ('36', _('Rain/Thunder'), 'thunshowers.png'),
+    ('37', _('Partly Cloudy/Windy'), 'pcloudy.png'),
+    ('38', _('AM Rain/Snow Showers'), 'rainsnow.png'),
+    ('40', _('Light Rain/Wind'), 'lshowers.png'),
+    ('41', _('Showers/Wind'), 'showers.png'),
+    ('42', _('Heavy Snow'), 'snowshow.png'),
+    ('43', _('Drizzle'), 'showers.png'),
+    ('44', _('Mostly Sunny/Wind'), 'sunny.png'),
+    ('45', _('Flurries'), 'flurries.png'),
+    ('47', _('Rain/Wind'), 'showers.png'),
+    ('49', _('Sct Flurries/Wind'), 'flurries.png'),
+    ('50', _('Sct Strong Storms'), 'thunshowers.png'),
+    ('51', _('PM T-Storms'), 'thunshowers.png'),
+    ('53', _('Thunderstorms'), 'thunshowers.png'),
+    ('55', _('Sunny/Windy'), 'sunny.png'),
+    ('56', _('AM Thunderstorms'), 'thunshowers.png'),
+    ('62', _('AM Rain'), 'showers.png'),
+    ('64', _('Iso T-Storms/Wind'), 'thunshowers.png'),
+    ('65', _('Rain/Snow'), 'rainsnow.png'),
+    ('66', _('Sct T-Storms/Wind'), 'showers.png'),
+    ('67', _('AM Showers/Wind'), 'showers.png'),
+    ('70', _('Sct Snow Showers'), 'snowshow.png'),
+    ('71', _('Snow to Ice/Wind'), 'snowshow.png'),
+    ('76', _('AM Ice'), 'rainsnow.png'),
+    ('77', _('Snow to Rain'), 'rainsnow.png'),
+    ('80', _('AM Light Rain'), 'lshowers.png'),
+    ('81', _('PM Light Rain'), 'lshowers.png'),
+    ('82', _('PM Rain'), 'showers.png'),
+    ('84', _('Snow Showers'), 'snowshow.png'),
+    ('85', _('Rain to Snow'), 'rainsnow.png'),
+    ('86', _('PM Rain/Snow'), 'snowshow.png'),
+    ('88', _('Few Showers/Wind'), 'showers.png'),
+    ('90', _('Snow/Wind'), 'snowshow.png'),
+    ('91', _('PM Rain/Snow Showers'), 'rainsnow.png'),
+    ('92', _('PM Rain/Snow/Wind'), 'rainsnow.png'),
+    ('93', _('Rain/Snow Showers/Wind'), 'rainsnow.png'),
+    ('94', _('Rain/Snow/Wind'), 'rainsnow.png'),
+    ('98', _('Light Snow'), 'flurries.png'),
+    ('100', _('PM Snow'), 'snowshow.png'),
+    ('101', _('Few Snow Showers/Wind'), 'snowshow.png'),
+    ('103', _('Light Snow/Wind'), 'flurries.png'),
+    ('104', _('Wintry Mix'), 'flurries.png'),
+    ('105', _('AM Wintry Mix'), 'rainsnow.png'),
+    ('106', _('Hvy Rain/Freezing Rain'), 'rainsnow.png'),
+    ('108', _('AM Light Snow'), 'flurries.png'),
+    ('109', _('PM Rain/Snow/Wind'), 'rainsnow.png'),
+    ('114', _('Rain/Freezing Rain'), 'showers.png'),
+    ('118', _('T-Storms/Wind'), 'thunshowers.png'),
+    ('123', _('Sprinkles'), 'lshowers.png'),
+    ('125', _('AM Snow Showers'), 'snowshow.png'),
+    ('126', _('AM Clouds/PM Sun/Wind'), 'pcloudy.png'),
+    ('128', _('AM Rain/Snow/Wind'), 'rainsnow.png'),
+    ('130', _('Rain to Snow/Wind'), 'rainsnow.png'),
+    ('132', _('Snow to Wintry Mix'), 'snowshow.png'),
+    ('133', _('PM Snow Showers/Wind'), 'snowshow.png'),
+    ('135', _('Snow and Ice to Rain'), 'rainsnow.png'),
+    ('137', _('Heavy Rain'), 'showers.png'),
+    ('138', _('AM Rain/Ice'), 'showers.png'),
+    ('145', _('AM Snow Showers/Wind'), 'snowshow.png'),
+    ('146', _('AM Light Snow/Wind'), 'flurries.png'),
+    ('150', _('PM Light Rain/Wind'), 'lshowers.png'),
+    ('152', _('AM Light Wintry Mix'), 'rainsnow.png'),
+    ('153', _('PM Light Snow/Wind'), 'flurries.png'),
+    ('154', _('Heavy Rain/Wind'), 'showers.png'),
+    ('155', _('PM Snow Shower'), 'snowshow.png'),
+    ('158', _('Snow to Rain/Wind'), 'rainsnow.png'),
+    ('164', _('PM Light Rain/Ice'), 'showers.png'),
+    ('167', _('AM Snow'), 'snowshow.png'),
+    ('171', _('Snow to Ice'), 'snowshow.png'),
+    ('172', _('Wintry Mix/Wind'), 'rainsnow.png'),
+    ('175', _('PM Light Snow'), 'flurries.png'),
+    ('178', _('AM Drizzle'), 'lshowers.png'),
+    ('189', _('Strong Storms/Wind'), 'thunshowers.png'),
+    ('193', _('PM Drizzle'), 'lshowers.png'),
+    ('194', _('Drizzle'), 'lshowers.png'),
+    ('201', _('AM Light Rain/Wind'), 'lshowers.png'),
+    ('204', _('AM Rain/Wind'), 'showers.png'),
+    ('223', _('Wintry Mix to Snow'), 'rainsnow.png'),
+    ('231', _('Rain'), 'showers.png'),
+    ('240', _('AM Light Rain/Ice'), 'rainsnow.png'),
+    ('259', _('Hvy Rain/Freezing Rain'), 'showers.png'),
+    ('271', _('Snow Showers/Windy'), 'snowshow.png'),
+    ('988', _('Partly Cloudy/Windy'), 'pcloudy.png'),
+    ('989', _('Light Rain Shower'), 'lshowers.png'),
+    ('990', _('Light Rain with Thunder'), 'thunshowers.png'),
+    ('991', _('Light Drizzle'), 'lshowers.png'),
+    ('992', _('Mist'), 'fog.png'),
+    ('993', _('Smoke'), 'fog.png'),
+    ('994', _('Haze'), 'fog.png'),
+    ('995', _('Light Snow Shower'), 'flurries.png'),
+    ('996', _('Light Snow Shower/ Windy'), 'flurries.png'),
+    ('997', _('Clear'), 'fair.png'),
+    ('998', _('A Few Clouds'), 'pcloudy.png'),
+    ('999', _('Fair'), 'fair.png')
+ ]
+
+def wget(iUrl):
+    for i in range(3):
+        try:
+            t1 = time.time()
+            fd = urllib.urlopen(iUrl)
+            data = fd.read()
+            fd.close()
+            t2 = time.time()
+            print "Weather download: ", iUrl, "-", "%.1f" % (t2-t1), "sec"
+            return data
+        except IOError:
+            print "retrying wget '%s'" % (iUrl,)
+            pass
+
+def toCelcius(fTemp):
+    try:
+        tTemp = float (fTemp )
+    except ValueError:
+        tTemp = 0.0
+    nTemp = (5.0/9.0)*(tTemp - 32.0)
+    return "%d" % (nTemp,)
+
+def toKilometers(miles):
+    try:
+        tTemp = float(miles)
+    except ValueError:
+        tTemp = 0.0
+    nTemp = tTemp*1.6
+    return "%d" % (int(nTemp),)
+
+def toBarometer(baro):
+    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('weather', level=45)
+    PLUGIN_WEATHER_LOCATIONS = [
+      ("<val1>", <bool>, "<lang>", "<str>"),
+      ("<val2>", <bool>, "<lang>", "<str>"),
+    ...
+    ]
+
+    where <val#> is a zipcode or
+    and <bool> (1 == convert to SI Units; 0 == do not convert)
+    and <str> is a custom name you wish to use for this location
+    """
+    # make an init func that creates the cache dir if it don't exist
+    def __init__(self):
+        if not hasattr(config, 'PLUGIN_WEATHER_LOCATIONS'):
+            self.reason = 'PLUGIN_WEATHER_LOCATIONS not defined'
+            return
+        plugin.MainMenuPlugin.__init__(self)
+
+    def config(self):
+        return [
+            ('PLUGIN_WEATHER_LOCATIONS', [("USNC0559", 0)], "Location codes to 
grab forecasts for"),
+            ('PLUGIN_WEATHER_DATAURL', 
'http://www.tpfans.com/rss/weather.php?Citycode=%s&Language=%s', 'Data URL'),
+            ('PLUGIN_WEATHER_MAPURL', 
'http://www.weather.com/weather/map/%s?from=LAPmaps', 'Radar Map URL')
+        ]
+
+    def items(self, parent):
+        return [ WeatherMainMenu(parent) ]
+
+
+class WeatherItem(Item):
+    """
+    Item for the menu for one rss feed
+    """
+    def __init__(self, parent, iLocation):
+        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.language     = 'EN'
+        self.convertData  = 0
+        self.name         = None
+        self.city         = None
+        self.state        = None
+        self.country      = None
+        self.curTemp      = None
+        self.updated      = None
+        self.curIcon      = None
+        self.curWind      = None
+        self.windDir      = None
+        self.barometer    = None
+        self.curHumid     = None
+        self.curFeel      = None
+        self.uvIndex      = None
+        self.visibility   = None
+        self.shortdesc    = 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.radarUrl     = None
+        # were we asked to convert to SI units?
+        if isinstance(iLocation, tuple):
+            self.location    = iLocation[0]
+            if len(iLocation) > 1:
+                self.convertData = int(iLocation[1])
+            if len(iLocation) > 2:
+                self.language = str(iLocation[2])
+            if len(iLocation) > 3:
+                self.name     = str(iLocation[3])
+            if len(iLocation) > 4:
+                self.radarUrl = str(iLocation[4])
+            self.popupParam = Unicode(self.location)
+            if self.name:
+                self.popupParam = Unicode(self.name)
+
+        else:
+            self.location    = iLocation
+            self.convertData = 0
+            self.popupParam = self.location
+
+        self.dataurl = 
"http://www.msnbc.com/m/chnk/d/weather_d_src.asp?acid=%s"; % (self.location,)
+        self.dataurl = 
"http://www.tpfans.com/rss/weather.php?Citycode=%s&Language=%s"; % 
(self.location, self.language)
+        self.dataurl = config.PLUGIN_WEATHER_DATAURL % (self.location, 
self.language)
+        self.mapurl         = 
"http://www.weather.com/weather/map/%s?from=LAPmaps"; % (self.location,)
+        self.mapurl         = config.PLUGIN_WEATHER_MAPURL % (self.location,)
+        self.mapurl2        = None
+        self.maplink        = None
+        self.weatherData    = None
+        self.weatherMapData = None
+
+        self.cacheDir  = '%s/weather_%s' % (config.FREEVO_CACHEDIR, 
self.location)
+        self.cacheFile = '%s/data' % (self.cacheDir,)
+        self.mapFile   = '%s/map' % (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 isValid(self):
+        return not self.error
+
+    def getHumidity(self):
+        return "%s %%" % (self.curHumid,)
+
+    def getBarometer(self):
+        if self.convertData:
+            return "%s kPa" % (self.barometer,)
+        else:
+            return "%s in" % (self.barometer,)
+
+    def getWind(self):
+        if self.convertData:
+            return "%s km/h" % (self.curWind,)
+        else:
+            return "%s mph" % (self.curWind,)
+
+    def getTemp(self):
+        if self.convertData:
+            return u"%s\xb0 C" % (self.curTemp,)
+        else:
+            return u"%s\xb0 F" % (self.curTemp,)
+
+    def getLastUpdated(self):
+        if self.convertData:
+            # day / month / year  24hour:min:sec
+            return _("Last updated: %s") % (time.strftime("%d/%m/%Y %H:%M:%S", 
time.localtime(self.last_update)),)
+        else:
+            # month / day / year  12hour:min:sec [AM|PM]
+            return _("Last updated: %s") % (time.strftime("%m/%d/%Y %I:%M:%S 
%p", time.localtime(self.last_update)),)
+
+    def getFeel(self):
+        if self.convertData:
+            return u"%s\xb0 C" % (self.curFeel,)
+        else:
+            return u"%s\xb0 F" % (self.curFeel,)
+
+    def getVisibility(self):
+        if float(self.visibility) == 999.00:
+            return _("Unlimited")
+        elif self.convertData:
+            return "%s km" % (self.visibility,)
+        else:
+            return "%s mi" % (self.visibility,)
+
+    def start_detailed_interface(self, arg=None, menuw=None):
+        WeatherDetailHandler(arg, menuw, self)
+
+    def actions(self):
+        """
+        return a list of actions for this item
+        """
+        return [ (self.start_detailed_interface, _('Show Weather Details')) ]
+
+    def saveToCache(self):
+        util.save_pickle(self.weatherData, self.cacheFile)
+        # attempt to save weathermap
+        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:
+            print "failed while saving weather map to cache '%s'" % 
(self.mapFile,)
+
+    def loadFromCache(self):
+        self.weatherData = util.read_pickle(self.cacheFile)
+
+        try:
+            size = int(os.stat(self.mapFile)[6])
+        except:
+            _debug_("failed attempting to load %s radar map from cache" % 
(self.location,), config.DERROR)
+            pass
+        else:
+            imgfd = os.open(self.mapFile, os.R_OK)
+            self.weatherMapData = os.read(imgfd, size)
+            os.close(imgfd)
+
+    def needRefresh(self):
+        '''is the cache too old?'''
+        if (os.path.isfile(self.cacheFile) == 0 or \
+            (abs(time.time() - os.path.getmtime(self.cacheFile)) > 
WEATHER_AGE)):
+            return 1
+        else:
+            return 0
+
+    def getForecast(self, force=0):
+        '''grab the forecast, updating for the website if needed'''
+
+        # check cache
+        try:
+            if force or self.needRefresh():
+                self.updateData()
+            else:
+                self.loadFromCache()
+        except:
+            self.error = 1
+            print "ERROR obtaining forecast data for '%s'" % (self.location,)
+        else:
+            # set the last update timestamp
+            self.last_update = os.path.getmtime(self.cacheFile)
+
+            # now convert the self.weatherData structure to parsable 
information
+            try:
+                self.convertWeatherData()
+            except:
+                self.error = 1
+                import traceback, sys
+                print "ERROR parsing forecast data for '%s'" % (self.location,)
+                print "\tThis could indicate a failed download of weather data 
from msnbc.  "\
+                      "You can confirm this by examining the contents of the 
file '%s'.  "\
+                      "Below is also the traceback indicating where we 
discovered the problem "\
+                      "with the weather file.  If the weather file appears 
intact, please report " \
+                      "this to the '[EMAIL PROTECTED]'\n" % (self.cacheFile,)
+                output = apply(traceback.format_exception, sys.exc_info())
+                output = ''.join(output)
+                output = urllib.unquote(output)
+                print output
+
+    def GetString(self, var):
+        '''when given a variable, it returns the value stored in the MSNBC 
forecast data'''
+
+        regexp  = re.compile('%s = "[^"]*"' % (var,))
+        results = regexp.search(self.weatherData)
+        if not results:
+            return ''
+        (start, end) = results.span()
+        start += len(var) + 4 # the 4 chars is the ' = "'
+        end   -= 1  # strip off the right "
+        return self.weatherData[start:end]
+
+    def updateData(self):
+        popup = PopupBox(text=_('Fetching Weather for %s...') % 
self.popupParam)
+        popup.show()
+
+        # parse the document
+        try:
+            self.weatherData = wget(self.dataurl)
+        except:
+            popup.destroy()
+            raise WeatherError, 'Weather ERROR: failed attempting to grab 
forecast for %s' % self.location
+
+        #TODO: Get description from 
http://weather.noaa.gov/pub/data/forecasts/zone/nc/ncz041.txt
+
+        # obtain radar map
+        popup.destroy()
+        popup = PopupBox(text=_('Fetching Radar Map for %s...') % 
self.popupParam)
+        popup.show()
+        try:
+            if self.radarUrl is not None:
+                self.maplink = (self.radarUrl)
+            if self.maplink is None:
+                # get the first web page
+                for attempt in range(3):
+                    weatherPage  = wget (self.mapurl)
+                    try:
+                        # find link to map page
+                        regexp       = re.compile ('if \(isMinNS4\) var 
mapNURL = "[^"]*";', re.IGNORECASE )
+                        results      = regexp.search(weatherPage)
+                        (start, end) = results.span()
+                        # TODO: I don't like having fixed length offsets from 
start, end
+                        weatherPage2 = "http://www.weather.com/%s"; % 
(weatherPage[start+30:end-2],)
+
+                        mapPage      = wget (weatherPage2)
+                        # find a link to the real doplay map
+                        regexp       = re.compile('<img NAME="mapImg" 
SRC="http://image.weather.com[^"]*jpg";', re.IGNORECASE)
+                        results      = regexp.search(mapPage)
+                        (start, end) = results.span()
+                        # TODO: I don't like having fixed length offsets from 
start, end
+                        self.maplink = mapPage[start+24:end-1]
+                        break;
+                    except:
+                        print "Retrying [%d] %s" % (attempt,self.mapurl)
+                        pass
+            # pull down the map locally
+            try:
+                self.weatherMapData = wget(self.maplink)
+            except:
+                print 'Weather ERROR: failed attempting to download radar map 
from %s' % self.maplink
+        except:
+            print 'Weather ERROR: failed attempting to locate radar map URL 
for %s' % self.location
+            self.weatherMapData = None
+            pass
+
+            import traceback, sys
+            output = apply(traceback.format_exception, sys.exc_info())
+            output = ''.join(output)
+            output = urllib.unquote(output)
+            print output
+
+        #write the file
+        self.saveToCache()
+
+        popup.destroy()
+
+    def convertWeatherData(self):
+        self.city    = self.GetString("this.swCity")
+        self.state   = self.GetString("this.swSubDiv")
+        self.country = self.GetString("this.swCountry")
+        self.curTemp = self.GetString("this.swTemp")
+        self.updated = self.GetString("this.swLastUp")
+
+        # reset variables
+        self.date        = []
+        self.weatherIcon = []
+        self.highTemp    = []
+        self.lowTemp     = []
+        self.weatherType = []
+
+        # set the location name (if one was not specified in the 
WEATHER_LOCATIONS"
+        if self.name is None:
+            self.name    = "%s" % (self.city)
+
+        # convert temperature
+        if self.curTemp is None or len(self.curTemp) == 0:
+            self.curTemp = "-na-"
+            self.updated = self.updated + " (Not All Information Available)"
+        else:
+            if self.convertData:
+                self.curTemp = toCelcius(self.curTemp)
+
+        self.curIcon   = self.GetString("this.swCIcon")
+        self.curWind   = self.GetString("this.swWindS")
+
+        # convert wind
+        if self.convertData:
+            self.curWind = toKilometers(self.curWind)
+
+        self.windDir   = self.GetString("this.swWindD")
+        self.barometer = self.GetString("this.swBaro")
+
+        # convert barometer
+        if self.convertData:
+            self.barometer = toBarometer(self.barometer)
+
+        self.curHumid = self.GetString("this.swHumid")
+        self.curFeel  = self.GetString("this.swReal")
+
+        # convert feels-like temp
+        if self.convertData:
+            self.curFeel = toCelcius(self.curFeel)
+
+        self.uvIndex     = self.GetString("this.swUV")
+        self.visibility  = self.GetString("this.swVis")
+        if not self.visibility:
+            self.visibility = 0.0
+
+        # convert visibility
+        if self.convertData and float(self.visibility) != 999.0:
+            self.visibility = toKilometers(self.visibility)
+
+        self.shortdesc = _(self.GetString("this.swConText"))
+        if self.shortdesc is None or len(self.shortdesc) == 0:
+            self.shortdesc = self.curIcon
+
+        self.forecastData = self.GetString("this.swFore")
+        holdings     = []
+        holdings     = self.forecastData.split("|")
+        try:
+            dayNum = int(holdings[0])
+        except ValueError:
+            dayNum = int(time.strftime("%u")) + 1
+        curDay = int(time.strftime("%u")) + 1 # day of week 2(mon) - 1(sun)
+
+        if dayNum != curDay:
+            self.pastTime = 1
+
+        ltime = time.localtime()
+        ctr   = 0
+        for i in range(5,10):
+            (mons, days, years) = holdings[i].split("/")
+            mons  = int(mons)
+            days  = int(days)
+            years = int(years)
+            dnum  = (ltime[6] + ctr) % 7
+            self.date.append(time.strftime("%A", (years, mons, days, ltime[3], 
ltime[4], ltime[5], \
+                dnum, ltime[7], ltime[8])))
+            ctr += 1
+
+        # weather icon
+        for i in (10,11,12,13):
+            self.weatherIcon.append(holdings[i])
+
+        # calculate high temps
+        for i in (20,21,22,23):
+            if self.convertData:
+                holdings[i] = toCelcius(holdings[i])
+            self.highTemp.append(holdings[i])
+
+        # calculate low temps
+        for i in (40,41,42,43):
+            if self.convertData:
+                holdings[i] = toCelcius(holdings[i])
+            self.lowTemp.append(holdings[i])
+
+        for i in (15,16,17,18):
+            self.weatherType.append(holdings[i])
+
+        self.setWeatherTypeIcon()
+        self.setWeatherIcon()
+
+        # Create description
+        self.description = "%s %s %s" % (self.shortdesc, _("at"), 
self.getTemp())
+
+    def setWeatherIcon(self):
+        '''set the weather icon given the short forecast description'''
+
+        match = weatherTypes.findType(name=self.shortdesc)
+        if match:
+            self.curIcon     = match.getIcon()
+        else:
+            self.curIcon     = "unknown.png"
+
+        # set the Item.image value
+        self.image = os.path.join(WEATHER_DIR, self.curIcon)
+        return
+
+    def setWeatherTypeIcon(self):
+        '''obtain the weather icons for multiple day forecast'''
+
+        for i in range(4):
+            weather_type = self.weatherType[i]
+            if not weather_type:
+                print 'No weather type for day %s' % (i)
+                self.weatherType[i] = _("%s (day: %s)") % (_("Unknown"), i)
+                self.weatherIcon[i] = "unknown.png"
+            else:
+                match = weatherTypes.findType(number=weather_type)
+                if match:
+                    self.weatherType[i] = match.getName()
+                    self.weatherIcon[i] = match.getIcon()
+                else:
+                    self.weatherType[i] = _("%s (type: %s)") % (_("Unknown"), 
weather_type)
+                    self.weatherIcon[i] = "unknown.png"
+
+class WeatherType:
+    def __init__(self, iNum=0, iName="", iIcon=""):
+        self.number = iNum
+        self.name   = iName
+        self.icon   = iIcon
+
+    def setNumber(self, n):
+        self.number = n
+
+    def setName(self, n):
+        self.name = n
+
+    def setIcon(self, n):
+        self.icon = n
+
+    def getNumber(self):
+        return self.number
+
+    def getName(self):
+        return _(self.name)
+
+    def getIcon(self):
+        return self.icon
+
+class WeatherTypesClass:
+    def __init__(self):
+        self.wtypes      = []
+        self.num_lookup  = {} # reverse hash to quickly get a Weathertype w/ a 
number
+        self.name_lookup = {} # reverse hash to quickly get a Weathertype w/ a 
name
+        self.icon_lookup = {} # reverse hash to quickly get a Weathertype w/ a 
icon
+        self.loadWeatherTypes()
+    def loadWeatherTypes(self):
+
+        for icdata in WEATHER_DATA:
+            try:
+                wtype = WeatherType()
+                wtype.setNumber (icdata[0])
+                wtype.setName   (icdata[1])
+                wtype.setIcon   (icdata[2])
+
+                # populate reverse dictionaries
+                self.num_lookup[ wtype.getNumber() ] = len(self.wtypes)
+                self.name_lookup[ wtype.getName() ]  = len(self.wtypes)
+                self.icon_lookup[ wtype.getIcon() ]  = len(self.wtypes)
+
+                self.wtypes.append (wtype)
+            except:
+                pass
+    def findType(self, number=None, name=None, icon=None):
+        ''' return a type given a type number '''
+        if number:
+            try:
+                idx = self.num_lookup[number]
+                return self.wtypes[ idx ]
+            except:
+                return None
+        elif name:
+            try:
+                idx = self.name_lookup[name]
+                return self.wtypes[ idx ]
+            except:
+                return None
+        elif icon:
+            try:
+                idx = self.icon_lookup[icon]
+                return self.wtypes[ idx ]
+            except:
+                return None
+        else:
+            print 'Unknown type requested number=%s name=%s icon=%s' % 
(number, name, icon)
+            return None
+
+    def __len__(self): return len(self.wtypes)
+    def __getitem__(self, i): return self.wtypes[i]
+
+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):
+        Item.__init__(self, parent, skin_type='weather')
+        self.parent = parent
+        self.name   = _('Weather')
+
+    def actions(self):
+        """
+        return a list of actions for this item
+        """
+        items = [ (self.create_locations_menu , _('Locations')) ]
+        return items
+
+    def __call__(self, arg=None, menuw=None):
+        """
+        call first action in the actions() list
+        """
+        if self.actions():
+            return self.actions()[0][0](arg=arg, menuw=menuw)
+
+    def create_locations_menu(self, arg=None, menuw=None):
+        locations  = []
+        autoselect = 0
+        # create menu items
+        for location in config.PLUGIN_WEATHER_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, iArg=None, iMenuw=None, iWeather=None):
+        self.arg     = iArg
+        self.menuw   = iMenuw
+        self.weather = iWeather
+        self.menuw.hide(clear=False)
+        rc.app(self)
+
+        self.skins     = ('day', 'forecast', 'week', 'doplar')
+
+        self.subtitles = (_('Current Conditions'), _('Today\'s Forecast'),
+                          _('Extended Forecast'), _('Radar Map'))
+
+        self.curSkin   = 0
+
+        self.title    = self.weather.name
+        self.subtitle = self.subtitles[0]
+
+        # Fire up splashscreen and load the plugins
+        skin.draw('weather', self)
+
+    def prevSkin(self):
+        '''decriment self.curSkin'''
+        self.curSkin -= 1
+
+        # out of bounds check, reset to size of skins array
+        if self.curSkin < 0:
+            self.curSkin = len(self.skins)-1
+        self.subtitle = self.subtitles[self.curSkin]
+
+    def nextSkin(self):
+        '''increment self.curSkin'''
+        self.curSkin += 1
+
+        # out of bounds check, reset to 0
+        if self.curSkin >= len(self.skins):
+            self.curSkin = 0
+        self.subtitle = self.subtitles[self.curSkin]
+
+    def eventhandler(self, event, menuw=None):
+        '''eventhandler'''
+        if event == 'MENU_BACK_ONE_MENU':
+            rc.app(None)
+            self.menuw.show()
+            return True
+
+        elif event == 'MENU_SELECT':
+            # TODO: update the current forecast data, and refresh
+            self.weather.getForecast(force=1)
+            skin.clear()
+            skin.draw('weather', self)
+            return True
+
+        elif event in ('MENU_DOWN', 'MENU_RIGHT'):
+            # Fire up the next skin
+            self.nextSkin()
+            skin.draw('weather', self)
+            return True
+
+        elif event in ('MENU_UP', 'MENU_LEFT'):
+            # Fire up the previous skin
+            self.prevSkin()
+            skin.draw('weather', self)
+            return True
+
+        return False
+
+class WeatherBaseScreen(skin.Area):
+    """
+    A base class for weather screens to inherit from, provides common 
members+methods
+    """
+    def __init__(self):
+        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_doplar)
+
+    def update_day(self):
+        # 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.getBarometer()
+        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 %s %s' % (self.parent.weather.windDir, _('at'), 
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.getFeel()
+        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.uvIndex
+        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.shortdesc,
+            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.getTemp(),
+            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 extremely useless, all it\'s doing is putting text
+        around the day view. It would be nice if I could use the same source
+        that the gnome-applet weather applet uses for detailed forecast data
+        '''
+        x_start = self.content.x + (20  * self.xmult)
+        y_start = self.content.y + (30  * self.xmult)
+
+        lines = []
+        lines.append('%s %s %s %s.' % (\
+            _('Today, a high of'), self.parent.weather.highTemp[0], \
+            _('and a low of'), self.parent.weather.lowTemp[0]))
+        lines.append('%s %s %s' % (_("Currently, there is a humidity of"),
+            self.parent.weather.getHumidity(), _("and"),))
+
+        text = _("the winds are ")
+        if self.parent.weather.windDir == "CALM":
+            text += "%s. " % (_("calm"),)
+        else:
+            text += "%s %s %s %s." % (\
+                _("coming in at"), self.parent.weather.getWind(), \
+                _("from the"), self.parent.weather.windDir)
+        lines.append(text)
+
+        if float(self.parent.weather.visibility) == 999.00:
+            lines.append(_("Visibility will be unlimited today"))
+        else:
+            lines.append("%s %s." % (\
+                _("There will be a visibility of"), 
self.parent.weather.getVisibility(),))
+
+        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)
+
+    def update_week(self):
+
+        x_start = self.content.x + (10  * self.xmult)
+        y_start = self.content.y + (10  * self.xmult)
+
+        day = 0
+        #for x in (40, 220, 400, 580):
+        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_doplar(self):
+        if self.parent.weather.weatherMapData is None:
+            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 
Radar 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, 
self.content.y, self.content.width,
+                                                           
self.content.height))
+
+    def update_content(self):
+        self.parent   = self.menu
+        self.content  = self.calc_geometry(self.layout.content, 
copy_object=True)
+        self.update_functions[self.menu.curSkin]()
+
+
+# create one instance of the WeatherType class
+weatherTypes = WeatherTypesClass()
+skin.register ('weather', ('screen', 'subtitle', 'title', 'plugin', 
WeatherBaseScreen()))

Added: branches/rel-1/testing/Duncan/weather/1click/SZXX0033-cc.xml
==============================================================================
--- (empty file)
+++ branches/rel-1/testing/Duncan/weather/1click/SZXX0033-cc.xml        Tue Sep 
11 15:38:44 2007
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--This document is intended only for use by authorized licensees of The 
Weather Channel. Unauthorized use is prohibited. Copyright 1995-2005, The 
Weather Channel Interactive, Inc. All Rights Reserved.-->
+<weather ver="2.0">
+  <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>
+  <loc id="SZXX0033">
+    <dnam>Zurich, Switzerland</dnam>
+    <tm>7:43 AM</tm>
+    <lat>47.38</lat>
+    <lon>8.54</lon>
+    <sunr>6:57 AM</sunr>
+    <suns>7:47 PM</suns>
+    <zone>2</zone>
+  </loc>
+  <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>
+      <r>1020.0</r>
+      <d>rising</d>
+    </bar>
+    <wind>
+      <s>5</s>
+      <gust>N/A</gust>
+      <d>20</d>
+      <t>NNE</t>
+    </wind>
+    <hmid>93</hmid>
+    <vis>10.0</vis>
+    <uv>
+      <i>0</i>
+      <t>Low</t>
+    </uv>
+    <dewp>8</dewp>
+    <moon>
+      <icon>29</icon>
+      <t>New</t>
+    </moon>
+  </cc>
+</weather>
+

Added: branches/rel-1/testing/Duncan/weather/1click/SZXX0033-dayf5.xml
==============================================================================
--- (empty file)
+++ branches/rel-1/testing/Duncan/weather/1click/SZXX0033-dayf5.xml     Tue Sep 
11 15:38:44 2007
@@ -0,0 +1,186 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--This document is intended only for use by authorized licensees of The 
Weather Channel. Unauthorized use is prohibited. Copyright 1995-2005, The 
Weather Channel Interactive, Inc. All Rights Reserved.-->
+<weather ver="2.0">
+  <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>
+  <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>
+  <dayf>
+    <lsup>9/11/07 2:27 AM Local Time</lsup>
+    <day d="0" t="Tuesday" dt="Sep 11">
+      <hi>13</hi>
+      <low>7</low>
+      <sunr>6:57 AM</sunr>
+      <suns>7:47 PM</suns>
+      <part p="d">
+        <icon>20</icon>
+        <t>AM Fog / PM Clouds</t>
+        <wind>
+          <s>11</s>
+          <gust>N/A</gust>
+          <d>325</d>
+          <t>NW</t>
+        </wind>
+        <bt>AM Fog</bt>
+        <ppcp>20</ppcp>
+        <hmid>78</hmid>
+      </part>
+      <part p="n">
+        <icon>29</icon>
+        <t>Partly Cloudy</t>
+        <wind>
+          <s>8</s>
+          <gust>N/A</gust>
+          <d>58</d>
+          <t>ENE</t>
+        </wind>
+        <bt>P Cloudy</bt>
+        <ppcp>0</ppcp>
+        <hmid>86</hmid>
+      </part>
+    </day>
+    <day d="1" t="Wednesday" dt="Sep 12">
+      <hi>18</hi>
+      <low>8</low>
+      <sunr>6:59 AM</sunr>
+      <suns>7:45 PM</suns>
+      <part p="d">
+        <icon>34</icon>
+        <t>Mostly Sunny</t>
+        <wind>
+          <s>10</s>
+          <gust>N/A</gust>
+          <d>50</d>
+          <t>NE</t>
+        </wind>
+        <bt>M Sunny</bt>
+        <ppcp>0</ppcp>
+        <hmid>72</hmid>
+      </part>
+      <part p="n">
+        <icon>31</icon>
+        <t>Clear</t>
+        <wind>
+          <s>11</s>
+          <gust>N/A</gust>
+          <d>88</d>
+          <t>E</t>
+        </wind>
+        <bt>Clear</bt>
+        <ppcp>10</ppcp>
+        <hmid>87</hmid>
+      </part>
+    </day>
+    <day d="2" t="Thursday" dt="Sep 13">
+      <hi>21</hi>
+      <low>8</low>
+      <sunr>7:00 AM</sunr>
+      <suns>7:43 PM</suns>
+      <part p="d">
+        <icon>20</icon>
+        <t>AM Fog / PM Sun</t>
+        <wind>
+          <s>8</s>
+          <gust>N/A</gust>
+          <d>101</d>
+          <t>E</t>
+        </wind>
+        <bt>AM Fog</bt>
+        <ppcp>10</ppcp>
+        <hmid>77</hmid>
+      </part>
+      <part p="n">
+        <icon>33</icon>
+        <t>Mostly Clear</t>
+        <wind>
+          <s>8</s>
+          <gust>N/A</gust>
+          <d>158</d>
+          <t>SSE</t>
+        </wind>
+        <bt>M Clear</bt>
+        <ppcp>10</ppcp>
+        <hmid>84</hmid>
+      </part>
+    </day>
+    <day d="3" t="Friday" dt="Sep 14">
+      <hi>22</hi>
+      <low>11</low>
+      <sunr>7:01 AM</sunr>
+      <suns>7:41 PM</suns>
+      <part p="d">
+        <icon>30</icon>
+        <t>Partly Cloudy</t>
+        <wind>
+          <s>10</s>
+          <gust>N/A</gust>
+          <d>222</d>
+          <t>SW</t>
+        </wind>
+        <bt>P Cloudy</bt>
+        <ppcp>20</ppcp>
+        <hmid>76</hmid>
+      </part>
+      <part p="n">
+        <icon>29</icon>
+        <t>Partly Cloudy</t>
+        <wind>
+          <s>8</s>
+          <gust>N/A</gust>
+          <d>227</d>
+          <t>SW</t>
+        </wind>
+        <bt>P Cloudy</bt>
+        <ppcp>20</ppcp>
+        <hmid>87</hmid>
+      </part>
+    </day>
+    <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">
+        <icon>30</icon>
+        <t>Partly Cloudy</t>
+        <wind>
+          <s>8</s>
+          <gust>N/A</gust>
+          <d>291</d>
+          <t>WNW</t>
+        </wind>
+        <bt>P Cloudy</bt>
+        <ppcp>20</ppcp>
+        <hmid>82</hmid>
+      </part>
+      <part p="n">
+        <icon>29</icon>
+        <t>Partly Cloudy</t>
+        <wind>
+          <s>6</s>
+          <gust>N/A</gust>
+          <d>109</d>
+          <t>ESE</t>
+        </wind>
+        <bt>P Cloudy</bt>
+        <ppcp>10</ppcp>
+        <hmid>82</hmid>
+      </part>
+    </day>
+  </dayf>
+</weather>
+

Added: branches/rel-1/testing/Duncan/weather/1click/parse.py
==============================================================================
--- (empty file)
+++ branches/rel-1/testing/Duncan/weather/1click/parse.py       Tue Sep 11 
15:38:44 2007
@@ -0,0 +1,142 @@
+#!/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
+
+tree_elem = {
+    'head/locale' : 'head-locale',
+    'head/form'   : 'head-form',
+    'head/ut'     : 'head-ut',
+    'head/ud'     : 'head-ud',
+    'head/us'     : 'head-us',
+    'head/up'     : 'head-up',
+    'head/ur'     : 'head-ur',
+    'loc'         : 'loc',
+    'loc/dnam'    : 'loc-dnam',
+    'loc/tm'      : 'loc-tm',
+    'loc/lat'     : 'loc-lat',
+    'loc/lon'     : 'loc-lon',
+    'loc/sunr'    : 'loc-sunr',
+    'loc/suns'    : 'loc-suns',
+    'loc/zone'    : 'loc-zone',
+}
+
+cc_elem = {
+    'lsup'        : 'lsup',
+    'obst'        : 'obst',
+    'tmp'         : 'tmp',
+    'flik'        : 'flik',
+    't'           : 't',
+    'icon'        : 'icon',
+    'bar/r'       : 'bar-r',
+    'bar/d'       : 'bar-d',
+    'wind/s'      : 'wind-s',
+    'wind/gust'   : 'wind-gust',
+    'wind/d'      : 'wind-d',
+    'wind/t'      : 'wind-t',
+    'hmid'        : 'hmid',
+    'vis'         : 'vis',
+    'uv/i'        : 'uv-i',
+    'uv/t'        : 'uv-t',
+    'dewp'        : 'dewp',
+    'moon/icon'   : 'moon-icon',
+    'moon/t'      : 'moon-t',
+}
+
+dayf_elem = {
+    'lsup'        : 'lsup',
+}
+
+day_elem = {
+    'hi'          : 'hi',
+    'low'         : 'low',
+    'sunr'        : 'sunr',
+    'suns'        : 'suns',
+}
+
+part_elem = {
+    'icon'        : 'icon',
+    't'           : 't',
+    'wind/s'      : 'wind-s',
+    'wind/gust'   : 'wind-gust',
+    'wind/d'      : 'wind-d',
+    'wind/t'      : 'wind-t',
+    'bt'          : 'bt',
+    'ppcp'        : 'ppcp',
+    'hmid'        : 'hmid',
+}
+
+def iterparent(tree):
+    for parent in tree.getiterator():
+        for child in parent:
+            yield parent, child
+
+#for parent, child in iterparent(tree):
+#    #print './%s/%s' % (parent.tag, child.tag), 't:%r' % child.text, 'i:', 
child.items()
+
+# The idea is to create a list or lists
+d = []
+
+tree=ET.parse('SZXX0033-cc.xml')
+##print tree.getroot().tag
+
+for k,v in tree_elem.items():
+    for elem in tree.findall(k):
+        #print '%s %r %r' % (elem.tag, elem.text.strip(), elem.items())
+        d.append([ elem.tag, elem.text.strip(), elem.items() ])
+
+d0 = []
+ccs = tree.findall('cc')
+for cc in ccs:
+    #print '  %s %r %r' % (cc.tag, cc.text.strip(), cc.items())
+    d0.append([ cc.tag, cc.text.strip(), cc.items() ])
+    for k,v in cc_elem.items():
+        for elem in cc.findall(k):
+            #print '      %s %r %r' % (elem.tag, elem.text.strip(), 
elem.items())
+            d0.append([ elem.tag, elem.text.strip(), elem.items() ])
+    d.append(d0)
+
+tree=ET.parse('SZXX0033-dayf5.xml')
+##print tree.getroot().tag
+
+for k,v in tree_elem.items():
+    for elem in tree.findall(k):
+        #print '%s %r %r' % (elem.tag, elem.text.strip(), elem.items())
+        d.append([ elem.tag, elem.text.strip(), elem.items() ])
+
+d0 = []
+dayfs = tree.findall('dayf')
+for dayf in dayfs:
+    #print '  %s %r %r' % (dayf.tag, dayf.text.strip(), dayf.items())
+    d0.append([ dayf.tag, dayf.text.strip(), dayf.items() ])
+    for k,v in dayf_elem.items():
+        for elem in dayf.findall(k):
+            #print '      %s %r %r' % (elem.tag, elem.text.strip(), 
elem.items())
+            d0.append([ elem.tag, elem.text.strip(), elem.items() ])
+    d1 = []
+    days = dayf.findall('day')
+    for day in days:
+        #print '    %s %r %r' % (day, day.text.strip(), day.items())
+        d1.append([ day.tag, day.text.strip(), day.items() ])
+        for k,v in day_elem.items():
+            for elem in day.findall(k):
+                #print '        %s %r %r' % (elem.tag, elem.text.strip(), 
elem.items())
+                d1.append([ elem.tag, elem.text.strip(), elem.items() ])
+        d2 = []
+        parts = day.findall('part')
+        for part in parts:
+            #print '      %s %r %r' % (part, part.text.strip(), part.items())
+            d2.append([ part.tag, part.text.strip(), part.items() ])
+            for k,v in part_elem.items():
+                for elem in part.findall(k):
+                    #print '          %s %r %r' % (elem.tag, 
elem.text.strip(), elem.items())
+                    d2.append([ elem.tag, elem.text.strip(), elem.items() ])
+            d1.append(d2)
+        d0.append(d1)
+    d.append(d0)
+
+from pprint import pprint
+pprint(d)

Modified: branches/rel-1/testing/Duncan/weather/yahoo/yahoo.py
==============================================================================
--- branches/rel-1/testing/Duncan/weather/yahoo/yahoo.py        (original)
+++ branches/rel-1/testing/Duncan/weather/yahoo/yahoo.py        Tue Sep 11 
15:38:44 2007
@@ -23,6 +23,7 @@
     './/{%(ns1)s}astronomy' % ns  : 'astronomy',
     './/{%(ns1)s}units' % ns      : 'units',
     './/{%(ns1)s}wind' % ns       : 'wind',
+    './/{%(ns1)s}condition' % ns  : 'condition',
     './/{%(ns1)s}forecast' % ns   : 'forecast',
     './/ttl'                      : 'ttl',
     './/lastBuildDate'            : 'lastBuildDate',
@@ -37,7 +38,7 @@
 
 res = {}
 for parent, child in iterparent(tree):
-    print child, child.text, child.items()
+    print '%s->%s' % (parent.tag, child.tag), 't:%r' % child.text, 'i:', 
child.items()
 
 print res
 

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