RE: Help with a Python Program

  • From: "Ken Perry" <whistler@xxxxxxxxxxxxx>
  • To: <programmingblind@xxxxxxxxxxxxx>
  • Date: Thu, 9 Oct 2008 22:25:05 -0500

 
 
Nod neither of those sound like something I would run on this device.  I
like just SAX or the TEMPLATE sax for the kind of thing we are doing.  We
are not doing lots of XML but I found using the trees or dom really slows
down things because of both memory and processing power.  Some things are
just made more for ease in use than speed.
 
Ken 

  _____  

From: programmingblind-bounce@xxxxxxxxxxxxx
[mailto:programmingblind-bounce@xxxxxxxxxxxxx] On Behalf Of Jim Dunleavy
Sent: Thursday, October 09, 2008 11:20 AM
To: programmingblind@xxxxxxxxxxxxx
Subject: Re: Help with a Python Program


Hi Ken,
 
Well lxml has 3 MB of library in native code as wel as the bindings
in Python.  I think it wraps the popular libxml2 library.
Its XPath support works off of in-memory trees.
Probably not what you want if space is tight or you're parsing really
big XML files.
 
BeautifulSoup is smaller but does more work in pure Python so is slower
than lxml.  It works from in-memory trees.
I like its conciseness, its flexibility e.g. being able to search for
text nodes and attribute values by regular expression, and it can
handle the dirtiest of HTML you can throw at it.
 
--Jim
 
----- Original Message ----- 
From: Ken Perry <mailto:whistler@xxxxxxxxxxxxx>  
To: programmingblind@xxxxxxxxxxxxx 
Sent: Thursday, October 09, 2008 12:56 PM
Subject: RE: Help with a Python Program

 
 
Yes but are they light weight enough for a small device that already ahs to
many libraries installed.  I am using the sax because it is on all devices
yes I have to do a bit of code writing but its worth it for the speed.  I
will have a look at the two libraries but I don't know about adding more
libraries for the device I am working on.
 
Ken

  _____  

From: programmingblind-bounce@xxxxxxxxxxxxx
[mailto:programmingblind-bounce@xxxxxxxxxxxxx] On Behalf Of Jim Dunleavy
Sent: Wednesday, October 08, 2008 11:17 AM
To: programmingblind@xxxxxxxxxxxxx
Subject: Re: Help with a Python Program


Hi,
 
I use the BeautifulSoup library from www.crummy.com.
The API is much more concise than calling those long-winded DOM
functions.
e.g.
cond = tree.find('yweather:condition')
result = '%s, %s' % (cond['temp'], cond['text'])
 
Or if you want speed, check out the lxml package and xpath.
 
--Jim
 
----- Original Message ----- 
From: Ken Perry <mailto:whistler@xxxxxxxxxxxxx>  
To: programmingblind@xxxxxxxxxxxxx 
Sent: Wednesday, October 08, 2008 5:11 AM
Subject: RE: Help with a Python Program

 
 
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: