diff --git a/plugins/Infobot.py b/plugins/Infobot.py
index d60813a44..bb2f4744f 100755
--- a/plugins/Infobot.py
+++ b/plugins/Infobot.py
@@ -33,7 +33,7 @@ Infobot compatibility, for the parts that we don't support already.
import supybot
-deprecated = True
+#deprecated = True
__revision__ = "$Id$"
__author__ = supybot.authors.jemfinch
@@ -50,6 +50,7 @@ import supybot.dbi as dbi
import supybot.conf as conf
import supybot.utils as utils
import supybot.world as world
+from supybot.commands import *
import supybot.ircmsgs as ircmsgs
import supybot.ircutils as ircutils
import supybot.privmsgs as privmsgs
@@ -58,21 +59,27 @@ import supybot.callbacks as callbacks
conf.registerPlugin('Infobot')
-conf.registerGlobalValue(conf.supybot.plugins.Infobot, 'personality',
+conf.registerChannelValue(conf.supybot.plugins.Infobot, 'personality',
registry.Boolean(True, """Determines whether the bot will respond with
personable (Infobot-like) responses rather than its standard messages."""))
-conf.registerGlobalValue(conf.supybot.plugins.Infobot, 'boringDunno',
+conf.registerChannelValue(conf.supybot.plugins.Infobot, 'boringDunno',
registry.String('Dunno.', """Determines what boring dunno should be given
if supybot.plugins.Infobot.personality is False."""))
-conf.registerGlobalValue(conf.supybot.plugins.Infobot,
- 'snarfUnaddressedDefinitions', registry.Boolean(True, """Determines whether
- the bot will snarf definitions given in the channel that weren't directly
- addressed to it. Of course, no confirmation will be given if the bot isn't
- directly addressed."""))
-conf.registerGlobalValue(conf.supybot.plugins.Infobot,
- 'answerUnaddressedQuestions', registry.Boolean(True, """Determines whether
- the bot will answer questions that weren't directly addressed to it. Of
- course, if it doesn't have an answer, it will remain silent."""))
+
+conf.registerGroup(conf.supybot.plugins.Infobot, 'unaddressed')
+conf.registerChannelValue(conf.supybot.plugins.Infobot.unaddressed,
+ 'snarfDefinitions', registry.Boolean(True, """Determines whether the bot
+ will snarf definitions given in the channel that weren't directly
+ addressed to it. Of course, no confirmation will be given if the bot
+ isn't directly addressed."""))
+conf.registerChannelValue(conf.supybot.plugins.Infobot.unaddressed,
+ 'answerQuestions', registry.Boolean(True, """Determines whether the bot
+ will answer questions that weren't directly addressed to it. Of course,
+ if it doesn't have an answer, it will remain silent."""))
+conf.registerChannelValue(conf.supybot.plugins.Infobot.unaddressed,
+ 'replyExistingFactoid', registry.Boolean(False, """Determines whether the
+ bot will announce that a factoid already exists when it sees a definition
+ for a pre-existing factoid."""))
def configure(advanced):
# This will be called by setup.py to configure this module. Advanced is
@@ -128,94 +135,131 @@ initialAre = {'who': NORESPONSE,
class PickleInfobotDB(object):
def __init__(self, filename):
- self._changes = 0
- self._responses = 0
self.filename = filename
- try:
- fd = file(self.filename)
- except EnvironmentError:
- self._is = utils.InsensitivePreservingDict()
- self._are = utils.InsensitivePreservingDict()
- for (k, v) in initialIs.iteritems():
- self.setIs(k, v)
- for (k, v) in initialAre.iteritems():
- self.setAre(k, v)
- self._changes = 0
- else:
- try:
- (self._is, self._are) = pickle.load(fd)
- except cPickle.UnpicklingError, e:
- raise dbi.InvalidDBError, str(e)
+ self.dbs = ircutils.IrcDict()
+ self.changes = ircutils.IrcDict()
+ self.responses = ircutils.IrcDict()
- def flush(self):
- fd = utils.transactionalFile(self.filename, 'wb')
- pickle.dump((self._is, self._are), fd)
- fd.close()
+ def _getDb(self, channel):
+ filename = plugins.makeChannelFilename(self.filename, channel)
+ if filename in self.dbs:
+ pass
+ elif os.path.exists(filename):
+ fd = file(filename)
+ try:
+ (Is, Are) = pickle.load(fd)
+ self.dbs[filename] = (Is, Are)
+ self.changes[filename] = 0
+ self.responses[filename] = 0
+ except cPickle.UnpicklingError, e:
+ fd.close()
+ raise dbi.InvalidDBError, str(e)
+ fd.close()
+ else:
+ self.dbs[filename] = (utils.InsensitivePreservingDict(),
+ utils.InsensitivePreservingDict())
+ for (k, v) in initialIs.iteritems():
+ self.setIs(channel, k, v)
+ for (k, v) in initialAre.iteritems():
+ self.setAre(channel, k, v)
+ self.changes[filename] = 0
+ self.responses[filename] = 0
+ return (self.dbs[filename], filename)
+
+ def flush(self, db=None, filename=None):
+ if db is None and filename is None:
+ for (filename, db) in self.dbs.iteritems():
+ fd = utils.transactionalFile(filename, 'wb')
+ pickle.dump(db, fd)
+ fd.close()
+ else:
+ fd = utils.transactionalFile(filename, 'wb')
+ pickle.dump(db, fd)
+ fd.close()
+ self.dbs[filename] = db
def close(self):
self.flush()
- def changeIs(self, factoid, replacer):
+ def incChanges(self):
+ filename = dynamic.filename
+ print '*** self.changes: %s' % self.changes
+ self.changes[filename] += 1
+
+ def incResponses(self):
+ self.responses[dynamic.filename] += 1
+
+ def changeIs(self, channel, factoid, replacer):
+ ((Is, Are), filename) = self._getDb(channel)
try:
- old = self._is[factoid]
+ old = Is[factoid]
except KeyError:
raise dbi.NoRecordError
if replacer is not None:
- self._is[factoid] = replacer(old)
- self.flush()
- self._changes += 1
+ Is[factoid] = replacer(old)
+ self.flush((Is, Are), filename)
+ self.incChanges()
- def getIs(self, factoid):
- ret = self._is[factoid]
- self._responses += 1
+ def getIs(self, channel, factoid):
+ ((Is, Are), filename) = self._getDb(channel)
+ ret = Is[factoid]
+ self.incResponses()
return ret
- def setIs(self, fact, oid):
- self._is[fact] = oid
- self.flush()
- self._changes += 1
+ def setIs(self, channel, key, value):
+ ((Is, Are), filename) = self._getDb(channel)
+ Is[key] = value
+ self.flush((Is, Are), filename)
+ self.incChanges()
- def delIs(self, factoid):
+ def delIs(self, channel, factoid):
+ ((Is, Are), filename) = self._getDb(channel)
try:
- del self._is[factoid]
+ Is.pop(factoid)
except KeyError:
raise dbi.NoRecordError
- self.flush()
- self._changes += 1
+ self.flush((Is, Are), filename)
+ self.incChanges()
- def hasIs(self, factoid):
- return factoid in self._is
+ def hasIs(self, channel, factoid):
+ ((Is, Are), _) = self._getDb(channel)
+ return factoid in Is
- def changeAre(self, factoid, replacer):
+ def changeAre(self, channel, factoid, replacer):
+ ((Is, Are), filename) = self._getDb(channel)
try:
- old = self._are[factoid]
+ old = Are[factoid]
except KeyError:
raise dbi.NoRecordError
if replacer is not None:
- self._are[factoid] = replacer(old)
- self._changes += 1
- self.flush()
+ Are[factoid] = replacer(old)
+ self.flush((Is, Are), filename)
+ self.incChanges()
- def getAre(self, factoid):
- ret = self._are[factoid]
- self._responses += 1
+ def getAre(self, channel, factoid):
+ ((Is, Are), filename) = self._getDb(channel)
+ ret = Are[factoid]
+ self.incResponses()
return ret
- def hasAre(self, factoid):
- return factoid in self._are
+ def hasAre(self, channel, factoid):
+ ((Is, Are), _) = self._getDb(channel)
+ return factoid in Are
- def setAre(self, fact, oid):
- self._are[fact] = oid
- self.flush()
- self._changes += 1
+ def setAre(self, channel, key, value):
+ ((Is, Are), filename) = self._getDb(channel)
+ Are[key] = value
+ self.flush((Is, Are), filename)
+ self.incChanges()
- def delAre(self, factoid):
+ def delAre(self, channel, factoid):
+ ((Is, Are), filename) = self._getDb(channel)
try:
- del self._are[factoid]
+ Are.pop(factoid)
except KeyError:
raise dbi.NoRecordError
- self.flush()
- self._changes += 1
+ self.flush((Is, Are), filename)
+ self.incChanges()
def getDunno(self):
return random.choice(dunnos) + random.choice(ends)
@@ -223,33 +267,46 @@ class PickleInfobotDB(object):
def getConfirm(self):
return random.choice(confirms) + random.choice(ends)
- def getChangeCount(self):
- return self._changes
+ def getChangeCount(self, channel):
+ (_, filename) = self._getDb(channel)
+ return self.changes[filename]
- def getResponseCount(self):
- return self._responses
+ def getResponseCount(self, channel):
+ (_, filename) = self._getDb(channel)
+ return self.responses[filename]
- def getNumFacts(self):
- return len(self._are.keys()) + len(self._is.keys())
+ def getNumFacts(self, channel):
+ ((Is, Are), _) = self._getDb(channel)
+ return len(Are.keys()) + len(Is.keys())
class SqliteInfobotDB(object):
def __init__(self, filename):
+ self.filename = filename
+ self.dbs = ircutils.IrcDict()
+ self.changes = ircutils.IrcDict()
+ self.responses = ircutils.IrcDict()
+
+ def _getDb(self, channel):
try:
import sqlite
except ImportError:
raise callbacks.Error, 'You need to have PySQLite installed to '\
'use this plugin. Download it at '\
''
- self._changes = 0
- self._responses = 0
- self.filename = filename
try:
- if os.path.exists(self.filename):
- self.db = sqlite.connect(self.filename)
- return self.db
- #else:
- self.db = sqlite.connect(self.filename)
- cursor = self.db.cursor()
+ filename = plugins.makeChannelFilename(self.filename, channel)
+ if filename not in self.changes:
+ self.changes[filename] = 0
+ if filename not in self.responses:
+ self.responses[filename] = 0
+ if filename in self.dbs:
+ return (self.dbs[filename], filename)
+ if os.path.exists(filename):
+ self.dbs[filename] = sqlite.connect(filename)
+ return (self.dbs[filename], filename)
+ db = sqlite.connect(filename)
+ self.dbs[filename] = db
+ cursor = db.cursor()
cursor.execute("""CREATE TABLE isFacts (
key TEXT UNIQUE ON CONFLICT REPLACE,
value TEXT
@@ -258,20 +315,31 @@ class SqliteInfobotDB(object):
key TEXT UNIQUE ON CONFLICT REPLACE,
value TEXT
);""")
- self.db.commit()
+ db.commit()
for (k, v) in initialIs.iteritems():
- self.setIs(k, v)
+ self.setIs(channel, k, v)
for (k, v) in initialAre.iteritems():
- self.setAre(k, v)
- self._changes = 0
+ self.setAre(channel, k, v)
+ self.changes[filename] = 0
+ self.responses[filename] = 0
+ return (db, filename)
except sqlite.DatabaseError, e:
raise dbi.InvalidDBError, str(e)
def close(self):
- self.db.close()
+ for db in self.dbs.itervalues():
+ db.close()
+ self.dbs.clear()
- def changeIs(self, factoid, replacer):
- cursor = self.db.cursor()
+ def incChanges(self):
+ self.changes[dynamic.filename] += 1
+
+ def incResponses(self):
+ self.changes[dynamic.filename] += 1
+
+ def changeIs(self, channel, factoid, replacer):
+ (db, filename) = self._getDb(channel)
+ cursor = db.cursor()
cursor.execute("""SELECT value FROM isFacts WHERE key=%s""", factoid)
if cursor.rowcount == 0:
raise dbi.NoRecordError
@@ -279,37 +347,42 @@ class SqliteInfobotDB(object):
if replacer is not None:
cursor.execute("""UPDATE isFacts SET value=%s WHERE key=%s""",
replacer(old), factoid)
- self.db.commit()
- self._changes += 1
+ db.commit()
+ self.incChanges()
- def getIs(self, factoid):
- cursor = self.db.cursor()
+ def getIs(self, channel, factoid):
+ (db, filename) = self._getDb(channel)
+ cursor = db.cursor()
cursor.execute("""SELECT value FROM isFacts WHERE key=%s""", factoid)
ret = cursor.fetchone()[0]
- self._responses += 1
+ self.incResponses()
return ret
- def setIs(self, fact, oid):
- cursor = self.db.cursor()
+ def setIs(self, channel, fact, oid):
+ (db, filename) = self._getDb(channel)
+ cursor = db.cursor()
cursor.execute("""INSERT INTO isFacts VALUES (%s, %s)""", fact, oid)
- self.db.commit()
- self._changes += 1
+ db.commit()
+ self.incChanges()
- def delIs(self, factoid):
- cursor = self.db.cursor()
+ def delIs(self, channel, factoid):
+ (db, filename) = self._getDb(channel)
+ cursor = db.cursor()
cursor.execute("""DELETE FROM isFacts WHERE key=%s""", factoid)
if cursor.rowcount == 0:
raise dbi.NoRecordError
- self.db.commit()
- self._changes += 1
+ db.commit()
+ self.incChanges()
- def hasIs(self, factoid):
- cursor = self.db.cursor()
+ def hasIs(self, channel, factoid):
+ (db, _) = self._getDb(channel)
+ cursor = db.cursor()
cursor.execute("""SELECT * FROM isFacts WHERE key=%s""", factoid)
return cursor.rowcount == 1
- def changeAre(self, factoid, replacer):
- cursor = self.db.cursor()
+ def changeAre(self, channel, factoid, replacer):
+ (db, filename) = self._getDb(channel)
+ cursor = db.cursor()
cursor.execute("""SELECT value FROM areFacts WHERE key=%s""", factoid)
if cursor.rowcount == 0:
raise dbi.NoRecordError
@@ -317,32 +390,36 @@ class SqliteInfobotDB(object):
if replacer is not None:
cursor.execute("""UPDATE areFacts SET value=%s WHERE key=%s""",
replacer(old), factoid)
- self.db.commit()
- self._changes += 1
+ db.commit()
+ self.incChanges()
- def getAre(self, factoid):
- cursor = self.db.cursor()
+ def getAre(self, channel, factoid):
+ (db, filename) = self._getDb(channel)
+ cursor = db.cursor()
cursor.execute("""SELECT value FROM areFacts WHERE key=%s""", factoid)
ret = cursor.fetchone()[0]
- self._responses += 1
+ self.incResponses()
return ret
- def setAre(self, fact, oid):
- cursor = self.db.cursor()
+ def setAre(self, channel, fact, oid):
+ (db, filename) = self._getDb(channel)
+ cursor = db.cursor()
cursor.execute("""INSERT INTO areFacts VALUES (%s, %s)""", fact, oid)
- self.db.commit()
- self._changes += 1
+ db.commit()
+ self.incChanges()
- def delAre(self, factoid):
- cursor = self.db.cursor()
+ def delAre(self, channel, factoid):
+ (db, filename) = self._getDb(channel)
+ cursor = db.cursor()
cursor.execute("""DELETE FROM areFacts WHERE key=%s""", factoid)
if cursor.rowcount == 0:
raise dbi.NoRecordError
- self.db.commit()
- self._changes += 1
+ db.commit()
+ self.incChanges()
- def hasAre(self, factoid):
- cursor = self.db.cursor()
+ def hasAre(self, channel, factoid):
+ (db, _) = self._getDb(channel)
+ cursor = db.cursor()
cursor.execute("""SELECT * FROM areFacts WHERE key=%s""", factoid)
return cursor.rowcount == 1
@@ -352,14 +429,23 @@ class SqliteInfobotDB(object):
def getConfirm(self):
return random.choice(confirms) + random.choice(ends)
- def getChangeCount(self):
- return self._changes
+ def getChangeCount(self, channel):
+ (_, filename) = self._getDb(channel)
+ try:
+ return self.changes[filename]
+ except KeyError:
+ return 0
- def getResponseCount(self):
- return self._responses
+ def getResponseCount(self, channel):
+ (_, filename) = self._getDb(channel)
+ try:
+ return self.responses[filename]
+ except KeyError:
+ return 0
- def getNumFacts(self):
- cursor = self.db.cursor()
+ def getNumFacts(self, channel):
+ (db, _) = self._getDb(channel)
+ cursor = db.cursor()
cursor.execute("""SELECT COUNT(*) FROM areFacts""")
areFacts = int(cursor.fetchone()[0])
cursor.execute("""SELECT COUNT(*) FROM isFacts""")
@@ -375,34 +461,32 @@ class Dunno(Exception):
pass
class Infobot(callbacks.PrivmsgCommandAndRegexp):
- regexps = ['doForget', 'doChange', 'doFactoid', 'doUnknown']
+ regexps = ['doForce', 'doForget', 'doFactoid', 'doUnknown']
+ addressedRegexps = ['doForce', 'doForget', 'doChange', 'doFactoid', 'doUnknown']
def __init__(self):
self.__parent = super(Infobot, self)
self.__parent.__init__()
- try:
- self.db = InfobotDB()
- except Exception:
- self.log.exception('Error loading %s:', self.filename)
- raise # So it doesn't get loaded without its database.
+ self.db = InfobotDB()
self.irc = None
self.msg = None
- self.force = False
self.replied = True
- self.badForce = False
- self.addressed = False
- self.calledDoPrivmsg = False
+ self.changed = False
+ self.added = False
def die(self):
self.__parent.die()
self.db.close()
+ def reset(self):
+ self.db.close()
+
def _error(self, s):
- if self.addressed:
+ if msg.addressed:
self.irc.error(s)
else:
self.log.warning(s)
- def reply(self, s, irc=None, msg=None, action=False):
+ def reply(self, s, irc=None, msg=None, action=False, substitute=True):
if self.replied:
self.log.debug('Already replied, not replying again.')
return
@@ -413,8 +497,9 @@ class Infobot(callbacks.PrivmsgCommandAndRegexp):
assert self.msg is not None
msg = self.msg
self.replied = True
- irc.reply(ircutils.standardSubstitute(irc, msg, s),
- prefixName=False, action=action, msg=msg)
+ if substitute:
+ s = ircutils.standardSubstitute(irc, msg, s)
+ irc.reply(s, prefixName=False, action=action, msg=msg)
def confirm(self, irc=None, msg=None):
if self.registryValue('personality'):
@@ -429,26 +514,40 @@ class Infobot(callbacks.PrivmsgCommandAndRegexp):
else:
self.reply(self.registryValue('boringDunno'), irc=irc, msg=msg)
- def factoid(self, key, irc=None, msg=None, dunno=True, prepend=''):
+ def factoid(self, key, irc=None, msg=None, dunno=True, prepend='',
+ isAre=None):
if irc is None:
assert self.irc is not None
irc = self.irc
if msg is None:
assert self.msg is not None
msg = self.msg
- isAre = None
+ if isAre is not None:
+ isAre = isAre.lower()
+ channel = dynamic.channel
try:
- if self.db.hasIs(key):
- isAre = 'is'
- value = self.db.getIs(key)
- elif self.db.hasAre(key):
- isAre = 'are'
- value = self.db.getAre(key)
+ if isAre is None:
+ if self.db.hasIs(channel, key):
+ isAre = 'is'
+ value = self.db.getIs(channel, key)
+ elif self.db.hasAre(channel, key):
+ isAre = 'are'
+ value = self.db.getAre(channel, key)
+ elif isAre == 'is':
+ if not self.db.hasIs(channel, key):
+ isAre = None
+ else:
+ value = self.db.getIs(channel, key)
+ elif isAre == 'are':
+ if not self.db.hasAre(channel, key):
+ isAre = None
+ else:
+ value = self.db.getAre(channel, key)
except dbi.InvalidDBError, e:
self._error('Unable to access db: %s' % e)
return
if isAre is None:
- if self.addressed:
+ if msg.addressed:
if dunno:
self.dunno(irc=irc, msg=msg)
else:
@@ -481,72 +580,28 @@ class Infobot(callbacks.PrivmsgCommandAndRegexp):
return s
_forceRe = re.compile(r'^no[,: -]+', re.I)
- _karmaRe = re.compile(r'^(?:\S+|\(.+\))(?:\+\+|--)(?:\s+)?$')
+ _karmaRe = re.compile(r'(?:\+\+|--)(?:\s+)?$')
def doPrivmsg(self, irc, msg):
- if msg.repliedTo:
- self.log.debug('Returning early from doPrivmsg: msg.repliedTo.')
- return
- if ircmsgs.isCtcp(msg):
- self.log.debug('Returning early from doPrivmsg: isCtcp(msg).')
- return
- if self.calledDoPrivmsg:
- self.log.debug('Returning early from doPrivmsg: calledDoPrivmsg.')
- self.calledDoPrivmsg = False
- return
try:
- maybeAddressed = callbacks.addressed(irc.nick, msg,
- whenAddressedByNick=True)
- if maybeAddressed:
- self.addressed = True
- payload = maybeAddressed
- else:
- payload = msg.args[1]
- if self._karmaRe.search(payload):
- self.log.debug('Not snarfing a karma adjustment.')
+ if msg.repliedTo:
+ self.replied = True
+ if ircmsgs.isCtcp(msg):
+ self.log.debug('Returning early from doPrivmsg: isCtcp(msg).')
return
- payload = self.normalize(payload)
- maybeForced = self._forceRe.sub('', payload)
- if maybeForced != payload:
- self.force = True
- # Infobot requires that forces have the form "no, botname, ..."
- # We think that's stupid to require the bot name if the bot is
- # being directly addressed. The following makes sure both
- # "botname: no, botname, ..." and "botname: no, ..." work the
- # same and non-addressed forms require the bots nick.
- nick = irc.nick.lower()
- if not self.addressed:
- if not maybeForced.lower().startswith(nick):
- self.badForce = True
- self.force = False
- if maybeForced.lower().startswith(nick):
- maybeForced = maybeForced[len(nick):].lstrip(', ')
- payload = maybeForced
- # Let's make sure we dump out of Infobot if the privmsg is an
- # actual command otherwise we could get multiple responses.
- if self.addressed and '=~' not in payload:
- payload += '?'
- if payload.endswith(irc.nick):
- self.addressed = True
- payload = payload[:-len(irc.nick)]
- payload = payload.strip(', ') # Strip punctuation before nick.
- payload += '?' # So doUnknown gets called.
- if not payload.strip():
- self.log.debug('Bailing since we received an empty msg.')
+ if self._karmaRe.search(msg.args[1]):
+ self.log.debug('Returning early from doPrivmsg: karma.')
return
+ # For later dynamic scoping
+ channel = plugins.getChannel(msg.args[0])
+ payload = self.normalize(msg.args[1])
msg = ircmsgs.IrcMsg(args=(msg.args[0], payload), msg=msg)
self.__parent.doPrivmsg(irc, msg)
finally:
- self.force = False
self.replied = False
- self.badForce = False
- self.addressed = False
-
- def tokenizedCommand(self, irc, msg, tokens):
- self.doPrivmsg(irc, msg)
- self.calledDoPrivmsg = True
+ self.changed = False
+ self.added = False
def callCommand(self, name, irc, msg, *L, **kwargs):
- #print '***', name, utils.stackTrace()
try:
self.irc = irc
self.msg = msg
@@ -561,7 +616,7 @@ class Infobot(callbacks.PrivmsgCommandAndRegexp):
deleted = False
for method in [self.db.delIs, self.db.delAre]:
try:
- method(fact)
+ method(dynamic.channel, fact)
deleted = True
except dbi.NoRecordError:
pass
@@ -571,6 +626,41 @@ class Infobot(callbacks.PrivmsgCommandAndRegexp):
# XXX: Should this be genericified?
self.reply('I\'ve never heard of %s, %s!' % (fact, msg.nick))
+ def doForce(self, irc, msg, match):
+ r"^no,\s+(\w+,\s+)?(.+?)\s+(? [about]
Tells about .
"""
- if len(args) < 2:
- raise callbacks.ArgumentError
- if args[1] == 'about':
- del args[1]
- (nick, factoid) = privmsgs.getArgs(args, required=2)
try:
hostmask = irc.state.nickToHostmask(nick)
except KeyError:
irc.error('I haven\'t seen %s, I\'ll let you '
- 'do the telling.' % nick)
- return
+ 'do the telling.' % nick, Raise=True)
newmsg = ircmsgs.privmsg(irc.nick, factoid+'?', prefix=hostmask)
try:
prepend = '%s wants you to know that ' % msg.nick
self.factoid(factoid, msg=newmsg, prepend=prepend)
except Dunno:
self.dunno()
+ tell = wrap(tell, ['channeldb', 'something',
+ optional(('literal', 'about')), 'text'])
Class = Infobot
diff --git a/test/test_Infobot.py b/test/test_Infobot.py
index c55ba0585..ac2779789 100644
--- a/test/test_Infobot.py
+++ b/test/test_Infobot.py
@@ -29,122 +29,116 @@
from testsupport import *
-try:
- import sqlite
-except ImportError:
- sqlite = None
+import supybot.plugins.Infobot
+confirms = supybot.plugins.Infobot.confirms
+dunnos = supybot.plugins.Infobot.dunnos
+ibot = conf.supybot.plugins.Infobot
-if sqlite is not None:
- import supybot.plugins.Infobot
- confirms = supybot.plugins.Infobot.confirms
- dunnos = supybot.plugins.Infobot.dunnos
- ibot = conf.supybot.plugins.Infobot
+class InfobotTestCase(ChannelPluginTestCase):
+ plugins = ('Infobot',)
+ _endRe = re.compile(r'!|, \S+\.|\.')
+ def testIsSnarf(self):
+ learn = ibot.unaddressed.snarfDefinitions()
+ answer = ibot.unaddressed.answerQuestions()
+ try:
+ ibot.unaddressed.snarfDefinitions.setValue(True)
+ ibot.unaddressed.answerQuestions.setValue(True)
+ self.assertSnarfNoResponse('foo is at http://bar.com/', 2)
+ self.assertRegexp('infobot stats', '1 modification')
+ self.assertRegexp('infobot status', '1 modification')
+ self.assertSnarfRegexp('foo?', r'http://bar.com/')
+ self.assertSnarfNoResponse('foo is at http://baz.com/', 2)
+ self.assertSnarfNotRegexp('foo?', 'baz')
+ m = self.getMsg('bar is at http://foo.com/')
+ self.failUnless(self._endRe.sub('', m.args[1]) in confirms)
+ self.assertRegexp('bar?', r'bar.*is.*http://foo.com/')
+ finally:
+ ibot.unaddressed.snarfDefinitions.setValue(learn)
+ ibot.unaddressed.answerQuestions.setValue(answer)
- class InfobotTestCase(ChannelPluginTestCase):
- plugins = ('Infobot', 'Karma')
- _endRe = re.compile(r'!|, \S+\.|\.')
- def testIsSnarf(self):
- learn = ibot.snarfUnaddressedDefinitions()
- answer = ibot.answerUnaddressedQuestions()
- try:
- ibot.snarfUnaddressedDefinitions.setValue(True)
- ibot.answerUnaddressedQuestions.setValue(True)
- self.assertSnarfNoResponse('foo is at http://bar.com/', 2)
- self.assertRegexp('infobot stats', '1 modification')
- self.assertRegexp('infobot status', '1 modification')
- self.assertSnarfRegexp('foo?', r'foo.*is.*http://bar.com/')
- self.assertSnarfNoResponse('foo is at http://baz.com/', 2)
- self.assertSnarfNotRegexp('foo?', 'baz')
- m = self.getMsg('bar is at http://foo.com/')
- self.failUnless(self._endRe.sub('', m.args[1]) in confirms)
- self.assertRegexp('bar?', r'bar.*is.*http://foo.com/')
- finally:
- ibot.snarfUnaddressedDefinitions.setValue(learn)
- ibot.answerUnaddressedQuestions.setValue(answer)
+ def testAreSnarf(self):
+ learn = ibot.unaddressed.snarfDefinitions()
+ answer = ibot.unaddressed.answerQuestions()
+ try:
+ ibot.unaddressed.snarfDefinitions.setValue(True)
+ ibot.unaddressed.answerQuestions.setValue(True)
+ self.assertSnarfNoResponse('bars are dirty', 2)
+ self.assertSnarfRegexp('bars?', 'bars.*are.*dirty')
+ self.assertSnarfNoResponse('bars are not dirty', 2)
+ self.assertSnarfNotRegexp('bars?', 'not')
+ finally:
+ ibot.unaddressed.snarfDefinitions.setValue(learn)
+ ibot.unaddressed.answerQuestions.setValue(answer)
- def testAreSnarf(self):
- learn = ibot.snarfUnaddressedDefinitions()
- answer = ibot.answerUnaddressedQuestions()
- try:
- ibot.snarfUnaddressedDefinitions.setValue(True)
- ibot.answerUnaddressedQuestions.setValue(True)
- self.assertSnarfNoResponse('bars are dirty', 2)
- self.assertSnarfRegexp('bars?', 'bars.*are.*dirty')
- self.assertSnarfNoResponse('bars are not dirty', 2)
- self.assertSnarfNotRegexp('bars?', 'not')
- finally:
- ibot.snarfUnaddressedDefinitions.setValue(learn)
- ibot.answerUnaddressedQuestions.setValue(answer)
+ def testIsResponses(self):
+ learn = ibot.unaddressed.snarfDefinitions()
+ answer = ibot.unaddressed.answerQuestions()
+ try:
+ ibot.unaddressed.snarfDefinitions.setValue(True)
+ ibot.unaddressed.answerQuestions.setValue(True)
+ self.assertSnarfNoResponse('foo is bar', 2)
+ self.assertSnarfRegexp('foo?', 'foo.*is.*bar')
+ self.assertSnarfNoResponse('when is foo?', 2)
+ self.assertSnarfNoResponse('why is foo?', 2)
+ self.assertSnarfNoResponse('why foo?', 2)
+ self.assertSnarfNoResponse('when is foo?', 2)
+ finally:
+ ibot.unaddressed.snarfDefinitions.setValue(learn)
+ ibot.unaddressed.answerQuestions.setValue(answer)
- def testIsResponses(self):
- learn = ibot.snarfUnaddressedDefinitions()
- answer = ibot.answerUnaddressedQuestions()
- try:
- ibot.snarfUnaddressedDefinitions.setValue(True)
- ibot.answerUnaddressedQuestions.setValue(True)
- self.assertSnarfNoResponse('foo is bar', 2)
- self.assertSnarfRegexp('foo?', 'foo.*is.*bar')
- self.assertSnarfNoResponse('when is foo?', 2)
- self.assertSnarfNoResponse('why is foo?', 2)
- self.assertSnarfNoResponse('why foo?', 2)
- self.assertSnarfNoResponse('when is foo?', 2)
- finally:
- ibot.snarfUnaddressedDefinitions.setValue(learn)
- ibot.answerUnaddressedQuestions.setValue(answer)
+ def testAnswerUnaddressed(self):
+ answer = ibot.unaddressed.answerQuestions()
+ try:
+ ibot.unaddressed.answerQuestions.setValue(True)
+ self.assertSnarfNoResponse('foo is bar')
+ self.assertSnarfRegexp('foo?', 'bar')
+ ibot.unaddressed.answerQuestions.setValue(False)
+ self.assertSnarfNoResponse('foo?', 2)
+ finally:
+ ibot.unaddressed.answerQuestions.setValue(answer)
- def testAnswerUnaddressed(self):
- answer = ibot.answerUnaddressedQuestions()
- try:
- ibot.answerUnaddressedQuestions.setValue(True)
- self.assertSnarfNoResponse('foo is bar')
- self.assertSnarfRegexp('foo?', 'bar')
- ibot.answerUnaddressedQuestions.setValue(False)
- self.assertSnarfNoResponse('foo?', 2)
- finally:
- ibot.answerUnaddressedQuestions.setValue(answer)
+ def testReplaceFactoid(self):
+ answer = ibot.unaddressed.answerQuestions()
+ learn = ibot.unaddressed.snarfDefinitions()
+ try:
+ ibot.unaddressed.answerQuestions.setValue(True)
+ ibot.unaddressed.snarfDefinitions.setValue(True)
+ self.assertSnarfNoResponse('forums are good')
+ self.assertSnarfRegexp('forums?', 'good')
+ self.assertNotError('no, forums are evil')
+ self.assertSnarfRegexp('forums?', 'evil')
+ finally:
+ ibot.unaddressed.answerQuestions.setValue(answer)
+ ibot.unaddressed.snarfDefinitions.setValue(learn)
- def testReplaceFactoid(self):
- answer = ibot.answerUnaddressedQuestions()
- learn = ibot.snarfUnaddressedDefinitions()
- try:
- ibot.answerUnaddressedQuestions.setValue(True)
- ibot.snarfUnaddressedDefinitions.setValue(True)
- self.assertSnarfNoResponse('forums are good')
- self.assertSnarfRegexp('forums?', 'good')
- self.assertNotError('no, forums are evil')
- self.assertSnarfRegexp('forums?', 'evil')
- finally:
- ibot.answerUnaddressedQuestions.setValue(answer)
- ibot.snarfUnaddressedDefinitions.setValue(learn)
+ def testDoubleIsAre(self):
+ answer = ibot.unaddressed.answerQuestions()
+ learn = ibot.unaddressed.snarfDefinitions()
+ try:
+ ibot.unaddressed.answerQuestions.setValue(True)
+ ibot.unaddressed.snarfDefinitions.setValue(True)
+ self.assertSnarfNoResponse('foo is foo is bar')
+ self.assertSnarfRegexp('foo?', 'foo is bar')
+ self.assertSnarfNoResponse('bars are bars are good')
+ self.assertSnarfRegexp('bars?', 'bars are good')
+ self.assertSnarfNoResponse('bees are honey is good')
+ self.assertSnarfRegexp('bees?', 'honey is good')
+ self.assertSnarfNoResponse('food is tacos are good')
+ self.assertSnarfRegexp('food?', 'tacos are good')
+ finally:
+ ibot.unaddressed.answerQuestions.setValue(answer)
+ ibot.unaddressed.snarfDefinitions.setValue(learn)
- def testDoubleIsAre(self):
- answer = ibot.answerUnaddressedQuestions()
- learn = ibot.snarfUnaddressedDefinitions()
- try:
- ibot.answerUnaddressedQuestions.setValue(True)
- ibot.snarfUnaddressedDefinitions.setValue(True)
- self.assertSnarfNoResponse('foo is foo is bar')
- self.assertSnarfRegexp('foo?', 'foo is bar')
- self.assertSnarfNoResponse('bars are bars are good')
- self.assertSnarfRegexp('bars?', 'bars are good')
- self.assertSnarfNoResponse('bees are honey is good')
- self.assertSnarfRegexp('bees?', 'honey is good')
- self.assertSnarfNoResponse('food is tacos are good')
- self.assertSnarfRegexp('food?', 'tacos are good')
- finally:
- ibot.answerUnaddressedQuestions.setValue(answer)
- ibot.snarfUnaddressedDefinitions.setValue(learn)
+# def testNoKarmaDunno(self):
+# self.assertNoResponse('foo++')
- def testNoKarmaDunno(self):
- self.assertNoResponse('foo++')
+ def testPredefinedFactoids(self):
+ self.assertSnarfNoResponse('what?', 3)
+ self.assertRegexp('roses?', 'roses are red')
- def testPredefinedFactoids(self):
- self.assertSnarfNoResponse('what?', 3)
- self.assertRegexp('roses?', 'roses are red')
-
- def testAddressedQuestions(self):
- self.assertNotError('hi is Hello, $who.')
- self.assertSnarfRegexp('hi', 'Hello')
- self.assertRegexp('hi', 'Hello')
+ def testAddressedQuestions(self):
+ self.assertNotError('hi is Hello, $who.')
+ self.assertSnarfNoResponse('hi')
+ self.assertRegexp('hi', 'Hello')
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: