diff --git a/ChangeLog b/ChangeLog index a04460b4e..6e9ce07ee 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,14 +1,17 @@ - * Added Lookup.search + * Added Lookup.search - * Updated Todo.remove to allow removing multiple taskids + * Updated Todo.remove to allow removing multiple taskids - * Added Topic.reorder, a new command for reordering the topics in a + * Added Topic.reorder, a new command for reordering the topics in a specific manner. - * Added Http.extension, a new command to retrieve file extension in + * Added Topic.list, a new command for listing the topics in a + channel (mostly in order to help out with Topic.reorder :)) + + * Added Http.extension, a new command to retrieve file extension in formation from filext.com. - * Updated Relay.whois to include a user's away status and identified + * Updated Relay.whois to include a user's away status and identified state, if the server supports it. 2003-12-6 Jeremy Fincher diff --git a/plugins/Alias.py b/plugins/Alias.py index 8849913be..6398943d6 100644 --- a/plugins/Alias.py +++ b/plugins/Alias.py @@ -151,7 +151,7 @@ def makeNewAlias(name, alias): f = types.FunctionType(f.func_code, f.func_globals, name, closure=f.func_closure) f.__doc__ ='\n\nAlias for %r' % \ - (utils.nItems(biggestDollar, 'argument'), alias) + (utils.nItems('argument', biggestDollar), alias) return f diff --git a/plugins/ChannelDB.py b/plugins/ChannelDB.py index 57a3cdd78..0a7e78a77 100644 --- a/plugins/ChannelDB.py +++ b/plugins/ChannelDB.py @@ -432,21 +432,21 @@ class ChannelDB(plugins.ChannelDBHandler, '%s has joined %s, parted %s, quit %s, kicked someone %s, '\ 'been kicked %s, changed the topic %s, ' \ 'and changed the mode %s.' % \ - (name, utils.nItems(values.msgs, 'message'), - utils.nItems(values.chars, 'character'), - utils.nItems(values.words, 'word'), - utils.nItems(values.smileys, 'smiley'), - utils.nItems(values.frowns, 'frown'), + (name, utils.nItems('message', values.msgs), + utils.nItems('character', values.chars), + utils.nItems('word', values.words), + utils.nItems('smiley', values.smileys), + utils.nItems('frown', values.frowns), values.actions, values.actions == 1 and 'was an ACTION. ' or 'were ACTIONs. ', name, - utils.nItems(values.joins, 'time'), - utils.nItems(values.parts, 'time'), - utils.nItems(values.quits, 'time'), - utils.nItems(values.kicks, 'time'), - utils.nItems(values.kicked, 'time'), - utils.nItems(values.topics, 'time'), - utils.nItems(values.modes, 'time')) + utils.nItems('time', values.joins), + utils.nItems('time', values.parts), + utils.nItems('time', values.quits), + utils.nItems('time', values.kicks), + utils.nItems('time', values.kicked), + utils.nItems('time', values.topics), + utils.nItems('time', values.modes)) irc.reply(msg, s) def channelstats(self, irc, msg, args): @@ -538,7 +538,7 @@ class ChannelDB(plugins.ChannelDBHandler, irc.error(msg, '%s has never said %r.' % (user, word)) return count = int(cursor.fetchone()[0]) - s = '%s has said %r %s.' % (user,word,utils.nItems(count, 'time')) + s = '%s has said %r %s.' % (user,word,utils.nItems('time', count)) irc.reply(msg, s) else: # Figure out if we got a user or a word @@ -594,9 +594,9 @@ class ChannelDB(plugins.ChannelDBHandler, word) total = int(cursor.fetchone()[0]) ers = '%rer' % word - ret = 'Top %s ' % utils.nItems(numResultsShown, ers) + ret = 'Top %s ' % utils.nItems(ers, numResultsShown) ret += '(out of a total of %s seen):' % \ - utils.nItems(total, repr(word)) + utils.nItems(repr(word), total) L = [] for (count, id) in results[:numResultsShown]: username = ircdb.users.getUser(id).name @@ -607,7 +607,7 @@ class ChannelDB(plugins.ChannelDBHandler, for (_, userId) in results: if userId == id: s = 'You are ranked %s out of %s.' % \ - (rank, utils.nItems(len(results), ers)) + (rank, utils.nItems(ers, len(results))) break else: rank += 1 diff --git a/plugins/Factoids.py b/plugins/Factoids.py index c229d9c7d..a474c178c 100644 --- a/plugins/Factoids.py +++ b/plugins/Factoids.py @@ -318,7 +318,7 @@ class Factoids(plugins.ChannelDBHandler, callbacks.Privmsg): factoids = '; '.join(L) s = 'Key %r is %s and has %s associated with it: %s' % \ (key, locked and 'locked' or 'not locked', - utils.nItems(counter, 'factoid'), factoids) + utils.nItems('factoid', counter), factoids) irc.reply(msg, s) def change(self, irc, msg, args): diff --git a/plugins/FunDB.py b/plugins/FunDB.py index b72d0874c..3fe858673 100755 --- a/plugins/FunDB.py +++ b/plugins/FunDB.py @@ -259,7 +259,7 @@ class FunDB(callbacks.Privmsg, configurable.Mixin, plugins.ChannelDBHandler): cursor.execute(sql) total = int(cursor.fetchone()[0]) irc.reply(msg, 'There %s currently %s in my database.' % - (utils.be(total), utils.nItems(total, table))) + (utils.be(total), utils.nItems(table, total))) def get(self, irc, msg, args): """[] diff --git a/plugins/Gameknot.py b/plugins/Gameknot.py index ce6a5ab1e..20d5cc8fb 100644 --- a/plugins/Gameknot.py +++ b/plugins/Gameknot.py @@ -140,18 +140,18 @@ class Gameknot(callbacks.PrivmsgCommandAndRegexp, configurable.Mixin): 'and a record of %s, %s, and %s ' \ '(win/loss/draw percentage: %.2f%%/%.2f%%/%.2f%%). %s' % \ (name, team, rating, games, - utils.nItems(w, 'win'), - utils.nItems(l, 'loss'), - utils.nItems(d, 'draw'), + utils.nItems('win', w), + utils.nItems('loss', l), + utils.nItems('draw', d), wp, lp, dp, seen) else: s = '%s is rated %s and has %s ' \ 'and a record of %s, %s, and %s ' \ '(win/loss/draw percentage: %.2f%%/%.2f%%/%.2f%%). %s' % \ (name, rating, games, - utils.nItems(w, 'win'), - utils.nItems(l, 'loss'), - utils.nItems(d, 'draw'), + utils.nItems('win', w), + utils.nItems('loss', l), + utils.nItems('draw', d), wp, lp, dp, seen) return s except AttributeError: diff --git a/plugins/Google.py b/plugins/Google.py index cf334c94d..d35e28e02 100644 --- a/plugins/Google.py +++ b/plugins/Google.py @@ -153,7 +153,7 @@ class Google(callbacks.PrivmsgCommandAndRegexp, configurable.Mixin): def formatData(self, data): if isinstance(data, basestring): return data - time = 'Search took %s seconds: ' % data.meta.searchTime + time = 'Search took %s seconds' % data.meta.searchTime results = [] for result in data.results: title = utils.htmlToText(result.title.encode('utf-8')) @@ -163,9 +163,9 @@ class Google(callbacks.PrivmsgCommandAndRegexp, configurable.Mixin): else: results.append(url) if not results: - return 'No matches found %s' % time + return 'No matches found (%s)' % time else: - return '%s %s' % (time, '; '.join(results)) + return '%s: %s' % (time, '; '.join(results)) def licensekey(self, irc, msg, args): """ diff --git a/plugins/Karma.py b/plugins/Karma.py index 76e3090a5..765e26f74 100644 --- a/plugins/Karma.py +++ b/plugins/Karma.py @@ -124,11 +124,10 @@ class Karma(callbacks.PrivmsgCommandAndRegexp, if self.configurables.get('simple-output', channel): s = '%s: %s' % (name, total) else: - s = 'Karma for %r has been increased %s %s ' \ - 'and decreased %s %s for a total karma of %s.' % \ - (name, added, utils.pluralize(added, 'time'), - subtracted, utils.pluralize(subtracted, 'time'), - total) + s = 'Karma for %r has been increased %s ' \ + 'and decreased %s for a total karma of %s.' % \ + (name, utils.nItems('time', added), + utils.nItems('time', subtracted), total) irc.reply(msg, s) elif len(args) > 1: normalizedArgs = sets.Set(imap(str.lower, args)) diff --git a/plugins/MoobotFactoids.py b/plugins/MoobotFactoids.py index 043730467..4201a4d36 100644 --- a/plugins/MoobotFactoids.py +++ b/plugins/MoobotFactoids.py @@ -435,7 +435,7 @@ class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp): last_at = time.strftime(conf.humanTimestampFormat, time.localtime(int(last_requested_at))) req_count = requested_count - times_str = utils.nItems(requested_count, 'time') + times_str = utils.nItems('time', requested_count) s += " Last requested by %s on %s, requested %s." % \ (last_by, last_at, times_str) # Last, locked info @@ -538,14 +538,14 @@ class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp): L = ['%s (%s)' % (ircdb.users.getUser(t[0]).name, int(t[1])) for t in cursor.fetchall()] return 'Most prolific %s: %s' % \ - (utils.pluralize(len(L), 'author'), utils.commaAndify(L)) + (utils.pluralize('author', len(L)), utils.commaAndify(L)) def _mostRecent(self, cursor, limit): cursor.execute("""SELECT key FROM factoids ORDER by created_at DESC LIMIT %s""", limit) L = [repr(t[0]) for t in cursor.fetchall()] return '%s: %s' % \ - (utils.nItems(len(L), 'factoid', between='latest'), + (utils.nItems('factoid', len(L), between='latest'), utils.commaAndify(L)) def _mostPopular(self, cursor, limit): @@ -556,7 +556,7 @@ class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp): raise self.MostException, 'No factoids have been requested.' L = ['%r (%s)' % (t[0], t[1]) for t in cursor.fetchall()] return 'Top %s: %s' % \ - (utils.nItems(len(L), 'factoid', between='requested'), + (utils.nItems('factoid', len(L), between='requested'), utils.commaAndify(L)) def listauth(self, irc, msg, args): diff --git a/plugins/Movies.py b/plugins/Movies.py index c2af004de..521497be9 100644 --- a/plugins/Movies.py +++ b/plugins/Movies.py @@ -64,7 +64,7 @@ class Movies(callbacks.Privmsg): 'It\'s been rated %s out of 10. ' \ 'More information is available at <%s>' % \ (title, movie.year(), genres, - utils.pluralize(len(movie.genres()), 'genre'), + utils.pluralize('genre', len(movie.genres())), movie.rating(), movie.url) return s diff --git a/plugins/Note.py b/plugins/Note.py index bd0854325..5197314d0 100644 --- a/plugins/Note.py +++ b/plugins/Note.py @@ -114,7 +114,7 @@ class Note(callbacks.Privmsg): unread = int(cursor.fetchone()[0]) s = 'You have %s; ' \ '%s that I haven\'t told you about before now..' % \ - (utils.nItems(unread, 'note', 'unread'), unnotified) + (utils.nItems('note', unread, 'unread'), unnotified) irc.queueMsg(ircmsgs.privmsg(msg.nick, s)) cursor.execute("""UPDATE notes SET notified=1 WHERE notes.to_id=%s""", id) diff --git a/plugins/Quotes.py b/plugins/Quotes.py index 330b6ec4b..4ad4a533a 100644 --- a/plugins/Quotes.py +++ b/plugins/Quotes.py @@ -110,8 +110,8 @@ class Quotes(plugins.ChannelDBHandler, callbacks.Privmsg): maxid = int(cursor.fetchone()[0]) if maxid is None: maxid = 0 - QUOTE = utils.pluralize(maxid, 'quote') - s = 'There %s %s %s in my database.' % (utils.be(maxid), maxid, QUOTE) + s = 'There %s %s in my database.' % \ + (utils.be(maxid), utils.nItems('quote', maxid)) irc.reply(msg, s) def get(self, irc, msg, args): diff --git a/plugins/Status.py b/plugins/Status.py index 616723580..b8c1fe40f 100644 --- a/plugins/Status.py +++ b/plugins/Status.py @@ -176,7 +176,7 @@ class Status(callbacks.Privmsg): 'seconds of CPU time. Out of %s I have %s active.' % (user, system, user + system, childUser, childSystem, childUser + childSystem, - utils.nItems(world.threadsSpawned, 'thread', 'spawned'), + utils.nItems('thread', world.threadsSpawned, 'spawned'), activeThreads)) mem = None pid = os.getpid() @@ -211,9 +211,9 @@ class Status(callbacks.Privmsg): attr == callbacks.canonicalName(attr): commands += 1 s = 'I offer a total of %s in %s. I have processed %s.' % \ - (utils.nItems(commands, 'command'), - utils.nItems(callbacksPrivmsg, 'plugin', 'command-based'), - utils.nItems(world.commandsProcessed, 'command')) + (utils.nItems('command', commands), + utils.nItems('plugin', callbacksPrivmsg, 'command-based'), + utils.nItems('command', world.commandsProcessed)) irc.reply(msg, s) def commands(self, irc, msg, args): diff --git a/plugins/Todo.py b/plugins/Todo.py index dbb351a1b..2adee88f7 100644 --- a/plugins/Todo.py +++ b/plugins/Todo.py @@ -247,20 +247,18 @@ class Todo(callbacks.Privmsg): _sqlTrans = string.maketrans('*?', '%_') def search(self, irc, msg, args): - """[--{regexp,exact}=] [] + """[--{regexp}=] [] - Searches the keyspace for tasks matching . If --regexp is given, + Searches the todos for tasks matching . If --regexp is given, its associated value is taken as a regexp and matched against the - tasks; if --exact is given, its associated value is taken as an exact - string to match against the tasks. + tasks. """ try: id = ircdb.users.getUserId(msg.prefix) except KeyError: irc.error(msg, conf.replyNotRegistered) return - - (optlist, rest) = getopt.getopt(args, '', ['regexp=', 'exact=']) + (optlist, rest) = getopt.getopt(args, '', ['regexp=']) if not optlist and not rest: raise callbacks.ArgumentError db = self.dbHandler.getDb() @@ -268,10 +266,7 @@ class Todo(callbacks.Privmsg): formats = [] predicateName = 'p' for (option, arg) in optlist: - if option == '--exact': - criteria.append('task LIKE %s') - formats.append('%' + arg + '%') - elif option == '--regexp': + if option == '--regexp': criteria.append('%s(task)' % predicateName) try: r = utils.perlReToPythonRe(arg) diff --git a/plugins/Topic.py b/plugins/Topic.py index 68624f6c2..6b5870159 100644 --- a/plugins/Topic.py +++ b/plugins/Topic.py @@ -76,6 +76,13 @@ class Topic(callbacks.Privmsg, configurable.Mixin): separator = self.configurables.get('separator', channel) return separator.join(topics) + def _unformatTopic(self, topic, channel): + m = self.topicUnformatter.match(topic) + if m: + return (m.group(1), m.group(2)) + else: + return (topic, '') + def add(self, irc, msg, args, channel): """[] @@ -168,6 +175,22 @@ class Topic(callbacks.Privmsg, configurable.Mixin): irc.error(msg, 'There are no topics to reorder.') reorder = privmsgs.checkChannelCapability(reorder, 'topic') + def list(self, irc, msg, args, channel): + """[] + + Returns a list of the topics in , prefixed by their indexes. + Mostly useful for topic reordering. is only necessary if the + message isn't sent in the channel itself. + """ + topics = self._splitTopic(irc.state.getTopic(channel), channel) + L = [] + for (i, t) in enumerate(topics): + (t, _) = self._unformatTopic(t, channel) + L.append('%s: %s' % (i+1, utils.ellipsisify(t, 30))) + s = utils.commaAndify(L) + irc.reply(msg, s) + list = privmsgs.channel(list) + def get(self, irc, msg, args, channel): """[] @@ -189,11 +212,7 @@ class Topic(callbacks.Privmsg, configurable.Mixin): topics = self._splitTopic(irc.state.getTopic(channel), channel) if topics: try: - match = self.topicUnformatter.match(topics[number]) - if match: - irc.reply(msg, match.group(1)) - else: - irc.reply(msg, topics[number]) + irc.reply(msg, self._unformatTopic(topics[number], channel)[0]) except IndexError: irc.error(msg, 'That\'s not a valid topic.') else: @@ -233,11 +252,7 @@ class Topic(callbacks.Privmsg, configurable.Mixin): irc.error(msg, 'There are no topics to change.') return topic = topics.pop(number) - match = self.topicUnformatter.match(topic) - if match is None: - name = '' - else: - (topic, name) = match.groups() + (topic, name) = self._unformatTopic(topic, channel) try: senderName = ircdb.users.getUser(msg.prefix).name except KeyError: @@ -279,11 +294,7 @@ class Topic(callbacks.Privmsg, configurable.Mixin): except IndexError: irc.error(msg, 'That\'s not a valid topic number.') return - match = self.topicUnformatter.match(topic) - if match is None: - name = '' - else: - (topic, name) = match.groups() + (topic, name) = self._unformatTopic(topic, channel) try: username = ircdb.users.getUser(msg.prefix).name except KeyError: diff --git a/src/Misc.py b/src/Misc.py index ed456ae36..3195c1e08 100755 --- a/src/Misc.py +++ b/src/Misc.py @@ -318,7 +318,7 @@ class Misc(callbacks.Privmsg): chunk = L.pop() if L: chunk += ' \x02(%s)\x0F' % \ - utils.nItems(len(L), 'message', 'more') + utils.nItems('message', len(L), 'more') irc.reply(msg, chunk, True) except KeyError: irc.error(msg, 'You haven\'t asked me a command!') diff --git a/src/Owner.py b/src/Owner.py index 141379ece..0f313c670 100644 --- a/src/Owner.py +++ b/src/Owner.py @@ -337,7 +337,7 @@ class Owner(privmsgs.CapabilityCheckingPrivmsg): if gc.garbage: irc.reply(msg, 'Garbage! %r' % gc.garbage) else: - irc.reply(msg, '%s collected.' % utils.nItems(collected, 'object')) + irc.reply(msg, '%s collected.' % utils.nItems('object', collected)) def set(self, irc, msg, args): """ diff --git a/src/callbacks.py b/src/callbacks.py index 93815743c..70a17e57b 100644 --- a/src/callbacks.py +++ b/src/callbacks.py @@ -445,8 +445,9 @@ class IrcObjectProxy: msgs.reverse() response = msgs.pop() if msgs: - response = ircutils.bold('(%s)') - response %= utils.nItems(len(msgs), 'message', 'more') + n = ircutils.bold('(%s)') + n %= utils.nItems('message', len(msgs), 'more') + response = '%s %s' % (response, n) mask = msg.prefix.split('!', 1)[1] Privmsg._mores[mask] = msgs private = self.private or not ircutils.isChannel(msg.args[0]) diff --git a/src/utils.py b/src/utils.py index aaa3e06d8..ef821e9d9 100755 --- a/src/utils.py +++ b/src/utils.py @@ -124,31 +124,31 @@ def timeElapsed(elapsed, leadingZeroes=False, years=True, weeks=True, if leadingZeroes or yrs: if yrs: leadingZeroes = True - ret.append(nItems(yrs, 'year')) + ret.append(nItems('year', yrs)) if weeks: wks, elapsed = elapsed // 604800, elapsed % 604800 if leadingZeroes or wks: if wks: leadingZeroes = True - ret.append(nItems(wks, 'week')) + ret.append(nItems('week', wks)) if days: ds, elapsed = elapsed // 86400, elapsed % 86400 if leadingZeroes or ds: if ds: leadingZeroes = True - ret.append(nItems(ds, 'day')) + ret.append(nItems('day', ds)) if hours: hrs, elapsed = elapsed // 3600, elapsed % 3600 if leadingZeroes or hrs: if hrs: leadingZeroes = True - ret.append(nItems(hrs, 'hour')) + ret.append(nItems('hour', hrs)) if minutes or seconds: mins, secs = elapsed // 60, elapsed % 60 if leadingZeroes or mins: - ret.append(nItems(mins, 'minute')) + ret.append(nItems('minute', mins)) if seconds: - ret.append(nItems(secs, 'second')) + ret.append(nItems('second', secs)) if len(ret) == 0: raise ValueError, 'Time difference not great enough to be noted.' if len(ret) == 1: @@ -317,7 +317,7 @@ def _matchCase(s1, s2): L[i] = char.upper() return ''.join(L) -def pluralize(i, s): +def pluralize(s, i=2): """Returns the plural of s based on its number i. Put any exceptions to the general English rule of appending 's' in the plurals dictionary. """ @@ -345,22 +345,22 @@ def depluralize(s): else: return s # Don't know what to do. -def nItems(n, item, between=None): +def nItems(item, n, between=None): """Works like this: - >>> nItems(1, 'clock') + >>> nItems('clock', 1) '1 clock' - >>> nItems(10, 'clock') + >>> nItems('clock', 10) '10 clocks' - >>> nItems(10, 'clock', between='grandfather') + >>> nItems('clock', 10, between='grandfather') '10 grandfather clocks' """ if between is None: - return '%s %s' % (n, pluralize(n, item)) + return '%s %s' % (n, pluralize(item, n)) else: - return '%s %s %s' % (n, between, pluralize(n, item)) + return '%s %s %s' % (n, between, pluralize(item, n)) def be(i): """Returns the form of the verb 'to be' based on the number i.""" diff --git a/test/test_Todo.py b/test/test_Todo.py index 930594eb6..16e9b4972 100644 --- a/test/test_Todo.py +++ b/test/test_Todo.py @@ -113,8 +113,6 @@ if sqlite is not None: self.assertRegexp('todo search task*', '#1: task number one and #2: task number two is ' 'much longer than task number...') - self.assertRegexp('todo search --exact "task number one"', - '#1: task number one') self.assertError('todo search --regexp s/bustedregex') self.assertRegexp('todo search --regexp m/task/', '#1: task number one and #2: task number two is ' diff --git a/test/test_Topic.py b/test/test_Topic.py index eead48c8b..721bf93a2 100644 --- a/test/test_Topic.py +++ b/test/test_Topic.py @@ -104,5 +104,14 @@ class TopicTestCase(ChannelPluginTestCase, PluginDocumentation): _ = self.getMsg('topic remove 1') self.assertError('topic reorder 0') + def testList(self): + _ = self.getMsg('topic add foo') + self.assertResponse('topic list', '1: foo') + _ = self.getMsg('topic add bar') + self.assertResponse('topic list', '1: foo and 2: bar') + _ = self.getMsg('topic add baz') + self.assertResponse('topic list', '1: foo, 2: bar, and 3: baz') + + # vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: diff --git a/test/test_utils.py b/test/test_utils.py index 90bf42294..ff465fe58 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -37,14 +37,14 @@ import utils class UtilsTest(unittest.TestCase): def testPluralize(self): f = utils.pluralize - self.assertEqual('bike', f(1, 'bike')) - self.assertEqual('bikes', f(2, 'bike')) - self.assertEqual('BIKE', f(1, 'BIKE')) - self.assertEqual('BIKES', f(2, 'BIKE')) - self.assertEqual('match', f(1, 'match')) - self.assertEqual('matches', f(2, 'match')) - self.assertEqual('Patch', f(1, 'Patch')) - self.assertEqual('Patches', f(2, 'Patch')) + self.assertEqual('bike', f('bike', 1)) + self.assertEqual('bikes', f('bike', 2)) + self.assertEqual('BIKE', f('BIKE', 1)) + self.assertEqual('BIKES', f('BIKE', 2)) + self.assertEqual('match', f('match', 1)) + self.assertEqual('matches', f('match', 2)) + self.assertEqual('Patch', f('Patch', 1)) + self.assertEqual('Patches', f('Patch', 2)) def testDepluralize(self): f = utils.depluralize @@ -221,10 +221,10 @@ class UtilsTest(unittest.TestCase): self.assertEqual(utils.sorted(L, mycmp), ['c', 'b', 'a']) def testNItems(self): - self.assertEqual(utils.nItems(1, 'tool', 'crazy'), '1 crazy tool') - self.assertEqual(utils.nItems(1, 'tool'), '1 tool') - self.assertEqual(utils.nItems(2, 'tool', 'crazy'), '2 crazy tools') - self.assertEqual(utils.nItems(2, 'tool'), '2 tools') + self.assertEqual(utils.nItems('tool', 1, 'crazy'), '1 crazy tool') + self.assertEqual(utils.nItems('tool', 1), '1 tool') + self.assertEqual(utils.nItems('tool', 2, 'crazy'), '2 crazy tools') + self.assertEqual(utils.nItems('tool', 2), '2 tools') def testItersplit(self): from utils import itersplit diff --git a/test/testsupport.py b/test/testsupport.py index c754a52a4..99edddd9d 100644 --- a/test/testsupport.py +++ b/test/testsupport.py @@ -106,6 +106,9 @@ class PluginTestCase(unittest.TestCase): cleanDataDir = True def setUp(self, nick='test'): # Set conf variables appropriately. + if self.__class__ in (PluginTestCase, ChannelPluginTestCase): + # Necessary because there's a test in here that shouldn\'t run. + return conf.prefixChars = '@' conf.replyWhenNotCommand = False self.myVerbose = world.myVerbose @@ -137,6 +140,9 @@ class PluginTestCase(unittest.TestCase): cb = Owner.loadPluginClass(self.irc, module) def tearDown(self): + if self.__class__ in (PluginTestCase, ChannelPluginTestCase): + # Necessary because there's a test in here that shouldn\'t run. + return self.irc.die() gc.collect() @@ -262,9 +268,29 @@ class PluginTestCase(unittest.TestCase): self.failUnless(re.search(regexp, s, flags), '%r does not match %r' % (s, regexp)) + def testDocumentation(self): + if self.__class__ in (PluginTestCase, ChannelPluginTestCase): + return + for cb in self.irc.callbacks: + name = cb.name() + if (name in ('Admin', 'Channel', 'Misc', 'Owner', 'User') and \ + not name.lower() in self.__class__.__name__.lower()) or \ + isinstance(cb, callbacks.PrivmsgRegexp): + continue + self.failUnless(sys.modules[cb.__class__.__name__].__doc__, + '%s has no module documentation.' % name) + if hasattr(cb, 'isCommand'): + for attr in dir(cb): + if cb.isCommand(attr): + self.failUnless(getattr(cb, attr, None).__doc__, + '%s.%s has no help.' % (name, attr)) + + class ChannelPluginTestCase(PluginTestCase): channel = '#test' def setUp(self): + if self.__class__ in (PluginTestCase, ChannelPluginTestCase): + return PluginTestCase.setUp(self) self.irc.feedMsg(ircmsgs.join(self.channel, prefix=self.prefix)) @@ -307,33 +333,7 @@ class ChannelPluginTestCase(PluginTestCase): class PluginDocumentation: - def testAllCommandsHaveHelp(self): - for cb in self.irc.callbacks: - if isinstance(cb, callbacks.PrivmsgRegexp): - continue - if hasattr(cb, 'isCommand'): - for attr in cb.__class__.__dict__: - if cb.isCommand(attr): - self.failUnless(getattr(cb, attr).__doc__, - '%s has no syntax' % attr) - - def testAllCommandsHaveMorehelp(self): - for cb in self.irc.callbacks: - if isinstance(cb, callbacks.PrivmsgRegexp): - continue - if hasattr(cb, 'isCommand'): - for attr in cb.__class__.__dict__: - if cb.isCommand(attr): - command = getattr(cb, attr) - helps = command.__doc__ - self.failUnless(helps and len(helps.splitlines()) >= 3, - '%s has no help' % attr) - - def testPluginHasDocumentation(self): - for cb in self.irc.callbacks: - m = sys.modules[cb.__class__.__module__] - self.failIf(m.__doc__ is None, - '%s has no module documentation'%cb.__class__.__name__) + pass # This is old stuff, it should be removed some day.