Permalink
Browse files

Added main definition so it should work on Windows. Turned project in…

…to a package
  • Loading branch information...
ip2k committed Jul 14, 2011
1 parent d996082 commit 9f0224c354f1b29cc1a1ceea41c9ff7bab259a0a
Showing with 214 additions and 0 deletions.
  1. +63 −0 LICENSE.txt
  2. +5 −0 MANIFEST
  3. +26 −0 README.txt
  4. BIN dist/pycliweather-0.3.tar.gz
  5. 0 pycliweather/__init__.py
  6. +111 −0 pycliweather/pycliweather.py
  7. +9 −0 setup.py
View

Large diffs are not rendered by default.

Oops, something went wrong.
View
@@ -0,0 +1,5 @@
+# file GENERATED by distutils, do NOT edit
+README.txt
+setup.py
+pycliweather/__init__.py
+pycliweather/pycliweather.py
View
@@ -0,0 +1,26 @@
+The problem: I want to look up the weather from wunderground from my terminal without opening up a web browser. I figured "hey, this should be easy / fun to do using Python!" -- WRONG! XML is always a pain to work with, and there is no *easy* way to get XML schema into a dict. Most people don't even use XML correctly; you should use JSON if you just have strings inside of XML tags and nothing more. Every API I've ever seen / worked with uses XML in this way, and so they could all replace it with the *much* easier to parse JSON.
+
+Update: You can now pass in the location as the first argument to the script.
+
+Update 2: You can use *any* location search format that wunderground supports; this includes zipcode, airport code, city name and state, etc.
+If Wunderground returns valid XML for your query, pycliweather will parse it; the searches are limited only by the Wunderground API.
+
+In the example below, I'm using 'dallas texas'. There is also a default specified in the code should a location not be passed.
+
+Anyway, here is what should come out when you run this:
+
+likwid@helios pycliweather(master)$ weather dallas texas
+Location: dallas+texas
+Sunrise: 6:18
+Sunset: 20:37
+Moon visible: 95%
+
+Friday - Partly Cloudy - 79F to 99F - 0% chance of rain
+Saturday - Partly Cloudy - 79F to 104F - 10% chance of rain
+Sunday - Partly Cloudy - 79F to 101F - 10% chance of rain
+Monday - Partly Cloudy - 77F to 99F - 10% chance of rain
+Tuesday - Chance of a Thunderstorm - 77F to 95F - 20% chance of rain
+Wednesday - Chance of a Thunderstorm - 76F to 92F - 30% chance of rain
+
+
+
Binary file not shown.
View
No changes.
@@ -0,0 +1,111 @@
+# ---- Config ----
+
+# set our default location
+# location can be one of (zipcode|airport code| city name) or anything that Wunderground supports for search.
+# if you're calling this script with the location as an arg, it has to be one word, so
+default_location = 48104
+
+# The functions could probably be a lot better, but I didn't write them.
+# Credit/blame goes to http://nonplatonic.com/ben.php?title=python_xml_to_dict_bow_to_my_recursive_g&more=1&c=1&tb=1&pb=1
+# :) thanks!
+
+# ---- Functions ----
+
+def xmltodict(xmlstring):
+ doc = xml.dom.minidom.parseString(xmlstring)
+ remove_whilespace_nodes(doc.documentElement)
+ return elementtodict(doc.documentElement)
+
+def elementtodict(parent):
+ child = parent.firstChild
+ if (not child):
+ return None
+ elif (child.nodeType == xml.dom.minidom.Node.TEXT_NODE):
+ return child.nodeValue
+
+ d={}
+ while child is not None:
+ if (child.nodeType == xml.dom.minidom.Node.ELEMENT_NODE):
+ try:
+ d[child.tagName]
+ except KeyError:
+ d[child.tagName]=[]
+ d[child.tagName].append(elementtodict(child))
+ child = child.nextSibling
+ return d
+
+def remove_whilespace_nodes(node, unlink=True):
+ remove_list = []
+ for child in node.childNodes:
+ if child.nodeType == xml.dom.Node.TEXT_NODE and not child.data.strip():
+ remove_list.append(child)
+ elif child.hasChildNodes():
+ remove_whilespace_nodes(child, unlink)
+ for node in remove_list:
+ node.parentNode.removeChild(node)
+ if unlink:
+ node.unlink()
+
+def getFullWeather(someLocation):
+ # open our XML feed URL from wunderground. Our query=default_location is already encoded in default_location.
+ feed = urllib2.urlopen('http://api.wunderground.com/auto/wui/geo/ForecastXML/index.xml?query=' + str(someLocation))
+
+ # read the feed into a huge string. the -1 means we're getting all the bytes, so we don't have to guess / calculate
+ feedxml = feed.read(-1)
+
+ # call the xmltodict on our huge XML string
+ return xmltodict(feedxml)
+
+# ---- Main ----
+if __name__ == "__main__":
+ import xml.dom.minidom
+ import urllib2
+ import sys
+
+
+ # change our default location to the first arg passed to our script, if one is passed.
+ # if not, it'll throw an index or value error, which we catch and proceed to just use the default location.
+ try:
+ location = sys.argv[1:]
+ location = ' '.join(location)
+ # ghetto hack instead of urlencode because urlencode sucks in this case
+ location = location.replace(' ', '+')
+ except (IndexError, ValueError):
+ print "Invalid location passed; using default location:", default_location
+ location = default_location
+ pass
+
+ fullweather = getFullWeather(location)
+ # this gets you up to each day. After that, have to dig into each to get whatever data you want.
+ try:
+ weather = fullweather['simpleforecast'][0]['forecastday']
+ except (TypeError):
+ if len(location) > 0:
+ print "Invalid location passed; using default location:", default_location
+ location = default_location
+ fullweather = getFullWeather(location)
+ weather = fullweather['simpleforecast'][0]['forecastday']
+ pass
+
+
+ # range(len(weather)) iterates through each day. The rest should be self-explanatory.
+ # yes, the schema is confusing and stupid. XML sucks for simple stuff like this; use JSON for your APIs!
+
+ sunrise_hour = fullweather['moon_phase'][0]['sunrise'][0]['hour'][0]
+ sunrise_minute = fullweather['moon_phase'][0]['sunrise'][0]['minute'][0]
+ sunset_hour = fullweather['moon_phase'][0]['sunset'][0]['hour'][0]
+ sunset_minute = fullweather['moon_phase'][0]['sunset'][0]['minute'][0]
+ moon = fullweather['moon_phase'][0]['percentIlluminated'][0]
+
+ print 'Location:', location
+ print 'Sunrise:', sunrise_hour + ':' + sunrise_minute
+ print 'Sunset:', sunset_hour + ':' + sunset_minute
+ print 'Moon visible:', moon + '% \n'
+
+ for i in range(len(weather)):
+ conditions = weather[i]['conditions'][0]
+ dayname = weather[i]['date'][0]['weekday'][0]
+ high = weather[i]['high'][0]['fahrenheit'][0]
+ low = weather[i]['low'][0]['fahrenheit'][0]
+ precip = weather[i]['pop'][0]
+ print dayname, '-', conditions, '-', low + 'F to', high + 'F -', precip + '% chance of rain'
View
@@ -0,0 +1,9 @@
+from distutils.core import setup
+
+setup(
+ name='pycliweather',
+ version='0.3',
+ packages=['pycliweather',],
+ license='Attribution-NonCommercial-ShareAlike 3.0 Unported',
+ long_description=open('README.txt').read(),
+)

0 comments on commit 9f0224c

Please sign in to comment.