This commit is contained in:
Jeremy Fincher 2004-04-14 10:13:53 +00:00
parent b15b85ea7c
commit 1cb8cd0933
3 changed files with 179 additions and 143 deletions

View File

@ -1,3 +1,7 @@
* Added supybot.plugins.WordStats.ignoreQueries, which, when
true, makes the bot ignore queries (and not increment its word
statistics).
* Added the LogToIrc plugin, for sending logs to an IRC * Added the LogToIrc plugin, for sending logs to an IRC
channel or nick. Useful for traceback notification and whatnot. channel or nick. Useful for traceback notification and whatnot.

View File

@ -51,11 +51,13 @@ import registry
import callbacks import callbacks
conf.registerPlugin('WordStats') conf.registerPlugin('WordStats')
conf.registerChannelValue(conf.supybot.plugins.WordStats, conf.registerChannelValue(conf.supybot.plugins.WordStats, 'rankingDisplay',
'rankingDisplay',
registry.PositiveInteger(3, """Determines the maximum number of top users registry.PositiveInteger(3, """Determines the maximum number of top users
to show for a given wordstat when someone requests the wordstats for a to show for a given wordstat when someone requests the wordstats for a
particular word.""")) particular word."""))
conf.registerChannelValue(conf.supybot.plugins.WordStats, 'ignoreQueries',
registry.Boolean(False, """Determines whether the bot will ignore words
said in a channel if they're in a wordstats query (command)."""))
nonAlphaNumeric = filter(lambda s: not s.isalnum(), string.ascii) nonAlphaNumeric = filter(lambda s: not s.isalnum(), string.ascii)
@ -143,14 +145,16 @@ class WordStatsDB(plugins.ChannelUserDB):
def addMsg(self, msg): def addMsg(self, msg):
assert msg.command == 'PRIVMSG' assert msg.command == 'PRIVMSG'
(channel, text) = msg.args
if not ircutils.isChannel(channel):
return
text = text.strip().lower()
if not text:
return
try: try:
id = ircdb.users.getUserId(msg.prefix) id = ircdb.users.getUserId(msg.prefix)
except KeyError: except KeyError:
return return
(channel, text) = msg.args
text = text.strip().lower()
if not ircutils.isChannel(channel) or not text:
return
msgwords = [s.strip(nonAlphaNumeric) for s in text.split()] msgwords = [s.strip(nonAlphaNumeric) for s in text.split()]
if channel not in self.channelWords: if channel not in self.channelWords:
self.channelWords[channel] = {} self.channelWords[channel] = {}
@ -172,6 +176,7 @@ class WordStats(callbacks.Privmsg):
def __init__(self): def __init__(self):
callbacks.Privmsg.__init__(self) callbacks.Privmsg.__init__(self)
self.db = WordStatsDB(filename) self.db = WordStatsDB(filename)
self.queried = False
world.flushers.append(self.db.flush) world.flushers.append(self.db.flush)
def die(self): def die(self):
@ -181,7 +186,17 @@ class WordStats(callbacks.Privmsg):
callbacks.Privmsg.die(self) callbacks.Privmsg.die(self)
def doPrivmsg(self, irc, msg): def doPrivmsg(self, irc, msg):
self.db.addMsg(msg) # This depends on the fact that it's called after the command.
try:
channel = msg.args[0]
if ircutils.isChannel(channel):
if not (self.queried and
self.registryValue('ignoreQueries', channel)):
self.db.addMsg(msg)
else:
self.log.debug('Queried and ignoring.')
finally:
self.queried = False
def add(self, irc, msg, args): def add(self, irc, msg, args):
"""[<channel>] <word> """[<channel>] <word>
@ -196,6 +211,7 @@ class WordStats(callbacks.Privmsg):
irc.error('<word> must not contain non-alphanumeric chars.') irc.error('<word> must not contain non-alphanumeric chars.')
return return
self.db.addWord(channel, word) self.db.addWord(channel, word)
self.queried = True
irc.replySuccess() irc.replySuccess()
def remove(self, irc, msg, args): def remove(self, irc, msg, args):
@ -260,12 +276,18 @@ class WordStats(callbacks.Privmsg):
if count: if count:
s = '%s has said %r %s.' % \ s = '%s has said %r %s.' % \
(user, word, utils.nItems('time', count)) (user, word, utils.nItems('time', count))
self.queried = True
irc.reply(s) irc.reply(s)
else: else:
irc.error('%s has never said %r.' % (user, word)) irc.error('%s has never said %r.' % (user, word))
elif arg1 in WordDict.fromkeys(self.db.getWords(channel)): elif arg1 in WordDict.fromkeys(self.db.getWords(channel)):
word = arg1 word = arg1
total = self.db.getTotalWordCount(channel, word) total = self.db.getTotalWordCount(channel, word)
if total == 0:
irc.reply('I\'m keeping stats on %s, but I haven\'t seen it '
'in this channel.' % word)
self.queried = True
return
n = self.registryValue('rankingDisplay', channel) n = self.registryValue('rankingDisplay', channel)
try: try:
id = ircdb.users.getUserId(msg.prefix) id = ircdb.users.getUserId(msg.prefix)
@ -296,6 +318,7 @@ class WordStats(callbacks.Privmsg):
else: else:
s = '' s = ''
ret = '%s %s.%s' % (ret, utils.commaAndify(L), s) ret = '%s %s.%s' % (ret, utils.commaAndify(L), s)
self.queried = True
irc.reply(ret) irc.reply(ret)
else: else:
user = arg1 user = arg1

View File

@ -33,153 +33,162 @@ from testsupport import *
import ircdb import ircdb
try: class WordStatsTestCase(ChannelPluginTestCase):
import sqlite plugins = ('WordStats', 'User', 'Utilities')
except ImportError: def setUp(self):
sqlite = None ChannelPluginTestCase.setUp(self)
self.prefix = 'foo!bar@baz'
self.nick = 'foo'
self.irc.feedMsg(ircmsgs.privmsg(self.irc.nick,
'register foo bar',
prefix=self.prefix))
_ = self.irc.takeMsg()
ircdb.users.getUser(self.nick).addCapability(self.channel + '.op')
if sqlite is not None: def testWordStatsNoArgs(self):
class WordStatsTestCase(ChannelPluginTestCase): self.assertResponse('wordstats', 'I am not currently keeping any '
plugins = ('WordStats', 'User') 'word stats.')
def setUp(self): self.assertNotError('add lol')
ChannelPluginTestCase.setUp(self) self.assertResponse('wordstats',
self.prefix = 'foo!bar@baz' 'I am currently keeping stats for lol.')
self.nick = 'foo'
self.irc.feedMsg(ircmsgs.privmsg(self.irc.nick,
'register foo bar',
prefix=self.prefix))
_ = self.irc.takeMsg()
ircdb.users.getUser(self.nick).addCapability(self.channel + '.op')
def testWordStatsNoArgs(self):
self.assertResponse('wordstats', 'I am not currently keeping any '
'word stats.')
self.assertNotError('add lol')
self.assertResponse('wordstats',
'I am currently keeping stats for lol.')
def testWordStatsUser(self): def testWordStatsUser(self):
self.assertNotError('add lol') self.assertNotError('add lol')
self.irc.feedMsg(ircmsgs.privmsg(self.channel, 'lol',
prefix=self.prefix))
self.assertResponse('wordstats foo', '\'lol\': 2')
self.assertNotError('add moo')
self.irc.feedMsg(ircmsgs.privmsg(self.channel, 'moo',
prefix=self.prefix))
self.assertResponse('wordstats foo', '\'lol\': 2 and \'moo\': 2')
def testWordStatsWord(self):
userPrefix1 = 'moo!bar@baz'; userNick1 = 'moo'
userPrefix2 = 'boo!bar@baz'; userNick2 = 'boo'
self.irc.feedMsg(ircmsgs.privmsg(self.irc.nick,
'register %s bar' % userNick1,
prefix=userPrefix1))
self.irc.feedMsg(ircmsgs.privmsg(self.irc.nick,
'register %s bar' % userNick2,
prefix=userPrefix2))
_ = self.irc.takeMsg()
_ = self.irc.takeMsg()
self.assertNotError('add lol')
self.assertRegexp('wordstats lol', 'foo: 1')
for i in range(5):
self.irc.feedMsg(ircmsgs.privmsg(self.channel, 'lol', self.irc.feedMsg(ircmsgs.privmsg(self.channel, 'lol',
prefix=self.prefix))
self.assertResponse('wordstats foo', '\'lol\': 2')
self.assertNotError('add moo')
self.irc.feedMsg(ircmsgs.privmsg(self.channel, 'moo',
prefix=self.prefix))
self.assertResponse('wordstats foo', '\'lol\': 2 and \'moo\': 2')
def testWordStatsWord(self):
userPrefix1 = 'moo!bar@baz'; userNick1 = 'moo'
userPrefix2 = 'boo!bar@baz'; userNick2 = 'boo'
self.irc.feedMsg(ircmsgs.privmsg(self.irc.nick,
'register %s bar' % userNick1,
prefix=userPrefix1)) prefix=userPrefix1))
self.irc.feedMsg(ircmsgs.privmsg(self.irc.nick, self.assertRegexp('wordstats lol',
'register %s bar' % userNick2, '2.*%s: 5.*foo: 2' % userNick1)
for i in range(10):
self.irc.feedMsg(ircmsgs.privmsg(self.channel, 'lol',
prefix=userPrefix2)) prefix=userPrefix2))
_ = self.irc.takeMsg() self.assertRegexp('wordstats lol',
_ = self.irc.takeMsg() '3.*%s: 10.*%s: 5.*foo: 3' %
self.assertNotError('add lol') (userNick2, userNick1))
self.assertRegexp('wordstats lol', 'foo: 1') # Check for the extra-swanky stuff too
for i in range(5): # (note: to do so we must make sure they don't appear in the list,
self.irc.feedMsg(ircmsgs.privmsg(self.channel, 'lol', # so we'll tweak the config)
prefix=userPrefix1)) try:
orig = conf.supybot.plugins.WordStats.rankingDisplay()
conf.supybot.plugins.WordStats.rankingDisplay.setValue(2)
self.assertRegexp('wordstats lol', self.assertRegexp('wordstats lol',
'2.*%s: 5.*foo: 2' % userNick1) 'total.*19 \'lol\'s.*%s: 10.*%s: 5.*'
for i in range(10): 'ranked 3 out of 3 \'lol\'ers' % \
self.irc.feedMsg(ircmsgs.privmsg(self.channel, 'lol',
prefix=userPrefix2))
self.assertRegexp('wordstats lol',
'3.*%s: 10.*%s: 5.*foo: 3' %
(userNick2, userNick1)) (userNick2, userNick1))
# Check for the extra-swanky stuff too finally:
# (note: to do so we must make sure they don't appear in the list, conf.supybot.plugins.WordStats.rankingDisplay.setValue(orig)
# so we'll tweak the config)
try:
orig = conf.supybot.plugins.WordStats.rankingDisplay()
conf.supybot.plugins.WordStats.rankingDisplay.setValue(2)
self.assertRegexp('wordstats lol',
'total.*19 \'lol\'s.*%s: 10.*%s: 5.*'
'ranked 3 out of 3 \'lol\'ers' % \
(userNick2, userNick1))
finally:
conf.supybot.plugins.WordStats.rankingDisplay.setValue(orig)
def testWordStatsUserWord(self):
self.assertNotError('add lol')
self.assertResponse('wordstats foo lol',
'foo has said \'lol\' 1 time.')
self.irc.feedMsg(ircmsgs.privmsg(self.channel, 'lol',
prefix=self.prefix))
self.assertResponse('wordstats foo lol',
'foo has said \'lol\' 3 times.')
# Now check for case-insensitivity
self.irc.feedMsg(ircmsgs.privmsg(self.channel, 'LOL',
prefix=self.prefix))
self.assertResponse('wordstats foo lol',
'foo has said \'lol\' 5 times.')
# Check and make sure actions get nabbed too
self.irc.feedMsg(ircmsgs.privmsg(self.channel, 'lol',
prefix=self.prefix))
self.assertResponse('wordstats foo lol',
'foo has said \'lol\' 7 times.')
# Check and make sure it handles two words in one message
self.assertNotError('add heh')
self.irc.feedMsg(ircmsgs.privmsg(self.channel, 'lol heh',
prefix=self.prefix))
self.assertResponse('wordstats foo lol',
'foo has said \'lol\' 9 times.')
self.assertResponse('wordstats foo heh',
'foo has said \'heh\' 2 times.')
# It should ignore punctuation around words
self.irc.feedMsg(ircmsgs.privmsg(self.channel,'lol, I said "heh"',
prefix=self.prefix))
self.assertResponse('wordstats foo lol',
'foo has said \'lol\' 11 times.')
self.assertResponse('wordstats foo heh',
'foo has said \'heh\' 4 times.')
def testAddword(self): def testWordStatsUserWord(self):
self.assertError('add lol!') self.assertNotError('add lol')
self.assertNotError('add lolz0r') self.assertResponse('wordstats foo lol',
self.assertRegexp('wordstats lolz0r', r'1 \'lolz0r\' seen') 'foo has said \'lol\' 1 time.')
self.irc.feedMsg(ircmsgs.privmsg(self.channel, 'lol',
prefix=self.prefix))
self.assertResponse('wordstats foo lol',
'foo has said \'lol\' 3 times.')
# Now check for case-insensitivity
self.irc.feedMsg(ircmsgs.privmsg(self.channel, 'LOL',
prefix=self.prefix))
self.assertResponse('wordstats foo lol',
'foo has said \'lol\' 5 times.')
# Check and make sure actions get nabbed too
self.irc.feedMsg(ircmsgs.privmsg(self.channel, 'lol',
prefix=self.prefix))
self.assertResponse('wordstats foo lol',
'foo has said \'lol\' 7 times.')
# Check and make sure it handles two words in one message
self.assertNotError('add heh')
self.irc.feedMsg(ircmsgs.privmsg(self.channel, 'lol heh',
prefix=self.prefix))
self.assertResponse('wordstats foo lol',
'foo has said \'lol\' 9 times.')
self.assertResponse('wordstats foo heh',
'foo has said \'heh\' 2 times.')
# It should ignore punctuation around words
self.irc.feedMsg(ircmsgs.privmsg(self.channel,'lol, I said "heh"',
prefix=self.prefix))
self.assertResponse('wordstats foo lol',
'foo has said \'lol\' 11 times.')
self.assertResponse('wordstats foo heh',
'foo has said \'heh\' 4 times.')
def testRemoveword(self): def testAddword(self):
self.assertError('wordstats remove foo') self.assertError('add lol!')
self.assertNotError('wordstats add foo') self.assertNotError('add lolz0r')
self.assertRegexp('wordstats foo', r'1 \'foo\' seen') self.assertRegexp('wordstats lolz0r', r'1 \'lolz0r\' seen')
self.assertRegexp('wordstats foo', r'2 \'foo\'s seen')
self.assertNotError('wordstats remove foo')
self.assertRegexp('wordstats foo', r'doesn\'t look like a word I')
# Verify that we aren't keeping results from before
self.assertNotError('add foo')
self.assertRegexp('wordstats foo', r'1 \'foo\' seen')
def testWordStatsRankingDisplay(self): def testRemoveword(self):
self.assertNotError('add lol') self.assertError('wordstats remove foo')
try: self.assertNotError('wordstats add foo')
orig = conf.supybot.plugins.WordStats.rankingDisplay() self.assertRegexp('wordstats foo', r'1 \'foo\' seen')
conf.supybot.plugins.WordStats.rankingDisplay.setValue(5) self.assertRegexp('wordstats foo', r'2 \'foo\'s seen')
# Create 10 users and have them each send a different number of self.assertNotError('wordstats remove foo')
# 'lol's to the channel self.assertRegexp('wordstats foo', r'doesn\'t look like a word I')
users = [] # Verify that we aren't keeping results from before
for i in range(10): self.assertNotError('add foo')
users.append(('foo%s!bar@baz' % i, 'foo%s' % i)) self.assertRegexp('wordstats foo', r'1 \'foo\' seen')
self.irc.feedMsg(ircmsgs.privmsg(self.irc.nick,
'register %s bar' % \ def testWordStatsRankingDisplay(self):
users[i][1], self.assertNotError('add lol')
try:
orig = conf.supybot.plugins.WordStats.rankingDisplay()
conf.supybot.plugins.WordStats.rankingDisplay.setValue(5)
# Create 10 users and have them each send a different number of
# 'lol's to the channel
users = []
for i in range(10):
users.append(('foo%s!bar@baz' % i, 'foo%s' % i))
self.irc.feedMsg(ircmsgs.privmsg(self.irc.nick,
'register %s bar' % \
users[i][1],
prefix=users[i][0]))
_ = self.irc.takeMsg()
for i in range(10):
for j in range(i):
self.irc.feedMsg(ircmsgs.privmsg(self.channel, 'lol',
prefix=users[i][0])) prefix=users[i][0]))
_ = self.irc.takeMsg() # Make sure it shows the top 5
for i in range(10): self.assertRegexp('wordstats lol',
for j in range(i): 'Top 5 \'lol\'ers.*foo9: 9.*foo8: 8.*'
self.irc.feedMsg(ircmsgs.privmsg(self.channel, 'lol', 'foo7: 7.*foo6: 6.*foo5: 5')
prefix=users[i][0])) finally:
# Make sure it shows the top 5 conf.supybot.plugins.WordStats.rankingDisplay.setValue(orig)
self.assertRegexp('wordstats lol',
'Top 5 \'lol\'ers.*foo9: 9.*foo8: 8.*' def testWordStatsIgnoreQueries(self):
'foo7: 7.*foo6: 6.*foo5: 5') try:
finally: original = conf.supybot.plugins.WordStats.ignoreQueries()
conf.supybot.plugins.WordStats.rankingDisplay.setValue(orig) conf.supybot.plugins.WordStats.ignoreQueries.setValue(True)
self.assertNotError('add lol')
self.assertNotRegexp('wordstats lol', 'foo')
self.assertNotRegexp('wordstats lol', 'foo')
self.assertNotRegexp('wordstats lol', 'foo')
self.assertNotError('echo lol')
self.assertRegexp('wordstats lol', 'foo: 1')
self.assertRegexp('wordstats lol', 'foo: 1')
self.assertRegexp('wordstats lol', 'foo: 1')
finally:
conf.supybot.plugins.WordStats.ignoreQueries.setValue(original)
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: # vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: