From 63244b1e47f1b91b0c24f6fcdb5755845c2debcc Mon Sep 17 00:00:00 2001 From: James Vega Date: Sun, 5 Sep 2010 01:09:43 -0400 Subject: [PATCH 1/7] News: Use positiveInt converter instead of manual checks. Closes: Sf#3059239 Signed-off-by: James Vega --- plugins/News/plugin.py | 28 ++++------------------------ 1 file changed, 4 insertions(+), 24 deletions(-) diff --git a/plugins/News/plugin.py b/plugins/News/plugin.py index 2cef9c966..554ddd825 100644 --- a/plugins/News/plugin.py +++ b/plugins/News/plugin.py @@ -147,16 +147,11 @@ class News(callbacks.Plugin): irc.reply(format('No news for %s.', channel)) else: try: - if id < 1: - raise ValueError record = self.db.get(channel, id) irc.reply(str(record)) except dbi.NoRecordError, id: irc.errorInvalid('news item id', id) - except ValueError: - irc.errorInvalid('news item id', id, - ' must be a positive integer.') - news = wrap(news, ['channeldb', additional('int')]) + news = wrap(news, ['channeldb', additional('positiveInt')]) def remove(self, irc, msg, args, channel, id): """[] @@ -165,16 +160,11 @@ class News(callbacks.Plugin): necessary if the message isn't sent in the channel itself. """ try: - if id < 1: - raise ValueError self.db.remove(channel, id) irc.replySuccess() except dbi.NoRecordError: irc.errorInvalid('news item id', id) - except ValueError: - irc.errorInvalid('news item id', id, - ' must be a positive integer.') - remove = wrap(remove, ['channeldb', 'int']) + remove = wrap(remove, ['channeldb', 'positiveInt']) def change(self, irc, msg, args, channel, id, replacer): """[] @@ -185,16 +175,11 @@ class News(callbacks.Plugin): isn't sent on the channel itself. """ try: - if id < 1: - raise ValueError self.db.change(channel, id, replacer) irc.replySuccess() except dbi.NoRecordError: irc.errorInvalid('news item id', id) - except ValueError: - irc.errorInvalid('news item id', id, - ' must be a positive integer.') - change = wrap(change, ['channeldb', 'int', 'regexpReplacer']) + change = wrap(change, ['channeldb', 'positiveInt', 'regexpReplacer']) def old(self, irc, msg, args, channel, id): """[] [] @@ -205,15 +190,10 @@ class News(callbacks.Plugin): """ if id: try: - if id < 1: - raise ValueError record = self.db.getOld(channel, id) irc.reply(str(record)) except dbi.NoRecordError, id: irc.errorInvalid('news item id', id) - except ValueError: - irc.errorInvalid('news item id', id, - ' must be a positive integer.') else: try: records = self.db.getOld(channel) @@ -222,7 +202,7 @@ class News(callbacks.Plugin): irc.reply(s) except dbi.NoRecordError: irc.reply(format('No old news for %s.', channel)) - old = wrap(old, ['channeldb', additional('int')]) + old = wrap(old, ['channeldb', additional('positiveInt')]) Class = News From 7cf61ad04643c3c9f795f06f0886ee25c2923472 Mon Sep 17 00:00:00 2001 From: James Vega Date: Wed, 8 Sep 2010 21:35:22 -0400 Subject: [PATCH 2/7] Games: Remove arbitrary upper limits on dice command. Closes: Sf#3057255 Signed-off-by: James Vega --- plugins/Games/plugin.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/plugins/Games/plugin.py b/plugins/Games/plugin.py index 7bc25870d..427880193 100644 --- a/plugins/Games/plugin.py +++ b/plugins/Games/plugin.py @@ -1,5 +1,6 @@ ### # Copyright (c) 2003-2005, Jeremiah Fincher +# Copyright (c) 2010, James Vega # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -57,11 +58,7 @@ class Games(callbacks.Plugin): ten-sided dice. """ (dice, sides) = utils.iter.imap(int, m.groups()) - if dice > 6: - irc.error('You can\'t roll more than 6 dice.') - elif sides > 100: - irc.error('Dice can\'t have more than 100 sides.') - elif sides < 3: + if sides < 3: irc.error('Dice can\'t have fewer than 3 sides.') else: L = [0] * dice From c9274606ce0312b9726400fc431c810c93d2aa3c Mon Sep 17 00:00:00 2001 From: James Vega Date: Wed, 8 Sep 2010 22:20:23 -0400 Subject: [PATCH 3/7] Google: Remove Groups snarfer The regular expressions were woefully out of date and since there's not a stable API (or any for that matter), keeping things working is a losing battle. Closes: Sf#3057485 Signed-off-by: James Vega --- plugins/Google/config.py | 14 ++-------- plugins/Google/plugin.py | 42 ++---------------------------- plugins/Google/test.py | 56 ---------------------------------------- 3 files changed, 4 insertions(+), 108 deletions(-) diff --git a/plugins/Google/config.py b/plugins/Google/config.py index d34f530a1..a309911ab 100644 --- a/plugins/Google/config.py +++ b/plugins/Google/config.py @@ -1,6 +1,6 @@ ### # Copyright (c) 2005, Jeremiah Fincher -# Copyright (c) 2008-2009, James Vega +# Copyright (c) 2008-2010, James Vega # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -37,13 +37,7 @@ def configure(advanced): output("""The Google plugin has the functionality to watch for URLs that match a specific pattern. (We call this a snarfer) When supybot sees such a URL, it will parse the web page - for information and reply with the results. - - Google has two available snarfers: Google Groups link - snarfing and a google search snarfer.""") - if yn('Do you want the Google Groups link snarfer enabled by ' - 'default?'): - conf.supybot.plugins.Google.groupsSnarfer.setValue(True) + for information and reply with the results.""") if yn('Do you want the Google search snarfer enabled by default?'): conf.supybot.plugins.Google.searchSnarfer.setValue(True) @@ -104,10 +98,6 @@ conf.registerGlobalValue(Google, 'referer', the Referer field of the search requests. If this value is empty, a Referer will be generated in the following format: http://$server/$botName""")) -conf.registerChannelValue(Google, 'groupsSnarfer', - registry.Boolean(False, """Determines whether the groups snarfer is - enabled. If so, URLs at groups.google.com will be snarfed and their - group/title messaged to the channel.""")) conf.registerChannelValue(Google, 'searchSnarfer', registry.Boolean(False, """Determines whether the search snarfer is enabled. If so, messages (even unaddressed ones) beginning with the word diff --git a/plugins/Google/plugin.py b/plugins/Google/plugin.py index f9b2fa0fd..2adef8ef3 100644 --- a/plugins/Google/plugin.py +++ b/plugins/Google/plugin.py @@ -1,6 +1,6 @@ ### # Copyright (c) 2002-2004, Jeremiah Fincher -# Copyright (c) 2008-2009, James Vega +# Copyright (c) 2008-2010, James Vega # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -66,7 +66,7 @@ except ImportError: class Google(callbacks.PluginRegexp): threaded = True callBefore = ['Web'] - regexps = ['googleSnarfer', 'googleGroups'] + regexps = ['googleSnarfer'] _colorGoogles = {} def _getColorGoogle(self, m): @@ -288,44 +288,6 @@ class Google(callbacks.PluginRegexp): irc.reply(url.encode('utf-8'), prefixNick=False) googleSnarfer = urlSnarfer(googleSnarfer) - _ggThread = re.compile(r'Subject: ([^<]+)', re.I) - _ggGroup = re.compile(r'Google Groups :\s*([^<]+)', re.I) - _ggThreadm = re.compile(r'src="(/group[^"]+)">', re.I) - _ggSelm = re.compile(r'selm=[^&]+', re.I) - _threadmThread = re.compile(r'TITLE="([^"]+)">', re.I) - _threadmGroup = re.compile(r'class=groupname[^>]+>([^<]+)<', re.I) - def googleGroups(self, irc, msg, match): - r"http://groups.google.[\w.]+/\S+\?(\S+)" - if not self.registryValue('groupsSnarfer', msg.args[0]): - return - queries = cgi.parse_qsl(match.group(1)) - queries = [q for q in queries if q[0] in ('threadm', 'selm')] - if not queries: - return - queries.append(('hl', 'en')) - url = 'http://groups.google.com/groups?' + urllib.urlencode(queries) - text = utils.web.getUrl(url) - mThread = None - mGroup = None - if 'threadm=' in url: - path = self._ggThreadm.search(text) - if path is not None: - url = 'http://groups-beta.google.com' + path.group(1) - text = utils.web.getUrl(url) - mThread = self._threadmThread.search(text) - mGroup = self._threadmGroup.search(text) - else: - mThread = self._ggThread.search(text) - mGroup = self._ggGroup.search(text) - if mThread and mGroup: - irc.reply(format('Google Groups: %s, %s', - mGroup.group(1), mThread.group(1)), - prefixNick=False) - else: - self.log.debug('Unable to snarf. %s doesn\'t appear to be a ' - 'proper Google Groups page.', match.group(1)) - googleGroups = urlSnarfer(googleGroups) - def _googleUrl(self, s): s = s.replace('+', '%2B') s = s.replace(' ', '+') diff --git a/plugins/Google/test.py b/plugins/Google/test.py index 92b7aeee0..fe7affc3d 100644 --- a/plugins/Google/test.py +++ b/plugins/Google/test.py @@ -64,60 +64,4 @@ class GoogleTestCase(ChannelPluginTestCase): def testCalcDoesNotHaveExtraSpaces(self): self.assertNotRegexp('google calc 1000^2', r'\s+,\s+') - def testGroupsSnarfer(self): - orig = conf.supybot.plugins.Google.groupsSnarfer() - try: - conf.supybot.plugins.Google.groupsSnarfer.setValue(True) - # This should work, and does work in practice, but is failing - # in the tests. - #self.assertSnarfRegexp( - # 'http://groups.google.com/groups?dq=&hl=en&lr=lang_en&' - # 'ie=UTF-8&oe=UTF-8&selm=698f09f8.0310132012.738e22fc' - # '%40posting.google.com', - # r'comp\.lang\.python.*question: usage of __slots__') - self.assertSnarfRegexp( - 'http://groups.google.com/groups?selm=ExDm.8bj.23' - '%40gated-at.bofh.it&oe=UTF-8&output=gplain', - r'linux\.kernel.*NFS client freezes') - self.assertSnarfRegexp( - 'http://groups.google.com/groups?q=kernel+hot-pants&' - 'hl=en&lr=&ie=UTF-8&oe=UTF-8&selm=1.5.4.32.199703131' - '70853.00674d60%40adan.kingston.net&rnum=1', - r'Madrid Bluegrass Ramble') - self.assertSnarfRegexp( - 'http://groups.google.com/groups?selm=1.5.4.32.19970' - '313170853.00674d60%40adan.kingston.net&oe=UTF-8&' - 'output=gplain', - r'Madrid Bluegrass Ramble') - self.assertSnarfRegexp( - 'http://groups.google.com/groups?dq=&hl=en&lr=&' - 'ie=UTF-8&threadm=mailman.1010.1069645289.702.' - 'python-list%40python.org&prev=/groups%3Fhl%3Den' - '%26lr%3D%26ie%3DUTF-8%26group%3Dcomp.lang.python', - r'comp\.lang\.python.*What exactly are bound') - # Test for Bug #1002547 - self.assertSnarfRegexp( - 'http://groups.google.com/groups?q=supybot+is+the&' - 'hl=en&lr=&ie=UTF-8&c2coff=1&selm=1028329672' - '%40freshmeat.net&rnum=9', - r'fm\.announce.*SupyBot') - finally: - conf.supybot.plugins.Google.groupsSnarfer.setValue(orig) - - def testConfig(self): - orig = conf.supybot.plugins.Google.groupsSnarfer() - try: - conf.supybot.plugins.Google.groupsSnarfer.setValue(False) - self.assertSnarfNoResponse( - 'http://groups.google.com/groups?dq=&hl=en&lr=lang_en&' - 'ie=UTF-8&oe=UTF-8&selm=698f09f8.0310132012.738e22fc' - '%40posting.google.com') - conf.supybot.plugins.Google.groupsSnarfer.setValue(True) - self.assertSnarfNotError( - 'http://groups.google.com/groups?dq=&hl=en&lr=lang_en&' - 'ie=UTF-8&oe=UTF-8&selm=698f09f8.0310132012.738e22fc' - '%40posting.google.com') - finally: - conf.supybot.plugins.Google.groupsSnarfer.setValue(orig) - # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: From c0e24cef3093f061dc3abde3b80ff69ef68f0520 Mon Sep 17 00:00:00 2001 From: James Vega Date: Wed, 8 Sep 2010 22:42:07 -0400 Subject: [PATCH 4/7] Limiter: Fix "reduce limit" test case. Closes: Sf#3058142 Signed-off-by: James Vega --- plugins/Limiter/test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/Limiter/test.py b/plugins/Limiter/test.py index 9941dd433..f70eccdf3 100644 --- a/plugins/Limiter/test.py +++ b/plugins/Limiter/test.py @@ -47,7 +47,7 @@ class LimiterTestCase(ChannelPluginTestCase): conf.supybot.plugins.Limiter.maximumExcess.setValue(7) self.irc.feedMsg(ircmsgs.part('#foo', prefix='bar!root@host')) m = self.irc.takeMsg() - self.assertEqual(m, ircmsgs.limit('#foo', 1-5)) + self.assertEqual(m, ircmsgs.limit('#foo', 1+5)) finally: conf.supybot.plugins.Limiter.minimumExcess.setValue(origMin) conf.supybot.plugins.Limiter.maximumExcess.setValue(origMax) From fc2a84fb900bf4c9f7eabbbe3a8c11054c1f56b7 Mon Sep 17 00:00:00 2001 From: James Vega Date: Wed, 8 Sep 2010 22:43:45 -0400 Subject: [PATCH 5/7] -> in Karma.karma's help Closes: Sf#3057517 Signed-off-by: James Vega --- plugins/Karma/plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/Karma/plugin.py b/plugins/Karma/plugin.py index d7a33ec41..4f4c8eebd 100644 --- a/plugins/Karma/plugin.py +++ b/plugins/Karma/plugin.py @@ -276,7 +276,7 @@ class Karma(callbacks.Plugin): def karma(self, irc, msg, args, channel, things): """[] [ ...] - Returns the karma of . If is not given, returns the top + Returns the karma of . If is not given, returns the top three and bottom three karmas. If one is given, returns the details of its karma; if more than one is given, returns the total karma of each of the the things. is only necessary if From b0575cec885d2576b7ff5c7b302d4746b7c5a482 Mon Sep 17 00:00:00 2001 From: James Vega Date: Wed, 8 Sep 2010 23:31:01 -0400 Subject: [PATCH 6/7] Handle changes to fnmatch.translate in Python 2.6 Define utils.python.glob2re based on the Python version being used. Use glob2re in Todo and Note plugins. Closes: Sf#3059292 Signed-off-by: James Vega --- plugins/Note/plugin.py | 12 ++---------- plugins/Todo/plugin.py | 6 +++--- src/utils/python.py | 14 ++++++++++++-- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/plugins/Note/plugin.py b/plugins/Note/plugin.py index 95a53bbea..3fd3cb326 100644 --- a/plugins/Note/plugin.py +++ b/plugins/Note/plugin.py @@ -30,7 +30,6 @@ import re import time -import fnmatch import operator import supybot.dbi as dbi @@ -98,15 +97,9 @@ class DbiNoteDB(dbi.DB): self.set(id, n) def getUnnotifiedIds(self, to): -## def p(note): -## return not note.notified and note.to == to -## return [note.id for note in self.select(p)] return self.unNotified.get(to, []) def getUnreadIds(self, to): -## def p(note): -## return not note.read and note.to == to -## return [note.id for note in self.select(p)] return self.unRead.get(to, []) def send(self, frm, to, public, text): @@ -303,9 +296,8 @@ class Note(callbacks.Plugin): elif option == 'sent': own = frm if glob: - glob = fnmatch.translate(glob) - # ignore the trailing $ fnmatch.translate adds to the regexp - criteria.append(re.compile(glob[:-1]).search) + glob = utils.python.glob2re(glob) + criteria.append(re.compile(glob).search) def match(note): for p in criteria: if not p(note.text): diff --git a/plugins/Todo/plugin.py b/plugins/Todo/plugin.py index efc415e5f..b995140ba 100644 --- a/plugins/Todo/plugin.py +++ b/plugins/Todo/plugin.py @@ -1,5 +1,6 @@ ### # Copyright (c) 2003-2005, Daniel DiPaolo +# Copyright (c) 2010, James Vega # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -30,7 +31,6 @@ import os import re import time -import fnmatch import operator import supybot.dbi as dbi @@ -230,8 +230,8 @@ class Todo(callbacks.Plugin): if option == 'regexp': criteria.append(arg.search) for glob in globs: - glob = fnmatch.translate(glob) - criteria.append(re.compile(glob[:-1]).search) + glob = utils.python.glob2re(glob) + criteria.append(re.compile(glob).search) try: tasks = self.db.select(user.id, criteria) L = [format('#%i: %s', t.id, self._shrink(t.task)) for t in tasks] diff --git a/src/utils/python.py b/src/utils/python.py index d636d62bb..f38de2f78 100644 --- a/src/utils/python.py +++ b/src/utils/python.py @@ -1,6 +1,6 @@ ### # Copyright (c) 2005-2009, Jeremiah Fincher -# Copyright (c) 2009, James Vega +# Copyright (c) 2009-2010, James Vega # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -30,6 +30,7 @@ import sys import types +import fnmatch import UserDict import threading @@ -65,7 +66,6 @@ def changeFunctionName(f, name, doc=None): class Object(object): def __ne__(self, other): return not self == other - class Synchronized(type): METHODS = '__synchronized__' @@ -103,5 +103,15 @@ class Synchronized(type): newclass = super(Synchronized, cls).__new__(cls, name, bases, dict) return newclass +# Translate glob to regular expression, trimming the "match EOL" portion of +# the regular expression. +if sys.version_info < (2, 6, 0): + # Pre-2.6 just uses the $ anchor + def glob2re(g): + return fnmatch.translate(g)[:-1] +else: + # Post-2.6 uses \Z(?ms) per http://issues.python.org/6665 + def glob2re(g): + return fnmatch.translate(g)[:-7] # vim:set shiftwidth=4 softtabstop=8 expandtab textwidth=78: From 45abdc82485633d709a0eee98ccef111f4101bef Mon Sep 17 00:00:00 2001 From: James Vega Date: Wed, 8 Sep 2010 23:44:40 -0400 Subject: [PATCH 7/7] Karma: Refer to plugins.Karma.rankingDisplay in Karma.karma's help. Signed-off-by: James Vega --- plugins/Karma/plugin.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/plugins/Karma/plugin.py b/plugins/Karma/plugin.py index 4f4c8eebd..02570b5af 100644 --- a/plugins/Karma/plugin.py +++ b/plugins/Karma/plugin.py @@ -277,10 +277,11 @@ class Karma(callbacks.Plugin): """[] [ ...] Returns the karma of . If is not given, returns the top - three and bottom three karmas. If one is given, returns the - details of its karma; if more than one is given, returns the - total karma of each of the the things. is only necessary if - the message isn't sent on the channel itself. + N karmas, where N is determined by the config variable + supybot.plugins.Karma.rankingDisplay. If one is given, returns + the details of its karma; if more than one is given, returns + the total karma of each of the the things. is only necessary + if the message isn't sent on the channel itself. """ if len(things) == 1: name = things[0]