others/timeparse.py

This commit is contained in:
Jeremy Fincher 2004-09-17 04:56:38 +00:00
parent 6548085878
commit 0a2802f56e
14 changed files with 328 additions and 71 deletions

3
TODO
View File

@ -1,6 +1,9 @@
Roughly in order of precedence (the closer to the front of the file, Roughly in order of precedence (the closer to the front of the file,
the more likely it'll be done before next release): the more likely it'll be done before next release):
* We should have a channel-global value in ircdb.IrcChannel for
ignoring unregistered users.
* It'd be nice to be able to use a backslash to continue lines in the * It'd be nice to be able to use a backslash to continue lines in the
registry, so we could linewrap long strings or lists. registry, so we could linewrap long strings or lists.

231
others/timeparse.py Normal file
View File

@ -0,0 +1,231 @@
#!/usr/bin/python
#
# Copyright (c) 2004, Mike Taylor
# 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.
#
__author__ = "Mike Taylor <bear@code-bear.com>"
__copyright__ = "Copyright (c) 2004 Mike Taylor"
__license__ = "BSD"
__revision__ = "$Id$"
import os, string, re, time
RE_SPECIAL = r'(?P<special>^[in|last|next]+)\s+'
RE_UNITS = r'\s+(?P<units>[hour|minute|second|day|week|month|year]+)'
RE_QUNITS = r'(?P<qunits>[0-9]+[hmsdwmy])'
RE_MODIFIER = r'(?P<modifier>[from|before|after|ago|prior]+)\s+'
CRE_SPECIAL = re.compile(RE_SPECIAL, re.IGNORECASE)
CRE_UNITS = re.compile(RE_UNITS, re.IGNORECASE)
CRE_QUNITS = re.compile(RE_QUNITS, re.IGNORECASE)
CRE_MODIFIER = re.compile(RE_MODIFIER, re.IGNORECASE)
# Used to adjust the returned date before/after the source
_Modifiers = {'from': 1,
'before': -1,
'after': 1,
'ago': 1,
'prior': -1}
_Minute = 60
_Hour = 60 * _Minute
_Day = 24 * _Hour
_Week = 7 * _Day
_Month = 30 * _Day
_Year = 365 * _Day
# This looks hokey - but it is a nice simple way to get
# the proper unit value and it has the advantage that
# later I can morph it into something localized.
# Any trailing s will be removed before lookup.
_Units = {'second': 1,
'sec': 1,
's': 1,
'minute': _Minute,
'min': _Minute,
'm': _Minute,
'hour': _Hour,
'hr': _Hour,
'h': _Hour,
'day': _Day,
'dy': _Day,
'd': _Day,
'week': _Week,
'wk': _Week,
'w': _Week,
'month': _Month,
'mth': _Month,
'm': _Month,
'year': _Year,
'yr': _Year,
'y': _Year}
def _buildTime(sourceTime, quantity, modifier, units):
"""Take quantity, modifier and units strings and convert them
into values, calcuate the time and return the adjusted
sourceTime
"""
# print '[%s][%s][%s]' % (quantity, modifier, units)
q = int(quantity)
if _Modifiers.has_key(modifier):
q = q * _Modifiers[modifier]
if units[-1] == 's':
units = units[:-1]
if _Units.has_key(units):
u = _Units[units]
else:
u = 1
# print 'sourceTime [%d]' % sourceTime
# print 'quantity [%d]' % q
# print 'units [%d]' % u
return sourceTime + (q * u)
def parse(timeString, sourceTime=None):
"""Parse timeString and return the number of seconds from sourceTime
that the timeString expression represents.
This version of parse understands only the more basic of expressions
in this form:
<quantity> <units> <modifier> <target>
Example:
5 minutes from now
last week
2 hours before noon
Valid units - hour, minute, second, month, week, day and year
(including their plural forms)
Valid modifiers - from, before, after, ago, prior
"""
if sourceTime == None:
sourceTime = int(time.time())
else:
sourceTime = int(sourceTime)
quantity = ''
units = ''
modifier = ''
target = ''
s = string.strip(string.lower(timeString))
m = CRE_SPECIAL.search(s)
if m <> None:
target = 'now'
if m.group('special') == 'last':
modifier = 'before'
else:
modifier = 'from'
s = s[m.end('special'):]
m = CRE_UNITS.search(s)
if m <> None:
units = m.group('units')
quantity = s[:m.start('units')]
s = s[m.end('units'):]
else:
m = CRE_MODIFIER.search(s)
if m <> None:
modifier = m.group('modifier')
target = s[m.end('modifier'):]
s = s[:m.start('modifier'):]
m = CRE_UNITS.search(s)
if m <> None:
units = m.group('units')
quantity = s[:m.start('units')]
target = s[m.end('units'):]
return _buildTime(sourceTime, quantity, modifier, units)
def _test(text, value):
print text
v = parse(text)
print '\t%s\t%d\t%d' % ((v == value), value, v)
#
# TODO
#
# - make month unit adjustment aware of the actual number of days in each
# month between source and target
# - handle edge case where quantity and unit are merged: 5s for 5 sec
# - handle compound/nested quantites and modifiers
# - bring unit test over from prototype into this file
# - convert 'five' to 5 and also 'twenty five' to 25
if __name__ == '__main__':
start = int(time.time())
tests = { '5 minutes from now': start + 5 * _Minute,
'5 min from now': start + 5 * _Minute,
'in 5 minutes': start + 5 * _Minute,
'5 days from today': start + 5 * _Day,
'5 days before today': start - 5 * _Day,
'5 minutes': start + 5 * _Minute,
'5 min': start + 5 * _Minute,
'30 seconds from now': start + 30,
'30 sec from now': start + 30,
'30 seconds': start + 30,
'30 sec': start + 30,
'1 week': start + _Week,
'1 wk': start + _Week,
'1 week': start + _Week,
'5 days': start + 5 * _Day,
'1 year': start + _Year,
'2 years': start + 2 * _Year}
for test in tests.keys():
_test(test, tests[test])

View File

@ -45,9 +45,12 @@ import time
sys.path.append(os.pardir) sys.path.append(os.pardir)
import supybot.conf as conf import supybot.conf as conf
import supybot.utils as utils
import supybot.ircmsgs as ircmsgs import supybot.ircmsgs as ircmsgs
import supybot.ircutils as ircutils import supybot.ircutils as ircutils
import supybot.privmsgs as privmsgs
import supybot.registry as registry import supybot.registry as registry
import supybot.schedule as schedule
import supybot.callbacks as callbacks import supybot.callbacks as callbacks
conf.registerPlugin('Ctcp') conf.registerPlugin('Ctcp')
@ -63,8 +66,13 @@ conf.registerGlobalValue(conf.supybot.abuse.flood.ctcp, 'maximum',
conf.registerGlobalValue(conf.supybot.abuse.flood.ctcp, 'punishment', conf.registerGlobalValue(conf.supybot.abuse.flood.ctcp, 'punishment',
registry.PositiveInteger(300, """Determines how many seconds the bot will registry.PositiveInteger(300, """Determines how many seconds the bot will
ignore CTCP messages from users who flood it with CTCP messages.""")) ignore CTCP messages from users who flood it with CTCP messages."""))
conf.registerGlobalValue(conf.supybot.plugins.Ctcp, 'versionWait',
registry.PositiveInteger(10, """Determines how many seconds the bot will
wait after getting a version command (not a CTCP VERSION, but an actual
call of the command in this plugin named "version") before replying with
the results it has collected."""))
class Ctcp(callbacks.PrivmsgRegexp): class Ctcp(callbacks.PrivmsgCommandAndRegexp):
public = False public = False
def __init__(self): def __init__(self):
self.__parent = super(Ctcp, self) self.__parent = super(Ctcp, self)
@ -96,35 +104,77 @@ class Ctcp(callbacks.PrivmsgRegexp):
s = '\x01%s\x01' % s s = '\x01%s\x01' % s
irc.reply(s, notice=True, private=True, to=msg.nick) irc.reply(s, notice=True, private=True, to=msg.nick)
def ping(self, irc, msg, match): regexps = ('ctcpPing', 'ctcpVersion', 'ctcpUserinfo',
'ctcpTime', 'ctcpFinger', 'ctcpSource')
def ctcpPing(self, irc, msg, match):
"\x01PING (.*)\x01" "\x01PING (.*)\x01"
self.log.info('Received CTCP PING from %s', msg.prefix) self.log.info('Received CTCP PING from %s', msg.prefix)
self._reply(irc, msg, 'PING %s' % match.group(1)) self._reply(irc, msg, 'PING %s' % match.group(1))
def version(self, irc, msg, match): def ctcpVersion(self, irc, msg, match):
"\x01VERSION\x01" "\x01VERSION\x01"
self.log.info('Received CTCP VERSION from %s', msg.prefix) self.log.info('Received CTCP VERSION from %s', msg.prefix)
self._reply(irc, msg, 'VERSION Supybot %s' % conf.version) self._reply(irc, msg, 'VERSION Supybot %s' % conf.version)
def userinfo(self, irc, msg, match): def ctcpUserinfo(self, irc, msg, match):
"\x01USERINFO\x01" "\x01USERINFO\x01"
self.log.info('Received CTCP USERINFO from %s', msg.prefix) self.log.info('Received CTCP USERINFO from %s', msg.prefix)
self._reply(irc, msg, 'USERINFO') self._reply(irc, msg, 'USERINFO')
def time(self, irc, msg, match): def ctcpTime(self, irc, msg, match):
"\x01TIME\x01" "\x01TIME\x01"
self.log.info('Received CTCP TIME from %s' % msg.prefix) self.log.info('Received CTCP TIME from %s' % msg.prefix)
self._reply(irc, msg, time.ctime()) self._reply(irc, msg, time.ctime())
def finger(self, irc, msg, match): def ctcpFinger(self, irc, msg, match):
"\x01FINGER\x01" "\x01FINGER\x01"
self.log.info('Received CTCP FINGER from %s' % msg.prefix) self.log.info('Received CTCP FINGER from %s' % msg.prefix)
self._reply(irc, msg, 'Supybot, the best Python IRC bot in existence!') self._reply(irc, msg, 'Supybot, the best Python IRC bot in existence!')
def source(self, irc, msg, match): def ctcpSource(self, irc, msg, match):
"\x01SOURCE\x01" "\x01SOURCE\x01"
self.log.info('Received CTCP SOURCE from %s' % msg.prefix) self.log.info('Received CTCP SOURCE from %s' % msg.prefix)
self._reply(irc, msg, 'http://www.sourceforge.net/projects/supybot/') self._reply(irc, msg, 'http://www.sourceforge.net/projects/supybot/')
def doNotice(self, irc, msg):
if ircmsgs.isCtcp(msg):
try:
(version, payload) = msg.args[1][1:-1].split(None, 1)
except ValueError:
return
if version == 'VERSION':
self.versions.setdefault(payload, []).append(msg.nick)
def version(self, irc, msg, args):
"""[<channel>] [--nicks]
Sends a CTCP VERSION to <channel>, returning the various
version strings returned. It waits for 10 seconds before returning
the versions received at that point. If --nicks is given, nicks are
associated with the version strings; otherwise, only the version
strings are given.
"""
self.versions = ircutils.IrcDict()
nicks = False
while '--nicks' in args:
nicks = True
args.remove('--nicks')
channel = privmsgs.getChannel(msg, args)
irc.queueMsg(ircmsgs.privmsg(channel, '\x01VERSION\x01'))
def doReply():
if self.versions:
L = []
for (reply, nicks) in self.versions.iteritems():
if nicks:
L.append('%s responded with %r' %
(utils.commaAndify(nicks), reply))
else:
L.append(reply)
irc.reply(utils.commaAndify(L))
else:
irc.reply('I received no version responses.')
wait = self.registryValue('versionWait')
schedule.addEvent(doReply, time.time()+wait)
Class = Ctcp Class = Ctcp
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: # vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:

View File

@ -275,8 +275,7 @@ class Debian(callbacks.Privmsg,
r = utils.perlReToPythonRe(arg) r = utils.perlReToPythonRe(arg)
predicates.append(r.search) predicates.append(r.search)
except ValueError: except ValueError:
irc.error('%r is not a valid regexp.' % arg) irc.errorInvalid('regular expression', arg, Raise=True)
return
elif option == '--arch': elif option == '--arch':
arg = '_%s.' % arg arg = '_%s.' % arg
archPredicate = lambda s, arg=arg: (arg in s) archPredicate = lambda s, arg=arg: (arg in s)

View File

@ -194,8 +194,7 @@ class Dunno(callbacks.Privmsg):
try: try:
id = int(id) id = int(id)
except ValueError: except ValueError:
irc.error('Invalid id: %r' % id) irc.error('id', id, Raise=True)
return
dunno = self.db.get(channel, id) dunno = self.db.get(channel, id)
if by != dunno.by: if by != dunno.by:
cap = ircdb.makeChannelCapability(channel, 'op') cap = ircdb.makeChannelCapability(channel, 'op')
@ -238,8 +237,7 @@ class Dunno(callbacks.Privmsg):
try: try:
id = int(id) id = int(id)
except ValueError: except ValueError:
irc.error('%r is not a valid dunno id.' % id) irc.errorInvalid('dunno id', id, Raise=True)
return
try: try:
dunno = self.db.get(channel, id) dunno = self.db.get(channel, id)
name = ircdb.users.getUser(dunno.by).name name = ircdb.users.getUser(dunno.by).name
@ -268,18 +266,15 @@ class Dunno(callbacks.Privmsg):
try: try:
id = int(id) id = int(id)
except ValueError: except ValueError:
irc.error('%r is not a valid dunno id.' % id) irc.errorInvalid('dunno id', id, Raise=True)
return
try: try:
_ = self.db.get(channel, id) _ = self.db.get(channel, id)
except KeyError: except KeyError:
irc.error('There is no dunno #%s.' % id) irc.error('There is no dunno #%s.' % id)
return
try: try:
replacer = utils.perlReToReplacer(regexp) replacer = utils.perlReToReplacer(regexp)
except: except:
irc.error('%r is not a valid regular expression.' % regexp) irc.errorInvalid('regular expression', regexp, Raise=True)
return
self.db.change(channel, id, replacer) self.db.change(channel, id, replacer)
irc.replySuccess() irc.replySuccess()

View File

@ -171,8 +171,7 @@ class Factoids(plugins.ChannelDBHandler, callbacks.Privmsg):
try: try:
irc.reply(factoids[number-1]) irc.reply(factoids[number-1])
except IndexError: except IndexError:
irc.error('That\'s not a valid number for that key.') irc.errorInvalid('number for that key', number, Raise=True)
return
else: else:
intro = self.registryValue('factoidPrefix', channel) intro = self.registryValue('factoidPrefix', channel)
prefix = '%r %s' % (key, intro) prefix = '%r %s' % (key, intro)
@ -214,8 +213,7 @@ class Factoids(plugins.ChannelDBHandler, callbacks.Privmsg):
try: try:
number = int(number) number = int(number)
except ValueError: except ValueError:
irc.error('%s is not a valid number.' % number) irc.errorInvalid('number', number, Raise=True)
return
else: else:
number = 0 number = 0
factoids = self._lookupFactoid(channel, key) factoids = self._lookupFactoid(channel, key)
@ -293,8 +291,7 @@ class Factoids(plugins.ChannelDBHandler, callbacks.Privmsg):
try: try:
(_, id) = results[number] (_, id) = results[number]
except IndexError: except IndexError:
irc.error('Invalid factoid number.') irc.errorInvalid('factoid number', number, Raise=True)
return
cursor.execute("DELETE FROM factoids WHERE id=%s", id) cursor.execute("DELETE FROM factoids WHERE id=%s", id)
db.commit() db.commit()
irc.replySuccess() irc.replySuccess()
@ -370,15 +367,13 @@ class Factoids(plugins.ChannelDBHandler, callbacks.Privmsg):
try: try:
replacer = utils.perlReToReplacer(regexp) replacer = utils.perlReToReplacer(regexp)
except ValueError, e: except ValueError, e:
irc.error('Invalid regexp: %s' % e) irc.errorInvalid('regular expression', regexp, str(e), Raise=True)
return
try: try:
number = int(number) number = int(number)
if number <= 0: if number <= 0:
raise ValueError raise ValueError
except ValueError: except ValueError:
irc.error('Invalid key id.') irc.errorInvalid('id', number, Raise=True)
return
db = self.getDb(channel) db = self.getDb(channel)
cursor = db.cursor() cursor = db.cursor()
cursor.execute("""SELECT factoids.id, factoids.fact cursor.execute("""SELECT factoids.id, factoids.fact

View File

@ -101,14 +101,12 @@ class Format(callbacks.Privmsg):
try: try:
fg = ircutils.mircColors[fg] fg = ircutils.mircColors[fg]
except KeyError: except KeyError:
irc.error('%r is not a valid foreground color.' % fg) irc.errorInvalid('foreground color', fg, Raise=True)
return
if bg is not None: if bg is not None:
try: try:
bg = ircutils.mircColors[bg] bg = ircutils.mircColors[bg]
except KeyError: except KeyError:
irc.error('%r is not a valid background color.' % bg) irc.errorInvalid('background color', bg, Raise=True)
return
irc.reply(ircutils.mircColor(text, fg=fg, bg=bg)) irc.reply(ircutils.mircColor(text, fg=fg, bg=bg))
def join(self, irc, msg, args): def join(self, irc, msg, args):
@ -172,7 +170,7 @@ class Format(callbacks.Privmsg):
try: try:
size = int(size) size = int(size)
except ValueError: except ValueError:
irc.error('%r is not a valid integer.' % size) irc.errorInvalid('integer', size, Raise=True)
irc.reply(text[:size]) irc.reply(text[:size])
def field(self, irc, msg, args): def field(self, irc, msg, args):
@ -187,11 +185,11 @@ class Format(callbacks.Privmsg):
if index > 0: if index > 0:
index -= 1 index -= 1
except ValueError: except ValueError:
irc.error('%r is not a valid integer.' % number) irc.errorInvalid('integer', number, Raise=True)
try: try:
irc.reply(text.split()[index]) irc.reply(text.split()[index])
except IndexError: except IndexError:
irc.error('That\'s not a valid field.') irc.errorInvalid('field')
def format(self, irc, msg, args): def format(self, irc, msg, args):
"""<format string> [<arg> ...] """<format string> [<arg> ...]

View File

@ -252,8 +252,7 @@ class Herald(callbacks.Privmsg):
try: try:
changer = utils.perlReToReplacer(regexp) changer = utils.perlReToReplacer(regexp)
except ValueError, e: except ValueError, e:
irc.error('That\'s not a valid regexp: %s.' % e) irc.errorInvalid('regular expression', regexp, str(e), Raise=True)
return
s = self.db[channel, id] s = self.db[channel, id]
newS = changer(s) newS = changer(s)
self.db[channel, id] = newS self.db[channel, id] = newS

View File

@ -133,8 +133,7 @@ class Lookup(callbacks.Privmsg):
name = privmsgs.getArgs(args) name = privmsgs.getArgs(args)
name = callbacks.canonicalName(name) name = callbacks.canonicalName(name)
if name not in self.lookupDomains: if name not in self.lookupDomains:
irc.error('That\'s not a valid lookup to remove.') irc.errorInvalid('lookup', name, Raise=True)
return
db = self.dbHandler.getDb() db = self.dbHandler.getDb()
cursor = db.cursor() cursor = db.cursor()
try: try:
@ -249,9 +248,7 @@ class Lookup(callbacks.Privmsg):
try: try:
r = utils.perlReToPythonRe(arg) r = utils.perlReToPythonRe(arg)
except ValueError, e: except ValueError, e:
irc.error('%r is not a valid regular expression' % irc.errorInvalid('regular expression', arg, Raise=True)
arg)
return
def p(s, r=r): def p(s, r=r):
return int(bool(r.search(s))) return int(bool(r.search(s)))
db.create_function(predicateName, 1, p) db.create_function(predicateName, 1, p)

View File

@ -194,7 +194,7 @@ class Observer(callbacks.Privmsg):
""" """
name = privmsgs.getArgs(args) name = privmsgs.getArgs(args)
if name not in self.registryValue('observers'): if name not in self.registryValue('observers'):
irc.error('That\'s not a valid observer.', Raise=True) irc.errorInvalid('observer', name, Raise=True)
g = self.registryValue('observers.%s' % name, value=False) g = self.registryValue('observers.%s' % name, value=False)
regexp = g() regexp = g()
command = g.command() command = g.command()
@ -222,8 +222,9 @@ class Observer(callbacks.Privmsg):
probability = 1.0 probability = 1.0
(name, regexp, command) = privmsgs.getArgs(args, required=3) (name, regexp, command) = privmsgs.getArgs(args, required=3)
if not registry.isValidRegistryName(name): if not registry.isValidRegistryName(name):
irc.error('That\'s not a valid observer name. Please be sure ' irc.errorInvalid('observer name', name,
'there are no spaces in the name.', Raise=True) 'Please be sure there are no spaces in the name.',
Raise=True)
registerObserver(name, regexp, command, probability) registerObserver(name, regexp, command, probability)
irc.replySuccess() irc.replySuccess()

View File

@ -323,8 +323,7 @@ class Quotes(callbacks.Privmsg):
try: try:
id = int(id) id = int(id)
except ValueError: except ValueError:
irc.error('Invalid id: %r' % id) irc.errorInvalid('id', id, Raise=True)
return
try: try:
quote = self.db.get(channel, id) quote = self.db.get(channel, id)
irc.reply(str(quote)) irc.reply(str(quote))
@ -342,7 +341,7 @@ class Quotes(callbacks.Privmsg):
try: try:
id = int(id) id = int(id)
except ValueError: except ValueError:
irc.error('That\'s not a valid id: %r' % id) irc.errorInvalid('id', id, Raise=True)
try: try:
self.db.remove(channel, id) self.db.remove(channel, id)
irc.replySuccess() irc.replySuccess()

View File

@ -112,9 +112,7 @@ class Todo(callbacks.Privmsg):
try: try:
userid = ircdb.users.getUserId(arg) userid = ircdb.users.getUserId(arg)
except KeyError: except KeyError:
irc.error( irc.errorInvalid('task or username', arg, Raise=True)
'%r is not a valid task id or username' % arg)
return
db = self.dbHandler.getDb() db = self.dbHandler.getDb()
cursor = db.cursor() cursor = db.cursor()
if not userid and not taskid: if not userid and not taskid:
@ -151,8 +149,7 @@ class Todo(callbacks.Privmsg):
cursor.execute("""SELECT userid,priority,added_at,task,active cursor.execute("""SELECT userid,priority,added_at,task,active
FROM todo WHERE id = %s""", taskid) FROM todo WHERE id = %s""", taskid)
if cursor.rowcount == 0: if cursor.rowcount == 0:
irc.error('%r is not a valid task id' % taskid) irc.errorInvalid('task id', taskid, Raise=True)
return
(userid, pri, added_at, task, active) = cursor.fetchone() (userid, pri, added_at, task, active) = cursor.fetchone()
# Construct and return the reply # Construct and return the reply
user = ircdb.users.getUser(userid) user = ircdb.users.getUser(userid)
@ -191,8 +188,7 @@ class Todo(callbacks.Privmsg):
try: try:
priority = int(arg) priority = int(arg)
except ValueError, e: except ValueError, e:
irc.error('%r is an invalid priority' % arg) irc.errorInvalid('priority', arg, Raise=True)
return
text = privmsgs.getArgs(rest) text = privmsgs.getArgs(rest)
db = self.dbHandler.getDb() db = self.dbHandler.getDb()
cursor = db.cursor() cursor = db.cursor()
@ -272,9 +268,7 @@ class Todo(callbacks.Privmsg):
try: try:
r = utils.perlReToPythonRe(arg) r = utils.perlReToPythonRe(arg)
except ValueError, e: except ValueError, e:
irc.error('%r is not a valid regular expression' % irc.errorInvalid('regular expression', arg, Raise=True)
arg)
return
def p(s, r=r): def p(s, r=r):
return int(bool(r.search(s))) return int(bool(r.search(s)))
db.create_function(predicateName, 1, p) db.create_function(predicateName, 1, p)
@ -337,19 +331,17 @@ class Todo(callbacks.Privmsg):
try: try:
replacer = utils.perlReToReplacer(regexp) replacer = utils.perlReToReplacer(regexp)
except ValueError: except ValueError:
irc.error('%r is not a valid regexp' % regexp) irc.errorInvalid('regular expression', regexp, Raise=True)
return
db = self.dbHandler.getDb() db = self.dbHandler.getDb()
cursor = db.cursor() cursor = db.cursor()
cursor.execute("""SELECT task FROM todo cursor.execute("""SELECT task FROM todo
WHERE userid = %s AND id = %s WHERE userid = %s AND id = %s
AND active = 1""", userid, taskid) AND active = 1""", userid, taskid)
if cursor.rowcount == 0: if cursor.rowcount == 0:
irc.error('%r is not a valid task id' % taskid) irc.errorInvalid('task id', taskid, Raise=True)
return
newtext = replacer(cursor.fetchone()[0]) newtext = replacer(cursor.fetchone()[0])
cursor.execute("""UPDATE todo SET task = %s cursor.execute("""UPDATE todo SET task = %s WHERE id = %s""",
WHERE id = %s""", newtext, taskid) newtext, taskid)
db.commit() db.commit()
irc.replySuccess() irc.replySuccess()

View File

@ -166,7 +166,7 @@ class Topic(callbacks.Privmsg):
n += len(topics) n += len(topics)
return n return n
except (ValueError, IndexError): except (ValueError, IndexError):
irc.error('That\'s not a valid topic number.', Raise=True) irc.errorInvalid('topic number', n, Raise=True)
def topic(self, irc, msg, args, channel): def topic(self, irc, msg, args, channel):
"""[<channel>] """[<channel>]
@ -308,14 +308,12 @@ class Topic(callbacks.Privmsg):
(number, regexp) = privmsgs.getArgs(args, required=2) (number, regexp) = privmsgs.getArgs(args, required=2)
topics = self._splitTopic(irc.state.getTopic(channel), channel) topics = self._splitTopic(irc.state.getTopic(channel), channel)
if not topics: if not topics:
irc.error('There are no topics to change.') irc.error('There are no topics to change.', Raise=True)
return
number = self._topicNumber(irc, number, topics=topics) number = self._topicNumber(irc, number, topics=topics)
try: try:
replacer = utils.perlReToReplacer(regexp) replacer = utils.perlReToReplacer(regexp)
except ValueError, e: except ValueError, e:
irc.error('The regexp wasn\'t valid: %s' % e) irc.errorInvalid('regexp', regexp, Raise=True)
return
topics[number] = replacer(topics[number]) topics[number] = replacer(topics[number])
self._sendTopics(irc, channel, topics) self._sendTopics(irc, channel, topics)
change = privmsgs.channel(change) change = privmsgs.channel(change)

View File

@ -303,10 +303,10 @@ class Words(callbacks.Privmsg):
else: else:
# User input an invalid character # User input an invalid character
if len(letter) == 1: if len(letter) == 1:
irc.error('That is not a valid letter.') irc.errorInvalid('letter', letter, Raise=True)
# User input an invalid word (len(try) != len(hidden)) # User input an invalid word (len(try) != len(hidden))
else: else:
irc.error('That is not a valid word guess.') irc.errorInvalid('word guess', letter, Raise=True)
# Verify if the user won or lost # Verify if the user won or lost
if game.guessed and game.tries > 0: if game.guessed and game.tries > 0:
self._hangmanReply(irc, channel, self._hangmanReply(irc, channel,