pywapi-0.3.6/examples/pywapi-countries-example.py000664 001750 001750 00000000241 12171145451 023344 0ustar00jtaskerjtasker000000 000000 #!/usr/bin/env python import pywapi import pprint pp = pprint.PrettyPrinter(indent=4) countries = pywapi.get_countries_from_google('en') pp.pprint(countries) pywapi-0.3.6/examples/pywapi-yahoo-example.py000664 001750 001750 00000000245 12171145451 022454 0ustar00jtaskerjtasker000000 000000 #!/usr/bin/env python import pywapi import pprint pp = pprint.PrettyPrinter(indent=4) result = pywapi.get_weather_from_yahoo('10001', 'metric') pp.pprint(result) pywapi-0.3.6/examples/pywapi-noaa-example.py000664 001750 001750 00000000230 12171145451 022245 0ustar00jtaskerjtasker000000 000000 #!/usr/bin/env python import pywapi import pprint pp = pprint.PrettyPrinter(indent=4) result = pywapi.get_weather_from_noaa('KJFK') pp.pprint(result) pywapi-0.3.6/examples/pywapi-cities-example.py000664 001750 001750 00000000277 12171145451 022622 0ustar00jtaskerjtasker000000 000000 #!/usr/bin/env python import pywapi import pprint pp = pprint.PrettyPrinter(indent=4) cities = pywapi.get_cities_from_google('fr', 'de') # or (country = 'fr', hl = 'de') pp.pprint(cities) pywapi-0.3.6/pywapi.py000664 001750 001750 00000106463 12211476244 016103 0ustar00jtaskerjtasker000000 000000 #!/usr/bin/python # -*- coding: utf-8 -*- ### BEGIN LICENSE #Copyright (c) 2009 Eugene Kaznacheev #Copyright (c) 2013 Joshua Tasker #Permission is hereby granted, free of charge, to any person #obtaining a copy of this software and associated documentation #files (the "Software"), to deal in the Software without #restriction, including without limitation the rights to use, #copy, modify, merge, publish, distribute, sublicense, and/or sell #copies of the Software, and to permit persons to whom the #Software is furnished to do so, subject to the following #conditions: #The above copyright notice and this permission notice shall be #included in all copies or substantial portions of the Software. #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, #EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES #OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND #NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT #HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, #WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING #FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR #OTHER DEALINGS IN THE SOFTWARE. ### END LICENSE """ Fetches weather reports from Yahoo! Weather, Weather.com and NOAA """ __version__ = "0.3.6" try: # Python 3 imports from urllib.request import urlopen from urllib.parse import quote from urllib.parse import urlencode from urllib.error import URLError # needed for code to work on Python3 xrange = range unicode = str except ImportError: # Python 2 imports from urllib2 import urlopen from urllib import quote from urllib import urlencode from urllib2 import URLError import sys import re from math import pow from xml.dom import minidom import json try: from unidecode import unidecode except ImportError: pass GOOGLE_COUNTRIES_URL = 'http://www.google.com/ig/countries?output=xml&hl=%s' GOOGLE_CITIES_URL = 'http://www.google.com/ig/cities?output=xml&' + \ 'country=%s&hl=%s' YAHOO_WEATHER_URL = 'http://xml.weather.yahoo.com/forecastrss/%s_%s.xml' YAHOO_WEATHER_NS = 'http://xml.weather.yahoo.com/ns/rss/1.0' NOAA_WEATHER_URL = 'http://www.weather.gov/xml/current_obs/%s.xml' WEATHER_COM_URL = 'http://xml.weather.com/weather/local/%s?' + \ 'par=1138276742&key=15ee9c789ccd70f5&' + \ 'unit=%s&dayf=5&cc=*' LOCID_SEARCH_URL = 'http://xml.weather.com/search/search?where=%s' WOEID_SEARCH_URL = 'http://query.yahooapis.com/v1/public/yql' WOEID_QUERY_STRING = 'select line1, line2, line3, line4, ' + \ 'woeid from geo.placefinder where text="%s"' #WXUG_BASE_URL = 'http://api.wunderground.com/auto/wui/geo' #WXUG_FORECAST_URL = WXUG_BASE_URL + '/ForecastXML/index.xml?query=%s' #WXUG_CURRENT_URL = WXUG_BASE_URL + '/WXCurrentObXML/index.xml?query=%s' #WXUG_GEOLOOKUP_URL = WXUG_BASE_URL + '/GeoLookupXML/index.xml?query=%s' #WXUG_ALERTS_URL = WXUG_BASE_URL + '/AlertsXML/index.xml?query=%s' class WindUnits: """Class for available wind unit systems""" MPS = 1 MPH = 2 BEAUFORT = 3 KPH = 4 KNOTS = 5 def get_weather_from_weather_com(location_id, units = 'metric'): """Fetches weather report from Weather.com Parameters: location_id: A five digit US zip code or location ID. To find your location ID, use function get_loc_id_from_weather_com(). units: type of units. 'metric' for metric and 'imperial' for non-metric. Note that choosing metric units changes all the weather units to metric. For example, wind speed will be reported as kilometers per hour and barometric pressure as millibars. Returns: weather_data: a dictionary of weather data that exists in XML feed. """ location_id = quote(location_id) if units == 'metric': unit = 'm' elif units == 'imperial' or units == '': # for backwards compatibility unit = '' else: unit = 'm' # fallback to metric url = WEATHER_COM_URL % (location_id, unit) try: handler = urlopen(url) except URLError: return {'error': 'Could not connect to Weather.com'} if sys.version > '3': # Python 3 content_type = dict(handler.getheaders())['Content-Type'] else: # Python 2 content_type = handler.info().dict['content-type'] try: charset = re.search('charset\=(.*)', content_type).group(1) except AttributeError: charset = 'utf-8' if charset.lower() != 'utf-8': xml_response = handler.read().decode(charset).encode('utf-8') else: xml_response = handler.read() dom = minidom.parseString(xml_response) handler.close() try: weather_dom = dom.getElementsByTagName('weather')[0] except IndexError: error_data = {'error': dom.getElementsByTagName('error')[ 0].getElementsByTagName('err')[0].firstChild.data} dom.unlink() return error_data key_map = {'head':'units', 'ut':'temperature', 'ud':'distance', 'us':'speed', 'up':'pressure', 'ur':'rainfall', 'loc':'location', 'dnam':'name', 'lat':'lat', 'lon':'lon', 'cc':'current_conditions', 'lsup':'last_updated', 'obst':'station', 'tmp':'temperature', 'flik':'feels_like', 't':'text', 'icon':'icon', 'bar':'barometer', 'r':'reading', 'd':'direction', 'wind':'wind', 's':'speed', 'gust':'gust', 'hmid':'humidity', 'vis':'visibility', 'uv':'uv', 'i':'index', 'dewp':'dewpoint', 'moon':'moon_phase', 'hi':'high', 'low':'low', 'sunr':'sunrise', 'suns':'sunset', 'bt':'brief_text', 'ppcp':'chance_precip'} data_structure = {'head': ('ut', 'ud', 'us', 'up', 'ur'), 'loc': ('dnam', 'lat', 'lon'), 'cc': ('lsup', 'obst', 'tmp', 'flik', 't', 'icon', 'hmid', 'vis', 'dewp')} cc_structure = {'bar': ('r','d'), 'wind': ('s','gust','d','t'), 'uv': ('i','t'), 'moon': ('icon','t')} # sanity check, skip missing items try: for (tag, list_of_tags2) in data_structure.items(): for tag2 in list_of_tags2: if weather_dom.getElementsByTagName(tag)[0].childNodes.length == 0: data_structure[tag] = [] except IndexError: error_data = {'error': 'Error parsing Weather.com response. Full response: %s' % xml_response} return error_data try: weather_data = {} for (tag, list_of_tags2) in data_structure.items(): key = key_map[tag] weather_data[key] = {} for tag2 in list_of_tags2: key2 = key_map[tag2] weather_data[key][key2] = weather_dom.getElementsByTagName( tag)[0].getElementsByTagName(tag2)[0].firstChild.data except IndexError: error_data = {'error': 'Error parsing Weather.com response. Full response: %s' % xml_response} return error_data if weather_dom.getElementsByTagName('cc')[0].childNodes.length > 0: cc_dom = weather_dom.getElementsByTagName('cc')[0] for (tag, list_of_tags2) in cc_structure.items(): key = key_map[tag] weather_data['current_conditions'][key] = {} for tag2 in list_of_tags2: key2 = key_map[tag2] weather_data['current_conditions'][key][key2] = cc_dom.getElementsByTagName( tag)[0].getElementsByTagName(tag2)[0].firstChild.data forecasts = [] if len(weather_dom.getElementsByTagName('dayf')) > 0: time_of_day_map = {'d':'day', 'n':'night'} for forecast in weather_dom.getElementsByTagName('dayf')[0].getElementsByTagName('day'): tmp_forecast = {} tmp_forecast['day_of_week'] = forecast.getAttribute('t') tmp_forecast['date'] = forecast.getAttribute('dt') for tag in ('hi', 'low', 'sunr', 'suns'): key = key_map[tag] tmp_forecast[key] = forecast.getElementsByTagName( tag)[0].firstChild.data for part in forecast.getElementsByTagName('part'): time_of_day = time_of_day_map[part.getAttribute('p')] tmp_forecast[time_of_day] = {} for tag2 in ('icon', 't', 'bt', 'ppcp', 'hmid'): key2 = key_map[tag2] tmp_forecast[time_of_day][ key2] = part.getElementsByTagName(tag2)[0].firstChild.data tmp_forecast[time_of_day]['wind'] = {} for tag2 in ('s', 'gust', 'd', 't'): key2 = key_map[tag2] tmp_forecast[time_of_day]['wind'][key2] = part.getElementsByTagName( 'wind')[0].getElementsByTagName(tag2)[0].firstChild.data forecasts.append(tmp_forecast) weather_data['forecasts'] = forecasts dom.unlink() return weather_data def get_weather_from_google(location_id, hl = ''): """Fetches weather report from Google. No longer functional, since Google discontinued their Weather API as of Sep 2012. Method retained for backwards compatibility. Returns: weather_data: a dictionary containing only the key 'error' """ weather_data = {'error': 'The Google Weather API has been ' + \ 'discontinued as of September 2012.'} return weather_data def get_countries_from_google(hl = ''): """Get list of countries in specified language from Google Parameters: hl: the language parameter (language code). Default value is empty string, in this case Google will use English. Returns: countries: a list of elements(all countries that exists in XML feed). Each element is a dictionary with 'name' and 'iso_code' keys. For example: [{'iso_code': 'US', 'name': 'USA'}, {'iso_code': 'FR', 'name': 'France'}] """ url = GOOGLE_COUNTRIES_URL % hl try: handler = urlopen(url) except URLError: return [{'error':'Could not connect to Google'}] if sys.version > '3': # Python 3 content_type = dict(handler.getheaders())['Content-Type'] else: # Python 2 content_type = handler.info().dict['content-type'] try: charset = re.search('charset\=(.*)', content_type).group(1) except AttributeError: charset = 'utf-8' if charset.lower() != 'utf-8': xml_response = handler.read().decode(charset).encode('utf-8') else: xml_response = handler.read() dom = minidom.parseString(xml_response) handler.close() countries = [] countries_dom = dom.getElementsByTagName('country') for country_dom in countries_dom: country = {} country['name'] = country_dom.getElementsByTagName( 'name')[0].getAttribute('data') country['iso_code'] = country_dom.getElementsByTagName( 'iso_code')[0].getAttribute('data') countries.append(country) dom.unlink() return countries def get_cities_from_google(country_code, hl = ''): """Get list of cities of necessary country in specified language from Google Parameters: country_code: code of the necessary country. For example 'de' or 'fr'. hl: the language parameter (language code). Default value is empty string, in this case Google will use English. Returns: cities: a list of elements(all cities that exists in XML feed). Each element is a dictionary with 'name', 'latitude_e6' and 'longitude_e6' keys. For example: [{'longitude_e6': '1750000', 'name': 'Bourges', 'latitude_e6': '47979999'}] """ url = GOOGLE_CITIES_URL % (country_code.lower(), hl) try: handler = urlopen(url) except URLError: return [{'error':'Could not connect to Google'}] if sys.version > '3': # Python 3 content_type = dict(handler.getheaders())['Content-Type'] else: # Python 2 content_type = handler.info().dict['content-type'] try: charset = re.search('charset\=(.*)', content_type).group(1) except AttributeError: charset = 'utf-8' if charset.lower() != 'utf-8': xml_response = handler.read().decode(charset).encode('utf-8') else: xml_response = handler.read() dom = minidom.parseString(xml_response) handler.close() cities = [] cities_dom = dom.getElementsByTagName('city') for city_dom in cities_dom: city = {} city['name'] = city_dom.getElementsByTagName( 'name')[0].getAttribute('data') city['latitude_e6'] = city_dom.getElementsByTagName( 'latitude_e6')[0].getAttribute('data') city['longitude_e6'] = city_dom.getElementsByTagName( 'longitude_e6')[0].getAttribute('data') cities.append(city) dom.unlink() return cities def get_weather_from_yahoo(location_id, units = 'metric'): """Fetches weather report from Yahoo! Weather Parameters: location_id: A five digit US zip code or location ID. To find your location ID, use function get_location_ids(). units: type of units. 'metric' for metric and 'imperial' for non-metric. Note that choosing metric units changes all the weather units to metric. For example, wind speed will be reported as kilometers per hour and barometric pressure as millibars. Returns: weather_data: a dictionary of weather data that exists in XML feed. See http://developer.yahoo.com/weather/#channel """ location_id = quote(location_id) if units == 'metric': unit = 'c' elif units == 'imperial' or units == '': # for backwards compatibility unit = 'f' else: unit = 'c' # fallback to metric url = YAHOO_WEATHER_URL % (location_id, unit) try: handler = urlopen(url) except URLError: return {'error': 'Could not connect to Yahoo! Weather'} if sys.version > '3': # Python 3 content_type = dict(handler.getheaders())['Content-Type'] else: # Python 2 content_type = handler.info().dict['content-type'] try: charset = re.search('charset\=(.*)', content_type).group(1) except AttributeError: charset = 'utf-8' if charset.lower() != 'utf-8': xml_response = handler.read().decode(charset).encode('utf-8') else: xml_response = handler.read() dom = minidom.parseString(xml_response) handler.close() weather_data = {} try: weather_data['title'] = dom.getElementsByTagName( 'title')[0].firstChild.data weather_data['link'] = dom.getElementsByTagName( 'link')[0].firstChild.data except IndexError: error_data = {'error': dom.getElementsByTagName('item')[ 0].getElementsByTagName('title')[0].firstChild.data} dom.unlink() return error_data ns_data_structure = { 'location': ('city', 'region', 'country'), 'units': ('temperature', 'distance', 'pressure', 'speed'), 'wind': ('chill', 'direction', 'speed'), 'atmosphere': ('humidity', 'visibility', 'pressure', 'rising'), 'astronomy': ('sunrise', 'sunset'), 'condition': ('text', 'code', 'temp', 'date') } for (tag, attrs) in ns_data_structure.items(): weather_data[tag] = xml_get_ns_yahoo_tag( dom, YAHOO_WEATHER_NS, tag, attrs ) weather_data['geo'] = {} try: weather_data['geo']['lat'] = dom.getElementsByTagName( 'geo:lat')[0].firstChild.data weather_data['geo']['long'] = dom.getElementsByTagName( 'geo:long')[0].firstChild.data except AttributeError: weather_data['geo']['lat'] = unicode() weather_data['geo']['long'] = unicode() weather_data['condition']['title'] = dom.getElementsByTagName( 'item')[0].getElementsByTagName('title')[0].firstChild.data weather_data['html_description'] = dom.getElementsByTagName( 'item')[0].getElementsByTagName('description')[0].firstChild.data forecasts = [] for forecast in dom.getElementsByTagNameNS(YAHOO_WEATHER_NS, 'forecast'): forecasts.append(xml_get_attrs(forecast,('day', 'date', 'low', 'high', 'text', 'code'))) weather_data['forecasts'] = forecasts dom.unlink() return weather_data def get_everything_from_yahoo(country_code, cities): """Get all weather data from yahoo for a specific country. Parameters: country_code: A four letter code of the necessary country. For example 'GMXX' or 'FRXX'. cities: The maximum number of cities for which to get data. Returns: weather_reports: A dictionary containing weather data for each city. """ city_codes = yield_all_country_city_codes_yahoo(country_code, cities) weather_reports = {} for city_c in city_codes: weather_data = get_weather_from_yahoo(city_c) if ('error' in weather_data): return weather_data city = weather_data['location']['city'] weather_reports[city] = weather_data return weather_reports def yield_all_country_city_codes_yahoo(country_code, cities): """Yield all cities codes for a specific country. Parameters: country_code: A four letter code of the necessary country. For example 'GMXX' or 'FRXX'. cities: The maximum number of cities to yield. Returns: country_city_codes: A generator containing the city codes. """ # cities stands for the number of available cities for i in range(1, cities + 1): yield ''.join([country_code, (4 - len(str(i))) * '0', str(i)]) def get_weather_from_noaa(station_id): """Fetches weather report from NOAA: National Oceanic and Atmospheric Administration (United States) Parameter: station_id: the ID of the weather station near the desired location To find your station ID, perform the following steps: 1. Open this URL: http://www.weather.gov/xml/current_obs/seek.php?state=az&Find=Find 2. Select the necessary state state. Click 'Find'. 3. Find the necessary station in the 'Observation Location' column. 4. The station ID is in the URL for the weather page for that station. For example if the weather page is http://weather.noaa.gov/weather/current/KPEO.html -- the station ID is KPEO. Another way to get the station ID: use the 'Weather.location2station' function of this library: http://code.google.com/p/python-weather/ Returns: weather_data: a dictionary of weather data that exists in XML feed. ( useful icons: http://www.weather.gov/xml/current_obs/weather.php ) """ station_id = quote(station_id) url = NOAA_WEATHER_URL % (station_id) try: handler = urlopen(url) except URLError: return {'error': 'Could not connect to NOAA'} if sys.version > '3': # Python 3 content_type = dict(handler.getheaders())['Content-Type'] else: # Python 2 content_type = handler.info().dict['content-type'] try: charset = re.search('charset\=(.*)', content_type).group(1) except AttributeError: charset = 'utf-8' if charset.lower() != 'utf-8': xml_response = handler.read().decode(charset).encode('utf-8') else: xml_response = handler.read() dom = minidom.parseString(xml_response) handler.close() data_structure = ('suggested_pickup', 'suggested_pickup_period', 'location', 'station_id', 'latitude', 'longitude', 'observation_time', 'observation_time_rfc822', 'weather', 'temperature_string', 'temp_f', 'temp_c', 'relative_humidity', 'wind_string', 'wind_dir', 'wind_degrees', 'wind_mph', 'wind_gust_mph', 'pressure_string', 'pressure_mb', 'pressure_in', 'dewpoint_string', 'dewpoint_f', 'dewpoint_c', 'heat_index_string', 'heat_index_f', 'heat_index_c', 'windchill_string', 'windchill_f', 'windchill_c', 'icon_url_base', 'icon_url_name', 'two_day_history_url', 'ob_url' ) weather_data = {} current_observation = dom.getElementsByTagName('current_observation')[0] for tag in data_structure: try: weather_data[tag] = current_observation.getElementsByTagName( tag)[0].firstChild.data except IndexError: pass dom.unlink() return weather_data def xml_get_ns_yahoo_tag(dom, ns, tag, attrs): """Parses the necessary tag and returns the dictionary with values Parameters: dom: DOM ns: namespace tag: necessary tag attrs: tuple of attributes Returns: a dictionary of elements """ element = dom.getElementsByTagNameNS(ns, tag)[0] return xml_get_attrs(element,attrs) def xml_get_attrs(xml_element, attrs): """Returns the list of necessary attributes Parameters: element: xml element attrs: tuple of attributes Returns: a dictionary of elements """ result = {} for attr in attrs: result[attr] = xml_element.getAttribute(attr) return result def wind_direction(degrees): """ Convert wind degrees to direction """ try: degrees = int(degrees) except ValueError: return '' if degrees < 23 or degrees >= 338: return 'N' elif degrees < 68: return 'NE' elif degrees < 113: return 'E' elif degrees < 158: return 'SE' elif degrees < 203: return 'S' elif degrees < 248: return 'SW' elif degrees < 293: return 'W' elif degrees < 338: return 'NW' def wind_beaufort_scale(value, wind_units = WindUnits.KPH): """Convert wind speed value to Beaufort number (0-12) The Beaufort wind force scale is an empirical measure that relates wind speed to observed conditions at sea or on land. Parameters: value: wind speed value to convert wind_units: unit system of value, defaults to km/h Returns: a string containing the Beaufort number from 0 to 12 """ if wind_units == WindUnits.BEAUFORT: return str(value) try: value = float(value) except ValueError: return '' if value < 0.0: return '' if wind_units == WindUnits.KPH: if value < 1: # Calm return '0' elif value <= 5.5: # Light air return '1' elif value <= 11: # Light breeze return '2' elif value <= 19: # Gentle breeze return '3' elif value <= 28: # Moderate breeze return '4' elif value <= 38: # Fresh breeze return '5' elif value <= 49: # Strong breeze return '6' elif value <= 61: # High wind, moderate gale, near gale return '7' elif value <= 74: # Gale, fresh gale return '8' elif value <= 88: # Strong gale return '9' elif value <= 102: # Storm, whole gale return '10' elif value <= 117: # Violent storm return '11' else: # Hurricane return '12' if wind_units == WindUnits.MPH: if value < 1: return '0' elif value <= 3: return '1' elif value <= 7: return '2' elif value <= 12: return '3' elif value <= 17: return '4' elif value <= 24: return '5' elif value <= 30: return '6' elif value <= 38: return '7' elif value <= 46: return '8' elif value <= 54: return '9' elif value <= 63: return '10' elif value <= 73: return '11' else: return '12' if wind_units == WindUnits.MPS: if value < 0.3: return '0' elif value <= 1.5: return '1' elif value <= 3.4: return '2' elif value <= 5.4: return '3' elif value <= 7.9: return '4' elif value <= 10.7: return '5' elif value <= 13.8: return '6' elif value <= 17.1: return '7' elif value <= 20.7: return '8' elif value <= 24.4: return '9' elif value <= 28.4: return '10' elif value <= 32.6: return '11' else: return '12' if wind_units == WindUnits.KNOTS: if value < 1: return '0' if value <= 3: return '1' if value <= 6: return '2' if value <= 10: return '3' if value <= 16: return '4' if value <= 21: return '5' if value <= 27: return '6' if value <= 33: return '7' if value <= 40: return '8' if value <= 47: return '9' if value <= 55: return '10' if value <= 63: return '11' else: return '12' def get_wind_direction(degrees): """ Same as wind_direction """ return wind_direction(degrees) def getText(nodelist): rc = "" for node in nodelist: if node.nodeType == node.TEXT_NODE: rc = rc + node.data return rc def get_location_ids(search_string): """Get location IDs for place names matching a specified string. Same as get_loc_id_from_weather_com() but different return format. Parameters: search_string: Plaintext string to match to available place names. For example, a search for 'Los Angeles' will return matches for the city of that name in California, Chile, Cuba, Nicaragua, etc as well as 'East Los Angeles, CA', 'Lake Los Angeles, CA', etc. Returns: location_ids: A dictionary containing place names keyed to location ID """ loc_id_data = get_loc_id_from_weather_com(search_string) if 'error' in loc_id_data: return loc_id_data location_ids = {} for i in xrange(loc_id_data['count']): location_ids[loc_id_data[i][0]] = loc_id_data[i][1] return location_ids def get_loc_id_from_weather_com(search_string): """Get location IDs for place names matching a specified string. Same as get_location_ids() but different return format. Parameters: search_string: Plaintext string to match to available place names. For example, a search for 'Los Angeles' will return matches for the city of that name in California, Chile, Cuba, Nicaragua, etc as well as 'East Los Angeles, CA', 'Lake Los Angeles, CA', etc. Returns: loc_id_data: A dictionary of tuples in the following format: {'count': 2, 0: (LOCID1, Placename1), 1: (LOCID2, Placename2)} """ # Weather.com stores place names as ascii-only, so convert if possible try: # search_string = unidecode(search_string.encode('utf-8')) search_string = unidecode(search_string) except NameError: pass url = LOCID_SEARCH_URL % quote(search_string) try: handler = urlopen(url) except URLError: return {'error': 'Could not connect to server'} if sys.version > '3': # Python 3 content_type = dict(handler.getheaders())['Content-Type'] else: # Python 2 content_type = handler.info().dict['content-type'] try: charset = re.search('charset\=(.*)', content_type).group(1) except AttributeError: charset = 'utf-8' if charset.lower() != 'utf-8': xml_response = handler.read().decode(charset).encode('utf-8') else: xml_response = handler.read() dom = minidom.parseString(xml_response) handler.close() loc_id_data = {} try: num_locs = 0 for loc in dom.getElementsByTagName('search')[0].getElementsByTagName('loc'): loc_id = loc.getAttribute('id') # loc id place_name = loc.firstChild.data # place name loc_id_data[num_locs] = (loc_id, place_name) num_locs += 1 loc_id_data['count'] = num_locs except IndexError: error_data = {'error': 'No matching Location IDs found'} return error_data finally: dom.unlink() return loc_id_data def get_where_on_earth_ids(search_string): """Get Yahoo 'Where On Earth' ID for the place names that best match the specified string. Same as get_woeid_from_yahoo() but different return format. Parameters: search_string: Plaintext string to match to available place names. Place can be a city, country, province, airport code, etc. Yahoo returns the 'Where On Earth' ID (WOEID) for the place name(s) that is the best match to the full string. For example, 'Paris' will match 'Paris, France', 'Deutschland' will match 'Germany', 'Ontario' will match 'Ontario, Canada', 'SFO' will match 'San Francisco International Airport', etc. Returns: where_on_earth_ids: A dictionary containing place names keyed to WOEID. """ woeid_data = get_woeid_from_yahoo(search_string) if 'error' in woeid_data: return woeid_data where_on_earth_ids = {} for i in xrange(woeid_data['count']): where_on_earth_ids[woeid_data[i][0]] = woeid_data[i][1] return where_on_earth_ids def get_woeid_from_yahoo(search_string): """Get Yahoo WOEID for the place names that best match the specified string. Same as get_where_on_earth_ids() but different return format. Parameters: search_string: Plaintext string to match to available place names. Place can be a city, country, province, airport code, etc. Yahoo returns the WOEID for the place name(s) that is the best match to the full string. For example, 'Paris' will match 'Paris, France', 'Deutschland' will match 'Germany', 'Ontario' will match 'Ontario, Canada', 'SFO' will match 'San Francisco International Airport', etc. Returns: woeid_data: A dictionary of tuples in the following format: {'count': 2, 0: (WOEID1, Placename1), 1: (WOEID2, Placename2)} """ ## This uses Yahoo's YQL tables to directly query Yahoo's database, e.g. ## http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20geo.placefinder%20where%20text%3D%22New%20York%22 if sys.version > '3': # Python 3 encoded_string = search_string else: # Python 2 encoded_string = search_string.encode('utf-8') params = {'q': WOEID_QUERY_STRING % encoded_string, 'format': 'json'} url = '?'.join((WOEID_SEARCH_URL, urlencode(params))) try: handler = urlopen(url) except URLError: return {'error': 'Could not connect to server'} if sys.version > '3': # Python 3 content_type = dict(handler.getheaders())['Content-Type'] else: # Python 2 content_type = handler.info().dict['content-type'] try: charset = re.search('charset\=(.*)', content_type).group(1) except AttributeError: charset = 'utf-8' if charset.lower() != 'utf-8': json_response = handler.read().decode(charset).encode('utf-8') else: json_response = handler.read() handler.close() yahoo_woeid_result = json.loads(json_response) try: result = yahoo_woeid_result['query']['results']['Result'] except KeyError: # On error, returned JSON evals to dictionary with one key, 'error' return yahoo_woeid_result except TypeError: return {'error': 'No matching place names found'} woeid_data = {} woeid_data['count'] = yahoo_woeid_result['query']['count'] for i in xrange(yahoo_woeid_result['query']['count']): try: place_data = result[i] except KeyError: place_data = result name_lines = [place_data[tag] for tag in ['line1','line2','line3','line4'] if place_data[tag] is not None] place_name = ', '.join(name_lines) woeid_data[i] = (place_data['woeid'], place_name) return woeid_data def heat_index(temperature, humidity, units = 'metric'): """Calculate Heat Index for the specified temperature and humidity The formula below approximates the heat index in degrees Fahrenheit, to within ±1.3 °F. It is the result of a multivariate fit (temperature equal to or greater than 80°F and relative humidity equal to or greater than 40%) to a model of the human body. Heat Index = c_1 + (c_2 * T) + (c_3 * R) + (c_4 * T * R) + (c_5 * T^2) + (c_6 * R^2) + (c_7 * T^2 * R) + (c_8 * T * R^2) + (c_9 * T^2 * R^2) where: T = ambient dry-bulb temperature (in degrees Fahrenheit) R = relative humidity (percentage value between 0 and 100) Parameters: temperature: air temperature in specified units humidity: relative humidity (a percentage) at specified air temperature units: type of units. 'metric' for metric and 'imperial' for non-metric. Returns: heat_index: a numerical value representing the heat index in the temperature scale of the specified unit system. Returns None if the specified temperature is less than 80°F or the specified relative humidity is less than 40%. """ # fallback to metric if units != 'imperial' and units != '' and units != 'metric': units = 'metric' R = float(humidity) if units == 'imperial' or units == '': # for backwards compatibility T = float(temperature) elif units == 'metric': # Heat Index is calculated in F T = (float(temperature) * 9.0/5.0) + 32.0 # Heat Index is only valid for temp >= 80°F and humidity >= 40%) if (R < 40.0 or T < 80.0): return None Rsquared = pow(R, 2.0) Tsquared = pow(T, 2.0) # coefficients for calculation c = [None, -42.379, 2.04901523, 10.14333127, -0.22475541, -6.83783 * pow(10.0,-3.0), -5.481717 * pow(10.0,-2.0), 1.22874 * pow(10.0,-3.0), 8.5282 * pow(10.0,-4.0), -1.99 * pow(10.0,-6.0)] heat_index = ( c[1] + (c[2]* T) + (c[3]* R) + (c[4]* T * R) + (c[5]* Tsquared) + (c[6]* Rsquared) + (c[7]* Tsquared * R) + (c[8]* T * Rsquared) + (c[9]* Tsquared * Rsquared) ) # round to one decimal place if units == 'metric': return round(((heat_index - 32.0) * 5.0/9.0), 1) else: return round(heat_index, 1) pywapi-0.3.6/examples/pywapi-example.py000775 001750 001750 00000001215 12171145451 021340 0ustar00jtaskerjtasker000000 000000 #!/usr/bin/env python import pywapi weather_com_result = pywapi.get_weather_from_weather_com('10001') yahoo_result = pywapi.get_weather_from_yahoo('10001') noaa_result = pywapi.get_weather_from_noaa('KJFK') print "Weather.com says: It is " + weather_com_result['current_conditions']['text'].lower() + " and " + weather_com_result['current_conditions']['temperature'] + "C now in New York." print("Yahoo says: It is " + yahoo_result['condition']['text'].lower() + " and " + yahoo_result['condition']['temp'] + "C now in New York.") print("NOAA says: It is " + noaa_result['weather'].lower() + " and " + noaa_result['temp_c'] + "C now in New York.") pywapi-0.3.6/examples/get-weather.py000775 001750 001750 00000006427 12171145451 020624 0ustar00jtaskerjtasker000000 000000 #!/usr/bin/env python3 #Copyright (c) 2010 Dimitris Leventeas #Permission is hereby granted, free of charge, to any person #obtaining a copy of this software and associated documentation #files (the "Software"), to deal in the Software without #restriction, including without limitation the rights to use, #copy, modify, merge, publish, distribute, sublicense, and/or sell #copies of the Software, and to permit persons to whom the #Software is furnished to do so, subject to the following #conditions: #The above copyright notice and this permission notice shall be #included in all copies or substantial portions of the Software. #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, #EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES #OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND #NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT #HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, #WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING #FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR #OTHER DEALINGS IN THE SOFTWARE. from optparse import OptionParser from xml.etree.cElementTree import ElementTree, Element import pywapi def write_everything_from_yahoo_to_xml(country, cities, outfile='weather.xml'): """ Write all the results from google to an xml file """ weather_reports = pywapi.get_everything_from_yahoo(country, cities) xml_output = Element('Weather') for city, report in weather_reports.items(): try: xml_city = Element('town') xml_name = Element('name') xml_name.text = city xml_city.append(xml_name) xml_temperature = Element('temperature') temp_c = report['wind']['chill'] temp_unit = report['units']['temperature'] temp_cond = ''.join([temp_c, ' ', temp_unit]) xml_temperature.text = temp_cond xml_city.append(xml_temperature) xml_humidity = Element('humidity') xml_humidity.text = report['atmosphere']['humidity'] xml_city.append(xml_humidity) xml_condition = Element('condition') xml_condition.text = report['condition']['text'] xml_city.append(xml_condition) xml_wind = Element('wind') beaufort = pywapi.wind_beaufort_scale(report['wind']['speed']) direction = pywapi.wind_direction(report['wind']['direction']) wind_cond = ''.join([beaufort, ' ', direction]) xml_wind.text = wind_cond xml_city.append(xml_wind) xml_output.append(xml_city) except KeyError: pass ElementTree(xml_output).write(outfile, 'UTF-8') def main(): parser = OptionParser(\ usage='Collect information about the weather in Greece.') parser.add_option("-f", "--file", dest="filename", default="weather.xml",\ help="write directory contents to FILE (default: weather.xml)",\ metavar="FILE") (options, args) = parser.parse_args() # Greece (GRXX) has 81 cities available with data write_everything_from_yahoo_to_xml('GRXX', 81, outfile=options.filename) if __name__ == '__main__': main() pywapi-0.3.6/CHANGELOG000664 001750 001750 00000005217 12211477405 015425 0ustar00jtaskerjtasker000000 000000 v0.3.6 (3 September 2013) ! Fix for Py3k compatibility in get_weather_from_weather_com() v0.3.5 (14 August 2013) ! Better handling of Weather.com data when current conditions are empty v0.3.4 (17 July 2013) ! Fix for Unicode decoding issue in get_woeid_from_yahoo() v0.3.3 (2 June 2013) + Added suggested dependency on unidecode Python module, to get location IDs for place names containing non-ascii characters + Added __version__ string to module for version tracking ! Now uses json module to parse json replies instead of unsafe eval() ! Unicode strings are now correctly handled by all methods ! Fixes for Py3k compatibility v0.3.2 (21 May 2013) + Added function get_loc_id_from_weather_com(), which is same as get_location_ids(), but with return format like get_woeid_from_yahoo(). + Added function get_where_on_earth_ids(), which is same as get_woeid_from_yahoo(), but with return format like get_location_ids(). v0.3.1 (17 May 2013) + Added function to calculate Heat Index from specified temperature and humidity. + Added conversion to Beaufort scale for more wind unit types. ! get_woeid_from_yahoo() now returns number of results as a dictionary key. ! Returned get_weather_from_google() to module for backwards compatibility, now always returns 'error' dictionary. v0.3 (13 March 2013) + Now compatible with Python 2.x and Py3k + Added support of Weather.com XML feeds - Google Weather service was removed. It has been discontinued as of Sep 2012. ! Functions now return a dictionary with one key, 'error', if something goes wrong. ! When connecting, now fails gracefully if a URLError occurs. ! Some changes to prevent possible IndexError issues. v0.2.2 (31 August 2009) + Ability to get countries and cities lists from Google was added. + Shebang was added to the example scripts. Thank you, Runa. ! Small corrections to fix some pychecker's warnings. ! get_weather_from_google() now supports non-English languages. Thank you, Shinysky. ! "400: Bad Request" error was fixed. It appeared when Google API is used and location contains special characters(for example spaces). Thank you, Dan.y.tang. ! Some changes to prevent possible IndexError issues. v0.2.1 (07 July 2009) + GisMeteo service was removed. It doesn't provide XML feeds anymore. ! IndexError issue was fixed. Thank you, Dr. Drang. v0.2 (29 May 2009) + Added support of NOAA XML feeds + Added support of GisMeteo XML feeds + Re-organized files: no more package, only one Python module + Added some example scripts + Added CHANGELOG and README files v0.1 (18 May 2009) + Inital release: it is possible to get weather reports from Yahoo and Google pywapi-0.3.6/README000664 001750 001750 00000013164 12211477431 015072 0ustar00jtaskerjtasker000000 000000 Copy of http://code.google.com/p/python-weather-api/ page. =Introduction= The module provides a python wrapper around the Yahoo! Weather, Weather.com and NOAA APIs. Authors: Eugene Kaznacheev Joshua Tasker (*pywapi* - Python Weather API) =Building= ==From source == Download the latest pywapi library from: http://python-weather-api.googlecode.com/files/pywapi-0.3.6.tar.gz Untar the source distribution and run: {{{ $ python setup.py build $ python setup.py install }}} =Getting the code= View the trunk at: http://python-weather-api.googlecode.com/svn/trunk/ Check out the latest development version anonymously with: {{{ svn checkout http://python-weather-api.googlecode.com/svn/trunk/ python-weather-api-read-only }}} =Documentation= == Yahoo! Weather == Use the following function, that fetches weather report from Yahoo === *pywapi.get_weather_from_yahoo(* _location_id_ *,* _ units = 'metric' _ *)* === *location_id*: A five digit US zip code or location ID. To find your location ID, browse or search for your city from the Weather home page (http://weather.yahoo.com/) The weather ID is in the URL for the forecast page for that city. You can also get the location ID by entering your zip code on the home page. For example, if you search for Los Angeles on the Weather home page, the forecast page for that city is http://weather.yahoo.com/forecast/USCA0638.html. The location ID is USCA0638. *units*: type of units. 'metric' for metric and '' for non-metric Note that choosing metric units changes all the weather units to metric, for example, wind speed will be reported as kilometers per hour and barometric pressure as millibars. Default value is 'metric'. Returns: *weather_data*: a dictionary of weather data that exists in XML feed. See http://developer.yahoo.com/weather/#channel * [ExampleOfYahooXML Example of XML response from Yahoo] * [Examples#Yahoo!_Weather Example of return data] == Weather.com == Use the following function, that fetches weather report from Weather.com === *pywapi.get_weather_from_weather_com(* _location_id_ *,* _ units = 'metric' _ *)* === *location_id*: A five digit US zip code or location ID. To find your location ID, browse or search for your city from the Weather.com home page (http://www.weather.com/) The weather ID is in the URL for the forecast page for that city. You can also get the location ID by entering your zip code on the home page. For example, if you search for Los Angeles on the Weather home page, the forecast page for that city is http://www.weather.com/weather/today/Los+Angeles+CA+USCA0638:1:US. The location ID is USCA0638. *units*: type of units. 'metric' for metric and '' for non-metric Note that choosing metric units changes all the weather units to metric, for example, wind speed will be reported as kilometers per hour and barometric pressure as millibars. Default value is 'metric'. Returns: *weather_data*: a dictionary of weather data that exists in XML feed. * [ExampleOfWeatherComXML Example of XML response from Weather.com] * [Examples#Weather.com Example of return data] == NOAA == Use the following function, that fetches weather report from NOAA: National Oceanic and Atmospheric Administration (United States) === *pywapi.get_weather_from_noaa(* _station_id_ *)* === *station_id*: the ID of the weather station near the necessary location To find your station ID, perform the following steps: # Open this URL: http://www.weather.gov/xml/current_obs/seek.php?state=az&Find=Find # Select the necessary state state. Click 'Find'. # Find the necessary station in the 'Observation Location' column. # The station ID is in the URL for the weather page for that station. For example if the weather page is http://weather.noaa.gov/weather/current/KPEO.html -- the station ID is KPEO. Other way to get the station ID: use this library: http://code.google.com/p/python-weather/ and _Weather.location2station_ function. Returns: *weather_data*: a dictionary of weather data that exists in XML feed. * [ExampleOfNoaaXML Example of XML response from NOAA] * [Examples#NOAA Example of return data] (useful icons: http://www.weather.gov/xml/current_obs/weather.php) =Examples= ===[Examples More examples]=== ==Script== {{{ import pywapi import string weather_com_result = pywapi.get_weather_from_weather_com('10001') yahoo_result = pywapi.get_weather_from_yahoo('10001') noaa_result = pywapi.get_weather_from_noaa('KJFK') print "Weather.com says: It is " + string.lower(weather_com_result['current_conditions']['text']) + " and " + weather_com_result['current_conditions']['temperature'] + "C now in New York.\n\n" print "Yahoo says: It is " + string.lower(yahoo_result['condition']['text']) + " and " + yahoo_result['condition']['temp'] + "C now in New York.\n\n" print "NOAA says: It is " + string.lower(noaa_result['weather']) + " and " + noaa_result['temp_c'] + "C now in New York.\n" }}} ==Result== {{{ [~] python examples/pywapi-example.py Weather.com says: It is overcast and 15C now in New York. Yahoo says: It is fog and 14C now in New York. NOAA says: It is overcast and 15C now in New York. }}} = Where is it used? = Weather script for `GeekTool`: http://www.leancrew.com/all-this/2009/06/new-weather-script-for-geektool/ Google Wave robot: http://code.google.com/p/firstwave/wiki/DrWeather http://blog.chrisramsay.co.uk/2009/08/11/getting-weather-information-with-python/ Weather plugins for Dreambox E2: http://linux-sat.tv/index.php/topic,314.msg1328/topicseen.html#msg1328. pywapi-0.3.6/LICENSE000664 001750 001750 00000002154 12171145451 015213 0ustar00jtaskerjtasker000000 000000 Copyright (c) 2009 Eugene Kaznacheev Copyright (c) 2013 Joshua Tasker Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. pywapi-0.3.6/setup.py000664 001750 001750 00000003630 12171145451 015720 0ustar00jtaskerjtasker000000 000000 #!/usr/bin/env python #Copyright (c) 2009 Eugene Kaznacheev #Copyright (c) 2013 Joshua Tasker #Permission is hereby granted, free of charge, to any person #obtaining a copy of this software and associated documentation #files (the "Software"), to deal in the Software without #restriction, including without limitation the rights to use, #copy, modify, merge, publish, distribute, sublicense, and/or sell #copies of the Software, and to permit persons to whom the #Software is furnished to do so, subject to the following #conditions: #The above copyright notice and this permission notice shall be #included in all copies or substantial portions of the Software. #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, #EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES #OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND #NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT #HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, #WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING #FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR #OTHER DEALINGS IN THE SOFTWARE. from distutils.core import setup __author__ = 'qetzal@gmail.com, jtasker@gmail.com' from pywapi import __version__ setup(name='pywapi', version=__version__, description='Python wrapper around different weather APIs', author='Eugene Kaznacheev, Joshua Tasker', author_email='qetzal@gmail.com, jtasker@gmail.com', url='http://code.google.com/p/python-weather-api/', py_modules=['pywapi'], license='MIT', keywords = 'weather api yahoo noaa google', platforms = 'any', long_description = """ This module provides a Python wrapper around the Yahoo! Weather, Weather.com, and National Oceanic and Atmospheric Administration (NOAA) APIs. Fetch weather reports using zip code, location id, city name, state, country, etc. """ ) pywapi-0.3.6/MANIFEST000664 001750 001750 00000000361 12171145451 015335 0ustar00jtaskerjtasker000000 000000 README CHANGELOG LICENSE examples/pywapi-example.py examples/pywapi-google-example.py examples/pywapi-yahoo-example.py examples/pywapi-noaa-example.py examples/pywapi-cities-example.py examples/pywapi-countries-example.py pywapi.py setup.py pywapi-0.3.6/examples/000775 001750 001750 00000000000 12171145451 016022 5ustar00jtaskerjtasker000000 000000 pywapi-0.3.6/examples/pywapi-weather-com-example.py000664 001750 001750 00000000251 12171145451 023545 0ustar00jtaskerjtasker000000 000000 #!/usr/bin/env python3 import pywapi import pprint pp = pprint.PrettyPrinter(indent=4) kalamata = pywapi.get_weather_from_weather_com('GRXX0036') pp.pprint(kalamata) pywapi-0.3.6/000775 001750 001750 00000000000 12211500065 014173 5ustar00jtaskerjtasker000000 000000