Fix some problems in Infobot.py's sqlite implementation and genericize

some other errors to better fit in with db abstraction
This commit is contained in:
James Vega 2004-08-17 20:01:23 +00:00
parent 376e67def3
commit 72f36efc18
3 changed files with 86 additions and 35 deletions

View File

@ -43,6 +43,7 @@ import re
import random
import cPickle as pickle
import supybot.dbi as dbi
import supybot.conf as conf
import supybot.utils as utils
import supybot.ircmsgs as ircmsgs
@ -106,7 +107,10 @@ class PickleInfobotDB(object):
self._is = utils.InsensitivePreservingDict()
self._are = utils.InsensitivePreservingDict()
else:
try:
(self._is, self._are) = pickle.load(fd)
except cPickle.UnpicklingError, e:
raise dbi.InvalidDBError, str(e)
self._changes = 0
self._responses = 0
@ -119,7 +123,10 @@ class PickleInfobotDB(object):
self.flush()
def changeIs(self, factoid, replacer):
try:
old = self._is[factoid]
except KeyError:
raise dbi.NoRecordError
if replacer is not None:
self._is[factoid] = replacer(old)
self.flush()
@ -136,7 +143,10 @@ class PickleInfobotDB(object):
self._changes += 1
def delIs(self, factoid):
try:
del self._is[factoid]
except KeyError:
raise dbi.NoRecordError
self.flush()
self._changes += 1
@ -144,7 +154,10 @@ class PickleInfobotDB(object):
return factoid in self._is
def changeAre(self, factoid, replacer):
try:
old = self._are[factoid]
except KeyError:
raise dbi.NoRecordError
if replacer is not None:
self._are[factoid] = replacer(old)
self._changes += 1
@ -164,7 +177,10 @@ class PickleInfobotDB(object):
self._changes += 1
def delAre(self, factoid):
try:
del self._are[factoid]
except KeyError:
raise dbi.NoRecordError
self.flush()
self._changes += 1
@ -186,21 +202,24 @@ class SqliteInfobotDB(object):
self._responses = 0
def _getDb(self):
try:
if os.path.exists(filename):
return sqlite.connect(filename)
#else:
db = sqlite.connect(filename)
cursor = db.cursor()
cursor.execute("""CREATE TABLE isFacts (
key TEXT PRIMARY KEY,
key TEXT UNIQUE ON CONFLICT REPLACE,
value TEXT
);""")
cursor.execute("""CREATE TABLE areFacts (
key TEXT PRIMARY KEY,
key TEXT UNIQUE ON CONFLICT REPLACE,
value TEXT
);""")
db.commit()
return db
except sqlite.DatabaseError, e:
raise dbi.InvalidDBError, str(e)
def close(self):
pass
@ -209,6 +228,8 @@ class SqliteInfobotDB(object):
db = self._getDb()
cursor = db.cursor()
cursor.execute("""SELECT value FROM isFacts WHERE key=%s""", factoid)
if cursor.rowcount == 0:
raise dbi.NoRecordError
old = cursor.fetchone()[0]
if replacer is not None:
cursor.execute("""UPDATE isFacts SET value=%s WHERE key=%s""",
@ -235,6 +256,8 @@ class SqliteInfobotDB(object):
db = self._getDb()
cursor = db.cursor()
cursor.execute("""DELETE FROM isFacts WHERE key=%s""", factoid)
if cursor.rowcount == 0:
raise dbi.NoRecordError
db.commit()
self._changes += 1
@ -248,6 +271,8 @@ class SqliteInfobotDB(object):
db = self._getDb()
cursor = db.cursor()
cursor.execute("""SELECT value FROM areFacts WHERE key=%s""", factoid)
if cursor.rowcount == 0:
raise dbi.NoRecordError
old = cursor.fetchone()[0]
if replacer is not None:
cursor.execute("""UPDATE areFacts SET value=%s WHERE key=%s""",
@ -274,6 +299,8 @@ class SqliteInfobotDB(object):
db = self._getDb()
cursor = db.cursor()
cursor.execute("""DELETE FROM areFacts WHERE key=%s""", factoid)
if cursor.rowcount == 0:
raise dbi.NoRecordError
db.commit()
self._changes += 1
@ -320,6 +347,12 @@ class Infobot(callbacks.PrivmsgCommandAndRegexp):
def die(self):
self.db.close()
def _error(self, s):
if self.addressed:
self.irc.error(s)
else:
self.log.warning(s)
def reply(self, s, irc=None, msg=None, action=False):
if self.replied:
self.log.debug('Already replied, not replying again.')
@ -355,12 +388,16 @@ class Infobot(callbacks.PrivmsgCommandAndRegexp):
assert self.msg is not None
msg = self.msg
isAre = None
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)
except dbi.InvalidDBError:
self._error('Unable to access db: %s' % e)
return
if isAre is None:
if self.addressed:
if dunno:
@ -388,7 +425,7 @@ class Infobot(callbacks.PrivmsgCommandAndRegexp):
s = s.strip() # After stripFormatting for formatted spaces.
s = utils.normalizeWhitespace(s)
contractions = [('what\'s', 'what is'), ('where\'s', 'where is'),
('who\'s', 'who is'),]
('who\'s', 'who is'), ('wtf\'s', 'wtf is'),]
for (contraction, replacement) in contractions:
if s.startswith(contraction):
s = replacement + s[len(contraction):]
@ -467,7 +504,7 @@ class Infobot(callbacks.PrivmsgCommandAndRegexp):
try:
method(fact)
deleted = True
except KeyError:
except dbi.NoRecordError:
pass
if deleted:
self.confirm()
@ -492,7 +529,7 @@ class Infobot(callbacks.PrivmsgCommandAndRegexp):
try:
method(fact, r)
changed = True
except KeyError:
except dbi.NoRecordError:
pass
if changed:
self.confirm()
@ -501,7 +538,7 @@ class Infobot(callbacks.PrivmsgCommandAndRegexp):
irc.reply('I\'ve never heard of %s, %s!' % (fact, msg.nick))
def doUnknown(self, irc, msg, match):
r"^(.+?)\?[?!. ]*$"
r"^(.+?)\s*\?[?!. ]*$"
key = match.group(1)
if self.addressed or self.registryValue('answerUnaddressedQuestions'):
self.factoid(key) # Does the dunno'ing for us itself.
@ -513,7 +550,7 @@ class Infobot(callbacks.PrivmsgCommandAndRegexp):
r"^(.+)\s+(?<!\\)(was|is|am|were|are)\s+(also\s+)?(.+?)[?!. ]*$"
(key, isAre, also, value) = match.groups()
key = key.replace('\\', '')
if key.lower() in ('where', 'what', 'who'):
if key.lower() in ('where', 'what', 'who', 'wtf'):
# It's a question.
if self.addressed or \
self.registryValue('answerUnaddressedQuestions'):

View File

@ -51,6 +51,9 @@ class Error(Exception):
class NoRecordError(KeyError):
pass
class InvalidDBError(Exception):
pass
class MappingInterface(object):
"""This is a class to represent the underlying representation of a map
from integer keys to strings."""

View File

@ -34,12 +34,12 @@ from testsupport import *
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):
ibot = conf.supybot.plugins.Infobot
learn = ibot.snarfUnaddressedDefinitions()
answer = ibot.answerUnaddressedQuestions()
try:
@ -57,7 +57,6 @@ class InfobotTestCase(ChannelPluginTestCase):
ibot.answerUnaddressedQuestions.setValue(answer)
def testAreSnarf(self):
ibot = conf.supybot.plugins.Infobot
learn = ibot.snarfUnaddressedDefinitions()
answer = ibot.answerUnaddressedQuestions()
try:
@ -72,7 +71,6 @@ class InfobotTestCase(ChannelPluginTestCase):
ibot.answerUnaddressedQuestions.setValue(answer)
def testIsResponses(self):
ibot = conf.supybot.plugins.Infobot
learn = ibot.snarfUnaddressedDefinitions()
answer = ibot.answerUnaddressedQuestions()
try:
@ -89,7 +87,6 @@ class InfobotTestCase(ChannelPluginTestCase):
ibot.answerUnaddressedQuestions.setValue(answer)
def testAnswerUnaddressed(self):
ibot = conf.supybot.plugins.Infobot
answer = ibot.answerUnaddressedQuestions()
try:
ibot.answerUnaddressedQuestions.setValue(True)
@ -100,4 +97,18 @@ class InfobotTestCase(ChannelPluginTestCase):
finally:
ibot.answerUnaddressedQuestions.setValue(answer)
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)
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: