Updated to use commands.wrap.

This commit is contained in:
Jeremy Fincher 2004-10-23 21:27:01 +00:00
parent 1a6b4aaa95
commit c6e5d22f6b
5 changed files with 65 additions and 80 deletions

View File

@ -53,8 +53,8 @@ from itertools import imap
import supybot.conf as conf
import supybot.utils as utils
from supybot.commands import *
import supybot.webutils as webutils
import supybot.privmsgs as privmsgs
import supybot.registry as registry
import supybot.callbacks as callbacks
@ -76,34 +76,27 @@ class Http(callbacks.Privmsg):
except webutils.WebError, e:
irc.error(str(e))
def headers(self, irc, msg, args):
def headers(self, irc, msg, args, url):
"""<url>
Returns the HTTP headers of <url>. Only HTTP urls are valid, of
course.
"""
url = privmsgs.getArgs(args)
if not url.startswith('http://'):
irc.error('Only HTTP urls are valid.')
return
fd = webutils.getUrlFd(url)
try:
s = ', '.join(['%s: %s' % (k, v) for (k, v) in fd.headers.items()])
irc.reply(s)
finally:
fd.close()
headers = wrap(headers, ['httpUrl'])
_doctypeRe = re.compile(r'(<!DOCTYPE[^>]+>)', re.M)
def doctype(self, irc, msg, args):
def doctype(self, irc, msg, args, url):
"""<url>
Returns the DOCTYPE string of <url>. Only HTTP urls are valid, of
course.
"""
url = privmsgs.getArgs(args)
if not url.startswith('http://'):
irc.error('Only HTTP urls are valid.')
return
size = conf.supybot.protocols.http.peekSize()
s = webutils.getUrl(url, size=size)
m = self._doctypeRe.search(s)
@ -112,17 +105,14 @@ class Http(callbacks.Privmsg):
irc.reply(s)
else:
irc.reply('That URL has no specified doctype.')
doctype = wrap(doctype, ['httpUrl'])
def size(self, irc, msg, args):
def size(self, irc, msg, args, url):
"""<url>
Returns the Content-Length header of <url>. Only HTTP urls are valid,
of course.
"""
url = privmsgs.getArgs(args)
if not url.startswith('http://'):
irc.error('Only HTTP urls are valid.')
return
fd = webutils.getUrlFd(url)
try:
try:
@ -138,15 +128,13 @@ class Http(callbacks.Privmsg):
'but it\'s longer than %s bytes.' % (url, size))
finally:
fd.close()
size = wrap(size, ['httpUrl'])
def title(self, irc, msg, args):
def title(self, irc, msg, args, url):
"""<url>
Returns the HTML <title>...</title> of a URL.
"""
url = privmsgs.getArgs(args)
if '://' not in url:
url = 'http://%s' % url
size = conf.supybot.protocols.http.peekSize()
text = webutils.getUrl(url, size=size)
m = self._titleRe.search(text)
@ -155,13 +143,13 @@ class Http(callbacks.Privmsg):
else:
irc.reply('That URL appears to have no HTML title '
'within the first %s bytes.' % size)
title = wrap(title, ['httpUrl'])
def freshmeat(self, irc, msg, args):
def freshmeat(self, irc, msg, args, project):
"""<project name>
Returns Freshmeat data about a given project.
"""
project = privmsgs.getArgs(args)
project = ''.join(project.split())
url = 'http://www.freshmeat.net/projects-xml/%s' % project
try:
@ -183,14 +171,14 @@ class Http(callbacks.Privmsg):
(project, lastupdated, vitality, popularity, version))
except FreshmeatException, e:
irc.error(str(e))
freshmeat = wrap(freshmeat, ['something'])
def stockquote(self, irc, msg, args):
def stockquote(self, irc, msg, args, symbol):
"""<company symbol>
Gets the information about the current price and change from the
previous day of a given company (represented by a stock symbol).
"""
symbol = privmsgs.getArgs(args)
if ' ' in symbol:
irc.error('Only one stockquote can be looked up at a time.')
return
@ -205,15 +193,15 @@ class Http(callbacks.Privmsg):
else:
m = 'I couldn\'t find a listing for %s' % symbol
irc.error(m)
stockquote = wrap(stockquote, ['something'])
_cyborgRe = re.compile(r'<p class="mediumheader">(.*?)</p>', re.I)
def cyborg(self, irc, msg, args):
def cyborg(self, irc, msg, args, name):
"""[<name>]
Returns a cyborg acronym for <name> from <http://www.cyborgname.com/>.
If <name> is not specified, uses that of the user.
"""
name = privmsgs.getArgs(args, required=0, optional=1)
if not name:
name = msg.nick
name = urllib.quote(name)
@ -226,15 +214,15 @@ class Http(callbacks.Privmsg):
irc.reply(s)
else:
irc.errorPossibleBug('No cyborg name returned.')
cyborg = wrap(cyborg, [additional('somethingWithoutSpaces')])
_acronymre = re.compile(r'valign="middle" width="7\d%" bgcolor="[^"]+">'
r'(?:<b>)?([^<]+)')
def acronym(self, irc, msg, args):
def acronym(self, irc, msg, args, acronym):
"""<acronym>
Displays acronym matches from acronymfinder.com
"""
acronym = privmsgs.getArgs(args)
url = 'http://www.acronymfinder.com/' \
'af-query.asp?String=exact&Acronym=%s' % urllib.quote(acronym)
html = webutils.getUrl(url)
@ -253,16 +241,16 @@ class Http(callbacks.Privmsg):
else:
s = ', or '.join(defs)
irc.reply('%s could be %s' % (acronym, s))
acronym = wrap(acronym, ['text'])
_netcraftre = re.compile(r'td align="left">\s+<a[^>]+>(.*?)<a href',
re.S | re.I)
def netcraft(self, irc, msg, args):
def netcraft(self, irc, msg, args, hostname):
"""<hostname|ip>
Returns Netcraft.com's determination of what operating system and
webserver is running on the host given.
"""
hostname = privmsgs.getArgs(args)
url = 'http://uptime.netcraft.com/up/graph/?host=%s' % hostname
html = webutils.getUrl(url)
m = self._netcraftre.search(html)
@ -275,6 +263,7 @@ class Http(callbacks.Privmsg):
irc.reply('No results found for %s.' % hostname)
else:
irc.error('The format of page the was odd.')
netcraft = wrap(netcraft, ['text'])
def kernel(self, irc, msg, args):
"""takes no arguments
@ -299,16 +288,16 @@ class Http(callbacks.Privmsg):
irc.reply('The latest stable kernel is %s; '
'the latest snapshot of the stable kernel is %s; '
'the latest beta kernel is %s.' % (stable, snapshot, mm))
kernel = wrap(kernel)
_pgpkeyre = re.compile(r'pub\s+\d{4}\w/<a href="([^"]+)">'
r'([^<]+)</a>[^>]+>([^<]+)</a>')
def pgpkey(self, irc, msg, args):
def pgpkey(self, irc, msg, args, search):
"""<search words>
Returns the results of querying pgp.mit.edu for keys that match
the <search words>.
"""
search = privmsgs.getArgs(args)
urlClean = search.replace(' ', '+')
host = 'http://pgp.mit.edu:11371'
url = '%s/pks/lookup?op=index&search=%s' % (host, urlClean)
@ -326,19 +315,20 @@ class Http(callbacks.Privmsg):
irc.reply(s)
finally:
fd.close()
pgpkey = wrap(pgpkey, ['text'])
_filextre = re.compile(
r'<strong>Extension:</strong>.*?<tr>.*?</tr>\s+<tr>\s+<td colspan='
r'"2">(?:<a href[^>]+>([^<]+)</a>\s+|([^<]+))</td>\s+<td>'
r'(?:<a href[^>]+>([^<]+)</a>|<img src="images/spacer.gif"(.))',
re.I|re.S)
def extension(self, irc, msg, args):
def extension(self, irc, msg, args, ext):
"""<ext>
Returns the results of querying filext.com for file extensions that
match <ext>.
"""
ext = privmsgs.getArgs(args)
# XXX This probably ought to be handled in a converter from commands.py
invalid = '|<>\^=?/[]";,*'
for c in invalid:
if c in ext:
@ -367,16 +357,16 @@ class Http(callbacks.Privmsg):
irc.reply(utils.commaAndify(res))
else:
irc.error('No matching file extensions were found.')
extension = wrap(extension, ['text'])
_zipinfore = re.compile(r'Latitude<BR>\(([^)]+)\)</th><th>Longitude<BR>'
r'\(([^)]+)\).*?<tr>(.*?)</tr>', re.I)
_zipstatre = re.compile(r'(Only about \d+,\d{3} of.*?in use.)')
def zipinfo(self, irc, msg, args):
def zipinfo(self, irc, msg, args, zipcode):
"""<zip code>
Returns a plethora of information for the given <zip code>.
"""
zipcode = privmsgs.getArgs(args)
try:
int(zipcode)
except ValueError:
@ -416,6 +406,7 @@ class Http(callbacks.Privmsg):
'Longitude: %s (%s)' % (info[-1], longdir),
]
irc.reply('; '.join(resp))
zipinfo = wrap(zipinfo, ['text'])
Class = Http

View File

@ -48,10 +48,10 @@ import supybot.registry as registry
import supybot.conf as conf
import supybot.ircdb as ircdb
import supybot.utils as utils
from supybot.commands import *
import supybot.ircmsgs as ircmsgs
import supybot.plugins as plugins
import supybot.ircutils as ircutils
import supybot.privmsgs as privmsgs
import supybot.callbacks as callbacks
try:
@ -154,33 +154,32 @@ class QuoteGrabs(plugins.ChannelDBHandler, callbacks.Privmsg):
s = 'jots down a new quote for %s' % msg.nick
irc.reply(s, action=True, prefixName=False)
def grab(self, irc, msg, args):
def grab(self, irc, msg, args, channel, nick):
"""[<channel>] <nick>
Grabs a quote from <channel> by <nick> for the quotegrabs table.
<channel> is only necessary if the message isn't sent in the channel
itself.
"""
channel = privmsgs.getChannel(msg, args)
nick = privmsgs.getArgs(args)
if ircutils.strEqual(nick, msg.nick):
irc.error('You can\'t quote grab yourself.')
return
for m in reversed(irc.state.history):
# XXX Note that the channel isn't used here. Also note that
# channel might be None since we use channeldb
if m.command == 'PRIVMSG' and ircutils.strEqual(m.nick, nick):
self._grab(irc, m, msg.prefix)
irc.replySuccess()
return
irc.error('I couldn\'t find a proper message to grab.')
grab = wrap(grab, ['channeldb', 'nick'])
def quote(self, irc, msg, args):
def quote(self, irc, msg, args, channel, nick):
"""[<channel>] <nick>
Returns <nick>'s latest quote grab in <channel>. <channel> is only
necessary if the message isn't sent in the channel itself.
"""
channel = privmsgs.getChannel(msg, args)
nick = privmsgs.getArgs(args)
db = self.getDb(channel)
cursor = db.cursor()
cursor.execute("""SELECT quote FROM quotegrabs
@ -191,16 +190,17 @@ class QuoteGrabs(plugins.ChannelDBHandler, callbacks.Privmsg):
else:
text = cursor.fetchone()[0]
irc.reply(text)
quote = wrap(quote, ['channeldb', 'nick'])
def list(self, irc, msg, args):
"""<nick>
def list(self, irc, msg, args, channel, nick):
"""[<channel>] <nick>
Returns a list of shortened quotes that have been grabbed for <nick>
as well as the id of each quote. These ids can be used to get the
full quote.
full quote. <channel> is only necessary if the message isn't sent in
the channel itself.
"""
channel = privmsgs.getChannel(msg, args)
nick = privmsgs.getArgs(args)
# XXX This doesn't seem to be channel-specific in practice.
db = self.getDb(channel)
cursor = db.cursor()
cursor.execute("""SELECT id, quote FROM quotegrabs
@ -216,15 +216,17 @@ class QuoteGrabs(plugins.ChannelDBHandler, callbacks.Privmsg):
item_str = utils.ellipsisify('#%s: %s' % (id, quote), 50)
l.append(item_str)
irc.reply(utils.commaAndify(l))
list = wrap(list, ['channeldb', 'nick'])
def randomquote(self, irc, msg, args):
"""[<nick>]
# XXX Could we rename this "random", to fit in more with the rest of
# our plugins?
def randomquote(self, irc, msg, args, channel, nick):
"""[<channel>] [<nick>]
Returns a randomly grabbed quote, optionally choosing only from those
quotes grabbed for <nick>.
quotes grabbed for <nick>. <channel> is only necessary if the message
isn't sent in the channel itself.
"""
channel = privmsgs.getChannel(msg, args)
nick = privmsgs.getArgs(args, required=0, optional=1)
db = self.getDb(channel)
cursor = db.cursor()
if nick:
@ -243,19 +245,14 @@ class QuoteGrabs(plugins.ChannelDBHandler, callbacks.Privmsg):
return
quote = cursor.fetchone()[0]
irc.reply(quote)
randomquote = wrap(randomquote, ['channeldb', additional('nick')])
def get(self, irc, msg, args):
"""<id>
def get(self, irc, msg, args, channel, id):
"""[<channel>] <id>
Return the quotegrab with the given <id>.
Return the quotegrab with the given <id>. <channel> is only necessary
if the message isn't sent in the channel itself.
"""
id = privmsgs.getArgs(args)
try:
id = int(id)
except ValueError:
irc.error('%r does not appear to be a valid quotegrab id' % id)
return
channel = privmsgs.getChannel(msg, args)
db = self.getDb(channel)
cursor = db.cursor()
cursor.execute("""SELECT quote, hostmask, added_at, added_by
@ -272,6 +269,7 @@ class QuoteGrabs(plugins.ChannelDBHandler, callbacks.Privmsg):
grabber = grabber_mask
irc.reply('%s (Said by: %s; grabbed by %s at %s)' % \
(quote, hostmask, grabber, time_str))
get = wrap(get, ['channeldb', 'id'])
Class = QuoteGrabs

View File

@ -40,7 +40,7 @@ __contributors__ = {}
import supybot.plugins as plugins
import time
TIME = time
TIME = time # For later use.
import dateutil.parser
@ -117,7 +117,7 @@ class Time(callbacks.Privmsg):
seconds += i
irc.reply(str(seconds))
def at(self, irc, msg, args):
def at(self, irc, msg, args, s):
"""<time string>
Returns the number of seconds since epoch <time string> is.
@ -125,20 +125,19 @@ class Time(callbacks.Privmsg):
and see if it will work.
"""
now = int(time.time())
s = privmsgs.getArgs(args)
new = parse(s)
if new != now:
irc.reply(new)
else:
irc.error('That\'s right now!')
at = wrap(at, ['text'])
def until(self, irc, msg, args):
def until(self, irc, msg, args, s):
"""<time string>
Returns the number of seconds until <time string>.
"""
now = int(time.time())
s = privmsgs.getArgs(args)
new = parse(s)
if new != now:
if new - now < 0:
@ -146,6 +145,7 @@ class Time(callbacks.Privmsg):
irc.reply(new-now)
else:
irc.error('That\'s right now!')
until = wrap(until, ['text'])
def ctime(self, irc, msg, args, seconds):
"""[<seconds since epoch>]

View File

@ -45,8 +45,8 @@ import string
import supybot.conf as conf
import supybot.utils as utils
from supybot.commands import *
import supybot.ircutils as ircutils
import supybot.privmsgs as privmsgs
import supybot.registry as registry
import supybot.callbacks as callbacks
@ -143,13 +143,12 @@ class Words(callbacks.Privmsg):
'sorted order) to be at %s. Contact the owner of this '
'bot to remedy this situation.' %
self.registryValue('file'))
def crossword(self, irc, msg, args):
def crossword(self, irc, msg, args, word):
"""<word>
Gives the possible crossword completions for <word>; use underscores
('_') to denote blank spaces.
"""
word = privmsgs.getArgs(args).lower()
word = re.escape(word)
word = word.replace('\\_', '_') # Stupid re.escape escapes underscores!
word = word.replace('_', '.')
@ -197,32 +196,31 @@ class Words(callbacks.Privmsg):
def endGame(self, channel):
del self.games[channel]
def letters(self, irc, msg, args):
def letters(self, irc, msg, args, channel):
"""[<channel>]
Returns the unused letters that can be guessed in the hangman game
in <channel>. <channel> is only necessary if the message isn't sent in
the channel itself.
"""
channel = privmsgs.getChannel(msg, args)
if channel in self.games:
game = self.games[channel]
if game is not None:
self._hangmanReply(irc, channel, ' '.join(game.unused))
return
irc.error('There is currently no hangman game in %s.' % channel)
letters = wrap(letters, ['channel'])
def _hangmanReply(self, irc, channel, s):
s = self.registryValue('hangman.prefix', channel=channel) + s
irc.reply(s, prefixName=False)
def hangman(self, irc, msg, args):
def hangman(self, irc, msg, args, channel):
"""[<channel>]
Creates a new game of hangman in <channel>. <channel> is only
necessary if the message isn't sent in the channel itself.
"""
channel = privmsgs.getChannel(msg, args)
# Fill our dictionary of games
if channel not in self.games:
self.games[channel] = None
@ -259,14 +257,14 @@ class Words(callbacks.Privmsg):
irc.reply('Sorry, there is already a game going on. '
'%s left before the game times out.' %
utils.timeElapsed(game.timeout - secondsElapsed))
hangman = wrap(hangman, ['channel'])
def guess(self, irc, msg, args):
def guess(self, irc, msg, args, channel, letter):
"""[<channel>] <letter|word>
Try to guess a single letter or the whole word. If you try to guess
the whole word and you are wrong, you automatically lose.
"""
channel = privmsgs.getChannel(msg, args)
try:
game = self.games[channel]
if game is None:
@ -274,7 +272,6 @@ class Words(callbacks.Privmsg):
except KeyError:
irc.error('There is no hangman game going on right now.')
return
letter = privmsgs.getArgs(args)
game.timeGuess = time.time()
# User input a valid letter that hasn't been already tried
if letter in game.unused:
@ -326,6 +323,7 @@ class Words(callbacks.Privmsg):
self._hangmanReply(irc, channel,
'You lose! The word was %r.' % game.hidden)
self.endGame(channel)
guess = wrap(guess, ['channel', 'somethingWithoutSpaces'])
###
# END HANGMAN
###

View File

@ -65,8 +65,6 @@ class HttpTest(PluginTestCase):
self.failIf(m.args[1].count('Error') > 1)
def testTitle(self):
self.assertResponse('title slashdot.org',
'Slashdot: News for nerds, stuff that matters')
self.assertResponse('title http://www.slashdot.org/',
'Slashdot: News for nerds, stuff that matters')
self.assertNotRegexp('title '