diff --git a/plugins/Http.py b/plugins/Http.py
index fe04da273..7508a3780 100644
--- a/plugins/Http.py
+++ b/plugins/Http.py
@@ -186,137 +186,6 @@ class Http(callbacks.Privmsg):
m = 'I couldn\'t find a listing for %s' % symbol
irc.error(msg, m)
- _cityregex = re.compile(
- r'
'\
- r'(.*?), (.*?),(.*?) | ', re.IGNORECASE)
- _interregex = re.compile(
- r''\
- r'([^,]+), ([^<]+) | ', re.IGNORECASE)
- _condregex = re.compile(
- r''\
- r'([^<]+) | ', re.IGNORECASE)
- _tempregex = re.compile(
- r''\
- r'([^<]+) | ', re.IGNORECASE)
- _chillregex = re.compile(
- r'Wind Chill:\s+'\
- r'([^<]+) | ', re.I | re.S)
- _heatregex = re.compile(
- r'Heat Index:\s+'\
- r'([^<]+) | ', re.I | re.S)
- # States
- _realStates = sets.Set(['ak', 'al', 'ar', 'az', 'ca', 'co', 'ct',
- 'dc', 'de', 'fl', 'ga', 'hi', 'ia', 'id',
- 'il', 'in', 'ks', 'ky', 'la', 'ma', 'md',
- 'me', 'mi', 'mn', 'mo', 'ms', 'mt', 'nc',
- 'nd', 'ne', 'nh', 'nj', 'nm', 'nv', 'ny',
- 'oh', 'ok', 'or', 'pa', 'ri', 'sc', 'sd',
- 'tn', 'tx', 'ut', 'va', 'vt', 'wa', 'wi',
- 'wv', 'wy'])
- # Provinces. (Province being a metric state measurement mind you. :D)
- _fakeStates = sets.Set(['ab', 'bc', 'mb', 'nb', 'nf', 'ns', 'nt',
- 'nu', 'on', 'pe', 'qc', 'sk', 'yk'])
- # Certain countries are expected to use a standard abbreviation
- # The weather we pull uses weird codes. Map obvious ones here.
- _countryMap = {'uk': 'gb'}
- def weather(self, irc, msg, args):
- """
-
- Returns the approximate weather conditions for a given city.
- """
-
- #If we received more than one argument, then we have received
- #a city and state argument that we need to process.
- if len(args) > 1:
- #If we received more than 1 argument, then we got a city with a
- #multi-word name. ie ['Garden', 'City', 'KS'] instead of
- #['Liberal', 'KS']. We join it together with a + to pass
- #to our query
- state = args.pop()
- state = state.lower()
- city = '+'.join(args)
- city = city.rstrip(',')
- city = city.lower()
- #We must break the States up into two sections. The US and
- #Canada are the only countries that require a State argument.
-
- if state in self._realStates:
- country = 'us'
- elif state in self._fakeStates:
- country = 'ca'
- else:
- country = state
- state = ''
- if country in self._countryMap.keys():
- country = self._countryMap[country]
- url = 'http://www.hamweather.net/cgi-bin/hw3/hw3.cgi?'\
- 'pass=&dpp=&forecast=zandh&config=&'\
- 'place=%s&state=%s&country=%s' % \
- (city, state, country)
- html = webutils.getUrl(url)
- if 'was not found' in html:
- url = 'http://www.hamweather.net/cgi-bin/hw3/hw3.cgi?'\
- 'pass=&dpp=&forecast=zandh&config=&'\
- 'place=%s&state=&country=%s' % \
- (city, state)
- html = webutils.getUrl(url)
- if 'was not found' in html:
- irc.error(msg, 'No such location could be found.')
- return
-
- #We received a single argument. Zipcode or station id.
- else:
- zip = privmsgs.getArgs(args)
- zip = zip.replace(',', '')
- zip = zip.lower().split()
- url = 'http://www.hamweather.net/cgi-bin/hw3/hw3.cgi?'\
- 'config=&forecast=zandh&pands=%s&Submit=GO' % args[0]
- html = webutils.getUrl(url)
- if 'was not found' in html:
- irc.error(msg, 'No such location could be found.')
- return
-
- headData = self._cityregex.search(html)
- if headData:
- (city, state, country) = headData.groups()
- else:
- headData = self._interregex.search(html)
- if headData:
- (city, state) = headData.groups()
- else:
- irc.error(msg, 'No such location could be found.')
- return
-
- city = city.strip()
- state = state.strip()
- temp = self._tempregex.search(html)
- if temp:
- temp = temp.group(1)
- conds = self._condregex.search(html)
- if conds:
- conds = conds.group(1)
- chill = self._chillregex.search(html)
- if chill:
- chill = chill.group(1)
- heat = self._heatregex.search(html)
- if heat:
- heat = heat.group(1)
-
- if heat[:-2] > temp[:-2]:
- index = ' (Heat Index: %s)' % heat
- elif chill[:-2] < temp[:-2]:
- index = ' (Wind Chill: %s)' % chill
- else:
- index = ''
-
- if temp and conds and city and state:
- conds = conds.replace('Tsra', 'Thunder Storms')
- s = 'The current temperature in %s, %s is %s%s. Conditions: %s' % \
- (city, state, temp, index, conds)
- irc.reply(msg, s)
- else:
- irc.error(msg, 'The format of the page was odd.')
-
_mlgeekquotere = re.compile('(.*?)
', re.M | re.DOTALL)
def geekquote(self, irc, msg, args):
"""[]
diff --git a/plugins/Weather.py b/plugins/Weather.py
new file mode 100644
index 000000000..3319f248c
--- /dev/null
+++ b/plugins/Weather.py
@@ -0,0 +1,198 @@
+#!/n/bronze/7/fincher/bin/python
+
+###
+# Copyright (c) 2002, Jeremiah Fincher
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions, and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions, and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the author of this software nor the name of
+# contributors to this software may be used to endorse or promote products
+# derived from this software without specific prior written consent.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+###
+
+"""
+This plugin does weather-related stuff.
+"""
+
+import plugins
+
+import re
+import sets
+
+import utils
+import webutils
+import privmsgs
+import callbacks
+
+
+def configure(onStart, afterConnect, advanced):
+ # This will be called by setup.py to configure this module. onStart and
+ # afterConnect are both lists. Append to onStart the commands you would
+ # like to be run when the bot is started; append to afterConnect the
+ # commands you would like to be run when the bot has finished connecting.
+ from questions import expect, anything, something, yn
+ onStart.append('load Weather')
+
+
+class Weather(callbacks.Privmsg):
+ threaded = True
+ def callCommand(self, method, irc, msg, *L):
+ try:
+ callbacks.Privmsg.callCommand(self, method, irc, msg, *L)
+ except webutils.WebError, e:
+ irc.error(msg, str(e))
+
+ _cityregex = re.compile(
+ r''\
+ r'(.*?), (.*?),(.*?) | ', re.IGNORECASE)
+ _interregex = re.compile(
+ r''\
+ r'([^,]+), ([^<]+) | ', re.IGNORECASE)
+ _condregex = re.compile(
+ r''\
+ r'([^<]+) | ', re.IGNORECASE)
+ _tempregex = re.compile(
+ r''\
+ r'([^<]+) | ', re.IGNORECASE)
+ _chillregex = re.compile(
+ r'Wind Chill:\s+'\
+ r'([^<]+) | ', re.I | re.S)
+ _heatregex = re.compile(
+ r'Heat Index:\s+'\
+ r'([^<]+) | ', re.I | re.S)
+ # States
+ _realStates = sets.Set(['ak', 'al', 'ar', 'az', 'ca', 'co', 'ct',
+ 'dc', 'de', 'fl', 'ga', 'hi', 'ia', 'id',
+ 'il', 'in', 'ks', 'ky', 'la', 'ma', 'md',
+ 'me', 'mi', 'mn', 'mo', 'ms', 'mt', 'nc',
+ 'nd', 'ne', 'nh', 'nj', 'nm', 'nv', 'ny',
+ 'oh', 'ok', 'or', 'pa', 'ri', 'sc', 'sd',
+ 'tn', 'tx', 'ut', 'va', 'vt', 'wa', 'wi',
+ 'wv', 'wy'])
+ # Provinces. (Province being a metric state measurement mind you. :D)
+ _fakeStates = sets.Set(['ab', 'bc', 'mb', 'nb', 'nf', 'ns', 'nt',
+ 'nu', 'on', 'pe', 'qc', 'sk', 'yk'])
+ # Certain countries are expected to use a standard abbreviation
+ # The weather we pull uses weird codes. Map obvious ones here.
+ _countryMap = {'uk': 'gb'}
+ def weather(self, irc, msg, args):
+ """
+
+ Returns the approximate weather conditions for a given city.
+ """
+
+ #If we received more than one argument, then we have received
+ #a city and state argument that we need to process.
+ if len(args) > 1:
+ #If we received more than 1 argument, then we got a city with a
+ #multi-word name. ie ['Garden', 'City', 'KS'] instead of
+ #['Liberal', 'KS']. We join it together with a + to pass
+ #to our query
+ state = args.pop()
+ state = state.lower()
+ city = '+'.join(args)
+ city = city.rstrip(',')
+ city = city.lower()
+ #We must break the States up into two sections. The US and
+ #Canada are the only countries that require a State argument.
+
+ if state in self._realStates:
+ country = 'us'
+ elif state in self._fakeStates:
+ country = 'ca'
+ else:
+ country = state
+ state = ''
+ if country in self._countryMap.keys():
+ country = self._countryMap[country]
+ url = 'http://www.hamweather.net/cgi-bin/hw3/hw3.cgi?'\
+ 'pass=&dpp=&forecast=zandh&config=&'\
+ 'place=%s&state=%s&country=%s' % \
+ (city, state, country)
+ html = webutils.getUrl(url)
+ if 'was not found' in html:
+ url = 'http://www.hamweather.net/cgi-bin/hw3/hw3.cgi?'\
+ 'pass=&dpp=&forecast=zandh&config=&'\
+ 'place=%s&state=&country=%s' % \
+ (city, state)
+ html = webutils.getUrl(url)
+ if 'was not found' in html:
+ irc.error(msg, 'No such location could be found.')
+ return
+
+ #We received a single argument. Zipcode or station id.
+ else:
+ zip = privmsgs.getArgs(args)
+ zip = zip.replace(',', '')
+ zip = zip.lower().split()
+ url = 'http://www.hamweather.net/cgi-bin/hw3/hw3.cgi?'\
+ 'config=&forecast=zandh&pands=%s&Submit=GO' % args[0]
+ html = webutils.getUrl(url)
+ if 'was not found' in html:
+ irc.error(msg, 'No such location could be found.')
+ return
+
+ headData = self._cityregex.search(html)
+ if headData:
+ (city, state, country) = headData.groups()
+ else:
+ headData = self._interregex.search(html)
+ if headData:
+ (city, state) = headData.groups()
+ else:
+ irc.error(msg, 'No such location could be found.')
+ return
+
+ city = city.strip()
+ state = state.strip()
+ temp = self._tempregex.search(html)
+ if temp:
+ temp = temp.group(1)
+ conds = self._condregex.search(html)
+ if conds:
+ conds = conds.group(1)
+ chill = self._chillregex.search(html)
+ if chill:
+ chill = chill.group(1)
+ heat = self._heatregex.search(html)
+ if heat:
+ heat = heat.group(1)
+
+ if heat[:-2] > temp[:-2]:
+ index = ' (Heat Index: %s)' % heat
+ elif chill[:-2] < temp[:-2]:
+ index = ' (Wind Chill: %s)' % chill
+ else:
+ index = ''
+
+ if temp and conds and city and state:
+ conds = conds.replace('Tsra', 'Thunder Storms')
+ s = 'The current temperature in %s, %s is %s%s. Conditions: %s' % \
+ (city, state, temp, index, conds)
+ irc.reply(msg, s)
+ else:
+ irc.error(msg, 'The format of the page was odd.')
+
+
+Class = Weather
+
+# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
diff --git a/test/test_Weather.py b/test/test_Weather.py
new file mode 100644
index 000000000..30439633f
--- /dev/null
+++ b/test/test_Weather.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+
+###
+# Copyright (c) 2002, Jeremiah Fincher
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions, and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions, and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the author of this software nor the name of
+# contributors to this software may be used to endorse or promote products
+# derived from this software without specific prior written consent.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+###
+
+from testsupport import *
+
+if network:
+ class WeatherTest(PluginTestCase, PluginDocumentation):
+ plugins = ('Weather',)
+ def testWeather(self):
+ self.assertNotError('weather Columbus, OH')
+ self.assertNotError('weather 43221')
+ self.assertNotRegexp('weather Paris, FR', 'Virginia')
+ self.assertError('weather alsdkfjasdl, asdlfkjsadlfkj')
+ self.assertNotError('weather London, uk')
+ self.assertNotError('weather London, UK')
+ self.assertNotError('weather Munich, de')
+ self.assertNotError('weather Tucson, AZ')
+ self.assertError('weather hell')
+
+# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
+