RE: Help with a Python Program

  • From: "Ken Perry" <whistler@xxxxxxxxxxxxx>
  • To: <programmingblind@xxxxxxxxxxxxx>
  • Date: Tue, 7 Oct 2008 23:11:28 -0500

 
 
Just a hint on this code you can speed it up  a heck of a lot if you get
away from dom and use sax or the simple template parser in python.  Its not
that important to speed up on a PC but I am currently coding on a PDA and
this runs a bit slow do to the interpreter and the dom.
 
Ken

  _____  

From: programmingblind-bounce@xxxxxxxxxxxxx
[mailto:programmingblind-bounce@xxxxxxxxxxxxx] On Behalf Of BlueScale
Sent: Monday, October 06, 2008 10:39 PM
To: programmingblind@xxxxxxxxxxxxx
Subject: RE: Help with a Python Program


Hi,
Thanks for responding.  I actually just finished writing my own.  I never
did get that code shrunk down to size, so I visited the Yahoo developer site
and read through the documentation and code samples.  It took a lot of trial
and error, but I finally got it working!  I also learned a little more about
Python in the process.
If anyone else would like the code, here it is:
#change zipCode to your zip code
zipCode = 0
def getWeather(zip_code):
  if zip_code != 0:
    import urllib
    from xml.dom import minidom
    WEATHER_URL = 'http://xml.weather.yahoo.com/forecastrss?p=%s'
    WEATHER_NS = 'http://xml.weather.yahoo.com/ns/rss/1.0'
    url = WEATHER_URL % zip_code
    dom = minidom.parse(urllib.urlopen(url))
    ycondition = dom.getElementsByTagNameNS(WEATHER_NS, 'condition')[0]
    weatherReport = ycondition.getAttribute('temp') + ' | ' +
ycondition.getAttribute('text')
  else:
    weatherReport = "No zip code set."
  return weatherReport
print getWeather(zipCode)



        

On Mon, 2008-10-06 at 22:28 -0500, Ken Perry wrote: 

This is pretty easy to do.  Unfortunately I am extremely busy right this
minute.  However if no one gets to you till Wednesday I will get to it.  

Ken 


  _____  


From: programmingblind-bounce@xxxxxxxxxxxxx
[mailto:programmingblind-bounce@xxxxxxxxxxxxx] On Behalf Of BlueScale
Sent: Sunday, October 05, 2008 10:39 PM
To: programmingblind@xxxxxxxxxxxxx
Subject: Help with a Python Program





Hi,
I found this program to get the weather with a commandline program.  I want
to modify it for use inside another program, but every time I do anything to
it I end up breaking it.  I am still very new at Python.  I would like it
simplified quite a bit.  All I need is a variable set at the top with a 5
digit zipcode, so it is easy to modify.  I would like it to only return the
current temp followed by the current condition.  For example, when ran it
should return something like 78F | cloudy.  I need to remove the extended
forecast and the commandline arguments.  Can someone please help with this
and send me some info on how it was done? I thought it would be easy to do
but apparently I was wrong. *grin*  It would be even better if the whole
program could be simplified down to one function, but I am not sure that
will be possible.
Thanks for the help, and here is the code:
#! /usr/bin/python

"""
Fetches weather reports from Yahoo!

Written by Thomas Upton (http://thomas.fiveuptons.com/),
with contributions from Chris Lasher (http://igotgenes.blogspot.com/).

This code is licensed under a BY-NC-SA Creative Commons license.
http://creativecommons.org/licenses/by-nc-sa/3.0/us/
"""

import sys
import urllib
from optparse import OptionParser
from xml.dom.minidom import parse

# Yahoo!'s limit on the number of days they will forecast for
DAYS_LIMIT = 2
WEATHER_URL = 'http://xml.weather.yahoo.com/forecastrss?p=%s'
WEATHER_NS = 'http://xml.weather.yahoo.com/ns/rss/1.0'

def get_weather(zip_code, days):
  """
  Fetches weather report from Yahoo!

  :Parameters:
  -`zip_code`: A five digit US zip code.
  -`days`: number of days to obtain forecasts for

  :Returns:
  -`weather_data`: a dictionary of weather data

  """

  # Get the correct weather url.
  url = WEATHER_URL % zip_code

  # Parse the XML feed.
  dom = parse(urllib.urlopen(url))

  # Get the units of the current feed.
  yunits = dom.getElementsByTagNameNS(WEATHER_NS, 'units')[0]

  # Get the location of the specified zip code.
  ylocation = dom.getElementsByTagNameNS(WEATHER_NS, 'location')[0]

  # Get the currrent conditions.
  ycondition = dom.getElementsByTagNameNS(WEATHER_NS, 'condition')[0]

  # Hold the forecast in a hash.
  forecasts = []

  # Walk the DOM in order to find the forecast nodes.
  for i, node in enumerate(
          dom.getElementsByTagNameNS(WEATHER_NS,'forecast')):
      # Stop if the number of obtained forecasts equals the number of
requested days
      if i + 1 > days:
          break
      else:
          # Insert the forecast into the forcast dictionary.
          forecasts.append (
              {
                  'date': node.getAttribute('date'),
                  'low': node.getAttribute('low'),
                  'high': node.getAttribute('high'),
                  'condition': node.getAttribute('text')
              }
          )

  # Return a dictionary of the weather that we just parsed.
  weather_data = {
      'current_condition': ycondition.getAttribute('text'),
      'current_temp': ycondition.getAttribute('temp'),
      'forecasts': forecasts,
      'units': yunits.getAttribute('temperature'),
      'city': ylocation.getAttribute('city'),
      'region': ylocation.getAttribute('region'),
  }
  
  return weather_data

def create_report(weather_data, options):
  """
  Constructs a weather report as a string.

  :Parameters:
  -`weather_data`: a dictionary of weather data
  -`options`: options to determine output selections

  :Returns:
  -`report_str`: a formatted string reporting weather

  """

  report = []
  
  if options.location:
      if options.verbose:
          # Add the location header.
          report.append("Location:")

      # Add the location.
      location_string = "%(city)s, %(region)s\n" % weather_data
      report.append(location_string)

  if (not options.nocurr):
      if options.verbose:
          # Add current conditions header.
          report.append("Current conditions:")

      # Add the current weather.
      currstr = "%(current_temp)s%(units)s | %(current_condition)s \n" %
weather_data
      report.append(currstr)

  if (options.forecast > 0):
    if options.verbose:
        # Add the forecast header.
        report.append("Forecast:")

    # Add the forecasts.
    for forecast in weather_data['forecasts']:
      
        forecast['units'] = weather_data['units']
      
        forecast_str = """\
  %(date)s
    Low: %(low)s%(units)s
    High: %(high)s%(units)s
    Condition: %(condition)s
  """ % forecast

        report.append(forecast_str)

  report_str = "\n".join(report)
  
  return report_str

def create_cli_parser():
  """Creates a command line interface parser."""

  usage = (
      "%prog [options] zip_code",
      __doc__,
      """\
Arguments:
  ZIPCODE: The ZIP code for the region of interest.
"""
  )
  
  usage = "\n\n".join(usage)
  
  cli_parser = OptionParser(usage)
  
  # Add the CLI options
  cli_parser.add_option('-c', '--nocurr', action='store_true',
      help="Suppress reporting the current weather conditions"
  )
  
  cli_parser.add_option('-f', '--forecast', action='store', type='int',
      help="Show the forecast for DAYS days", metavar="DAYS")
  
  cli_parser.add_option('-l', '--location', action='store_true',
      help="Give the location of the weather"
  )
  
  cli_parser.add_option('-v', '--verbose', action='store_true',
      help="Print the weather section headers"
  )
  
  cli_parser.set_defaults(forecast=0)

  return cli_parser

def main(argv):

  # Create the command line parser.
  cli_parser = create_cli_parser()
  
  # Get the options and arguments.
  opts, args = cli_parser.parse_args(argv)

  # Check that an argument was passed.
  if len(args) < 1:
      cli_parser.error("Not enough arguments supplied.")

  # Check the zip code
  zip_code = args[0]
  
  if len(zip_code) != 5 or not zip_code.isdigit():
      cli_parser.error("ZIP code must be 5 digits")
  
  if opts.forecast > DAYS_LIMIT or opts.forecast < 0:
     cli_parser.error("Days to forecast must be between 0 and %d" %
DAYS_LIMIT)

  # Get the weather.
  weather = get_weather(zip_code, opts.forecast)

  # Create the report.
  report = create_report(weather, opts)

  print report

if __name__ == "__main__":
  main(sys.argv[1:]) 

Other related posts: