diff --git a/plugins/Admin/plugin.py b/plugins/Admin/plugin.py index 6f891b246..5d9d22467 100644 --- a/plugins/Admin/plugin.py +++ b/plugins/Admin/plugin.py @@ -184,8 +184,8 @@ class Admin(callbacks.Privmsg): def do438(self, irc, msg): irc = self.pendingNickChanges.get(irc, None) if irc is not None: - irc.error('I can\'t change nicks, the server said %s.' % - utils.str.quoted(msg.args[2]), private=True) + irc.error(format('I can\'t change nicks, the server said %q.', + msg.args[2]), private=True) else: self.log.debug('Got 438 without Admin.nick being called.') diff --git a/plugins/Babelfish/plugin.py b/plugins/Babelfish/plugin.py index 35db0045f..e907cb35c 100644 --- a/plugins/Babelfish/plugin.py +++ b/plugins/Babelfish/plugin.py @@ -64,7 +64,7 @@ class Babelfish(callbacks.Privmsg): Returns the languages that Babelfish can translate to/from. """ - irc.reply(utils.str.commaAndify(babelfish.available_languages)) + irc.reply(format('%L', babelfish.available_languages)) def translate(self, irc, msg, args, fromLang, toLang, text): """ [to] @@ -77,20 +77,20 @@ class Babelfish(callbacks.Privmsg): try: (fromLang, toLang) = self._getLang(fromLang, toLang, chan) if not fromLang or not toLang: - langs = self.registryValue('languages', chan) + langs = list(self.registryValue('languages', chan)) if not langs: irc.error('I do not speak any other languages.') return else: - irc.error('I only speak %s.' % utils.str.commaAndify(langs)) + irc.error(format('I only speak %L.', langs)) return translation = babelfish.translate(text, fromLang, toLang) irc.reply(utils.web.htmlToText(translation)) except (KeyError, babelfish.LanguageNotAvailableError), e: languages = self.registryValue('languages', chan) if languages: - languages = 'Valid languages include %s' % \ - utils.str.commaAndify(sorted(languages)) + languages = format('Valid languages include %L', + sorted(languages)) else: languages = 'I do not speak any other languages.' irc.errorInvalid('language', str(e), languages) @@ -120,16 +120,15 @@ class Babelfish(callbacks.Privmsg): irc.error('I do not speak any other languages.') return else: - irc.error('I only speak %s.' % utils.str.commaAndify(langs, - And='or')) + irc.error(format('I only speak %L.', (langs, 'or'))) return translations = babelfish.babelize(text, fromLang, toLang) irc.reply(utils.web.htmlToText(translations[-1])) except (KeyError, babelfish.LanguageNotAvailableError), e: languages = self.registryValue('languages', chan) if languages: - languages = 'Valid languages include %s' % \ - utils.str.commaAndify(sorted(languages)) + languages = format('Valid languages include %L', + sorted(languages)) else: languages = 'I do not speak any other languages.' irc.errorInvalid('language', str(e), languages) diff --git a/plugins/Channel/config.py b/plugins/Channel/config.py index f47688626..9c719f60a 100644 --- a/plugins/Channel/config.py +++ b/plugins/Channel/config.py @@ -46,13 +46,12 @@ class BanmaskStyle(registry.SpaceSeparatedSetOfStrings): assert self.validStrings, 'There must be some valid strings. ' \ 'This is a bug.' registry.SpaceSeparatedSetOfStrings.__init__(self, *args, **kwargs) - self.__doc__ = 'Valid values include %s.' % \ - utils.str.commaAndify(map(repr, self.validStrings)) + self.__doc__ = format('Valid values include %L.', + map(repr, self.validStrings)) def help(self): strings = [s for s in self.validStrings if s] - return '%s Valid strings: %s.' % \ - (self._help, utils.str.commaAndify(strings)) + return format('%s Valid strings: %L.', self._help, strings) def normalize(self, s): lowered = s.lower() diff --git a/plugins/Channel/plugin.py b/plugins/Channel/plugin.py index a194a690e..4a5a0db3e 100644 --- a/plugins/Channel/plugin.py +++ b/plugins/Channel/plugin.py @@ -284,13 +284,12 @@ class Channel(callbacks.Privmsg): # Check that they're not trying to make us kickban ourself. self.log.debug('In kban') if not irc.isNick(bannedNick): - self.log.warning('%s tried to kban a non nick: %s', - utils.str.quoted(msg.prefix), - utils.str.quoted(bannedNick)) + self.log.warning(format('%q tried to kban a non nick: %q', + msg.prefix, bannedNick)) raise callbacks.ArgumentError elif bannedNick == irc.nick: - self.log.warning('%s tried to make me kban myself.', - utils.str.quoted(msg.prefix)) + self.log.warning(format('%q tried to make me kban myself.', + msg.prefix)) irc.error('I cowardly refuse to kickban myself.') return if not reason: @@ -327,8 +326,8 @@ class Channel(callbacks.Privmsg): # Check (again) that they're not trying to make us kickban ourself. if ircutils.hostmaskPatternEqual(banmask, irc.prefix): if ircutils.hostmaskPatternEqual(banmask, irc.prefix): - self.log.warning('%s tried to make me kban myself.', - utils.str.quoted(msg.prefix)) + self.log.warning(format('%q tried to make me kban myself.', + msg.prefix)) irc.error('I cowardly refuse to ban myself.') return else: @@ -351,16 +350,16 @@ class Channel(callbacks.Privmsg): doBan() elif ircdb.checkCapability(msg.prefix, capability): if ircdb.checkCapability(bannedHostmask, capability): - self.log.warning('%s tried to ban %s, but both have %s', - msg.prefix, utils.str.quoted(bannedHostmask), - capability) + self.log.warning( + format('%s tried to ban %q, but both have %s', + msg.prefix, bannedHostmask, capability)) irc.error('%s has %s too, you can\'t ban him/her/it.' % (bannedNick, capability)) else: doBan() else: - self.log.warning('%s attempted kban without %s', - utils.str.quoted(msg.prefix), capability) + self.log.warning(format('%q attempted kban without %s', + msg.prefix, capability)) irc.errorNoCapability(capability) exact,nick,user,host kban = wrap(kban, @@ -513,7 +512,7 @@ class Channel(callbacks.Privmsg): # XXX Add the expirations. c = ircdb.channels.getChannel(channel) if c.bans: - irc.reply(utils.str.commaAndify(map(utils.str.dqrepr, c.bans))) + irc.reply(format('%L', map(utils.str.dqrepr, c.bans))) else: irc.reply('There are currently no permanent bans on %s' % channel) permbans = wrap(permbans, [('checkChannelCapability', 'op')]) @@ -558,8 +557,8 @@ class Channel(callbacks.Privmsg): # XXX Add the expirations. c = ircdb.channels.getChannel(channel) if len(c.ignores) == 0: - s = 'I\'m not currently ignoring any hostmasks in %s' % \ - utils.str.quoted(channel) + s = format('I\'m not currently ignoring any hostmasks in %q', + channel) irc.reply(s) else: L = sorted(c.ignores) @@ -599,9 +598,10 @@ class Channel(callbacks.Privmsg): fail.append(c) ircdb.users.setUser(user) if fail: - irc.error('That user didn\'t have the %s %s.' % - (utils.str.commaAndify(fail), - utils.str.pluralize('capability', len(fail))), + s = 'capability' + if len(fail) > 1: + s = utils.str.pluralize(s) + irc.error(format('That user didn\'t have the %L %s.', fail, s), Raise=True) irc.replySuccess() removecapability = wrap(removecapability, @@ -660,9 +660,10 @@ class Channel(callbacks.Privmsg): fail.append(c) ircdb.channels.setChannel(channel, chan) if fail: - irc.error('I do not know about the %s %s.' % - (utils.str.commaAndify(fail), - utils.str.pluralize('capability', len(fail))), + s = 'capability' + if len(fail) > 1: + s = utils.str.pluralize(s) + irc.error(format('I do not know about the %L %s.', fail, s), Raise=True) irc.replySuccess() unsetcapability = wrap(unsetcapability, diff --git a/plugins/Config/plugin.py b/plugins/Config/plugin.py index 696dc3adc..bb68ff50f 100644 --- a/plugins/Config/plugin.py +++ b/plugins/Config/plugin.py @@ -130,7 +130,7 @@ class Config(callbacks.Privmsg): """ L = self._list(group) if L: - irc.reply(utils.str.commaAndify(L)) + irc.reply(format('%L', L)) else: irc.error('There don\'t seem to be any values in %s.' % group._name) list = wrap(list, ['configVar']) @@ -147,7 +147,7 @@ class Config(callbacks.Privmsg): if not ircutils.isChannel(possibleChannel): L.append(name) if L: - irc.reply(utils.str.commaAndify(L)) + irc.reply(format('%L', L)) else: irc.reply('There were no matching configuration variables.') search = wrap(search, ['lowered']) # XXX compose with withoutSpaces? diff --git a/plugins/Dict/plugin.py b/plugins/Dict/plugin.py index 0e4e5c34d..8740ebabe 100644 --- a/plugins/Dict/plugin.py +++ b/plugins/Dict/plugin.py @@ -48,9 +48,9 @@ class Dict(callbacks.Privmsg): try: server = conf.supybot.plugins.Dict.server() conn = dictclient.Connection(server) - dbs = conn.getdbdescs().keys() + dbs = list(conn.getdbdescs().keys()) dbs.sort() - irc.reply(utils.str.commaAndify(dbs)) + irc.reply(format('%L', dbs)) except socket.error, e: irc.error(utils.web.strError(e)) dictionaries = wrap(dictionaries) @@ -98,11 +98,10 @@ class Dict(callbacks.Privmsg): dbs = set() if not definitions: if dictionary == '*': - irc.reply('No definition for %s could be found.' % - utils.str.quoted(word)) + irc.reply(format('No definition for %q could be found.', word)) else: - irc.reply('No definition for %s could be found in %s' % - (utils.str.quoted(word), ircutils.bold(dictionary))) + irc.reply(format('No definition for %q could be found in %s', + word, ircutils.bold(dictionary))) return L = [] for d in definitions: @@ -113,7 +112,7 @@ class Dict(callbacks.Privmsg): L.append('%s: %s' % (db, s)) utils.gen.sortBy(len, L) if dictionary == '*' and len(dbs) > 1: - s = '%s responded: %s' % (utils.str.commaAndify(dbs), '; '.join(L)) + s = format('%L responded: %s', list(dbs), '; '.join(L)) else: s = '; '.join(L) irc.reply(s) diff --git a/plugins/Math/plugin.py b/plugins/Math/plugin.py index f508c74ae..04be343d5 100644 --- a/plugins/Math/plugin.py +++ b/plugins/Math/plugin.py @@ -184,8 +184,7 @@ class Math(callbacks.Privmsg): return str(x) text = self._mathRe.sub(handleMatch, text) try: - self.log.info('evaluating %s from %s' % - (utils.str.quoted(text), msg.prefix)) + self.log.info(format('evaluating %q from %s', text, msg.prefix)) x = complex(eval(text, self._mathEnv, self._mathEnv)) irc.reply(self._complexToString(x)) except OverflowError: @@ -219,8 +218,7 @@ class Math(callbacks.Privmsg): return text = text.replace('lambda', '') try: - self.log.info('evaluating %s from %s' % - (utils.str.quoted(text), msg.prefix)) + self.log.info(format('evaluating %q from %s', text, msg.prefix)) irc.reply(str(eval(text, self._mathEnv, self._mathEnv))) except OverflowError: maxFloat = math.ldexp(0.9999999999999999, 1024) @@ -276,8 +274,7 @@ class Math(callbacks.Privmsg): try: stack.append(eval(s, self._mathEnv, self._mathEnv)) except SyntaxError: - irc.error('%s is not a defined function.' % - utils.str.quoted(arg)) + irc.error(format('%q is not a defined function.', arg)) return if len(stack) == 1: irc.reply(str(self._complexToString(complex(stack[0])))) diff --git a/plugins/Misc/plugin.py b/plugins/Misc/plugin.py index f0a040406..a838166ec 100644 --- a/plugins/Misc/plugin.py +++ b/plugins/Misc/plugin.py @@ -118,7 +118,7 @@ class Misc(callbacks.Privmsg): (not private and isPublic(cb))] names.sort() if names: - irc.reply(utils.str.commaAndify(names)) + irc.reply(format('%L', names)) else: if private: irc.reply('There are no private plugins.') @@ -143,7 +143,7 @@ class Misc(callbacks.Privmsg): commands.append(s) if commands: commands.sort() - irc.reply(utils.str.commaAndify(commands)) + irc.reply(format('%L', commands)) else: irc.error('That plugin exists, but it has no ' 'commands with help.') @@ -172,7 +172,7 @@ class Misc(callbacks.Privmsg): L.append('%s %s' % (name, key)) if L: L.sort() - irc.reply(utils.str.commaAndify(L)) + irc.reply(format('%L', L)) else: irc.reply('No appropriate commands were found.') apropos = wrap(apropos, ['lowered']) @@ -204,9 +204,9 @@ class Misc(callbacks.Privmsg): irc.error('There is no command %s.' % command) elif len(cbs) > 1: names = sorted([cb.name() for cb in cbs]) - irc.error('That command exists in the %s plugins. ' - 'Please specify exactly which plugin command ' - 'you want help with.'% utils.str.commaAndify(names)) + irc.error(format('That command exists in the %L plugins. ' + 'Please specify exactly which plugin command ' + 'you want help with.', names)) else: getHelp(cbs[0]) else: @@ -260,13 +260,14 @@ class Misc(callbacks.Privmsg): if cbs: names = [cb.name() for cb in cbs] names.sort() - plugin = utils.str.commaAndify(names) if irc.nested: - irc.reply(utils.str.commaAndify(names)) + irc.reply(format('%L', names)) else: - irc.reply('The %s command is available in the %s %s.' % - (utils.str.quoted(command), plugin, - utils.str.pluralize('plugin', len(names)))) + s = 'plugin' + if len(names) > 1: + s = utils.str.pluralize(s) + irc.reply(format('The %q command is available in the %L %s.', + command, names, s)) else: irc.error('There is no such command %s.' % command) plugin = wrap(plugin, ['commandName']) @@ -311,8 +312,7 @@ class Misc(callbacks.Privmsg): L = self._mores[userHostmask] chunk = L.pop() if L: - chunk += ' \x02(%s)\x0F' % \ - utils.str.nItems('message', len(L), 'more') + chunk += format(' \x02(%n)\x0F', (len(L), 'message', 'more')) irc.reply(chunk, True) except KeyError: irc.error('You haven\'t asked me a command; perhaps you want ' @@ -404,7 +404,7 @@ class Misc(callbacks.Privmsg): irc.error('I couldn\'t find a message matching that criteria in ' 'my history of %s messages.' % len(irc.state.history)) else: - irc.reply(utils.str.commaAndify(resp)) + irc.reply(format('%L', resp)) last = wrap(last, [getopts({'nolimit': '', 'on': 'something', 'with': 'something', @@ -491,7 +491,7 @@ class Misc(callbacks.Privmsg): shortname[, shortname and shortname]. """ L = [getShortName(n) for n in longList] - return utils.str.commaAndify(L) + return format('%L', L) def sortAuthors(): """ Sort the list of 'long names' based on the number of contributions @@ -525,9 +525,9 @@ class Misc(callbacks.Privmsg): except ValueError: pass if contribs: - contrib = '%s %s contributed to it.' % \ - (buildContributorsString(contribs), - utils.str.has(len(contribs))) + contrib = format('%s %h contributed to it.', + buildContributorsString(contribs), + len(contribs)) hasContribs = True elif hasAuthor: contrib = 'has no additional contributors listed' @@ -557,19 +557,22 @@ class Misc(callbacks.Privmsg): contributions) results = [] if commands: - results.append( - 'the %s %s' %(utils.str.commaAndify(commands), - utils.str.pluralize('command',len(commands)))) + s = 'command' + if len(commands) > 1: + s = utils.str.pluralize(s) + results.append(format('the %L %s', commands, s)) if nonCommands: - results.append('the %s' % utils.str.commaAndify(nonCommands)) + results.append(format('the %L', nonCommands)) if results and isAuthor: - return '%s wrote the %s plugin and also contributed %s' % \ - (fullName, cb.name(), utils.str.commaAndify(results)) + return format('%s wrote the %s plugin and also contributed %L', + (fullName, cb.name(), results)) elif results and not isAuthor: - return '%s contributed %s to the %s plugin' % \ - (fullName, utils.str.commaAndify(results), cb.name()) + return format('%s contributed %L to the %s plugin', + fullName, results, cb.name()) elif isAuthor and not results: return '%s wrote the %s plugin' % (fullName, cb.name()) + # XXX Does this ever actually get reached? If so, the string + # formatting needs to be fixed. else: return '%s has no listed contributions for the %s plugin %s' %\ (fullName, cb.name()) diff --git a/plugins/Network/plugin.py b/plugins/Network/plugin.py index 7fe687dcc..4bd566507 100644 --- a/plugins/Network/plugin.py +++ b/plugins/Network/plugin.py @@ -168,19 +168,19 @@ class Network(callbacks.Privmsg): normal.append(channel) L = [] if ops: - L.append('is an op on %s' % utils.str.commaAndify(ops)) + L.append(format('is an op on %L', ops)) if halfops: - L.append('is a halfop on %s' % utils.str.commaAndify(halfops)) + L.append(format('is a halfop on %L', halfops)) if voices: - L.append('is voiced on %s' % utils.str.commaAndify(voices)) + L.append(format('is voiced on %L', voices)) if normal: if L: - L.append('is also on %s' % utils.str.commaAndify(normal)) + L.append(format('is also on %L', normal)) else: - L.append('is on %s' % utils.str.commaAndify(normal)) + L.append(format('is on %L', normal)) else: L = ['isn\'t on any non-secret channels'] - channels = utils.str.commaAndify(L) + channels = format('%L', L) if '317' in d: idle = utils.gen.timeElapsed(d['317'].args[2]) signon = time.strftime(conf.supybot.reply.format.time(), @@ -241,8 +241,8 @@ class Network(callbacks.Privmsg): Returns the networks to which the bot is currently connected. """ L = ['%s: %s' % (ircd.network, ircd.server) for ircd in world.ircs] - utils.sortBy(str.lower, L) - irc.reply(utils.str.commaAndify(L)) + utils.gen.sortBy(str.lower, L) + irc.reply(format('%L', L)) networks = wrap(networks) def doPong(self, irc, msg): diff --git a/plugins/Status/plugin.py b/plugins/Status/plugin.py index 8723a36b8..825e85010 100644 --- a/plugins/Status/plugin.py +++ b/plugins/Status/plugin.py @@ -193,7 +193,7 @@ class Status(callbacks.Privmsg): commands.add(attr) commands = list(commands) commands.sort() - irc.reply(utils.str.commaAndify(commands)) + irc.reply(format('%L', commands)) commands = wrap(commands) def uptime(self, irc, msg, args): diff --git a/plugins/User/plugin.py b/plugins/User/plugin.py index 279b1a03a..2f03749ba 100644 --- a/plugins/User/plugin.py +++ b/plugins/User/plugin.py @@ -70,8 +70,8 @@ class User(callbacks.Privmsg): else: users.append(u.name) if users: - utils.sortBy(str.lower, users) - irc.reply(utils.str.commaAndify(users)) + utils.gen.sortBy(str.lower, users) + irc.reply(format('%L', users)) else: if predicates: irc.reply('There are no matching registered users.') @@ -154,7 +154,7 @@ class User(callbacks.Privmsg): """ try: id = ircdb.users.getUserId(newname) - irc.error('%s is already registered.' % utils.str.quoted(newname)) + irc.error(format('%q is already registered.', newname)) return except KeyError: pass @@ -291,7 +291,7 @@ class User(callbacks.Privmsg): def getHostmasks(user): hostmasks = map(repr, user.hostmasks) hostmasks.sort() - return utils.str.commaAndify(hostmasks) + return format('%L', hostmasks) try: user = ircdb.users.getUser(msg.prefix) if name: diff --git a/plugins/__init__.py b/plugins/__init__.py index 613b98e32..5f85d6b5d 100644 --- a/plugins/__init__.py +++ b/plugins/__init__.py @@ -384,9 +384,9 @@ class ChannelIdDatabasePlugin(callbacks.Privmsg): def getCommandHelp(self, name): help = self.__parent.getCommandHelp(name) - help = help.replace('$Types', utils.str.pluralize(self.name())) + help = help.replace('$Types', format('%p', self.name())) help = help.replace('$Type', self.name()) - help = help.replace('$types', utils.str.pluralize(self.name().lower())) + help = help.replace('$types', format('%p', self.name().lower())) help = help.replace('$type', self.name().lower()) return help @@ -437,8 +437,8 @@ class ChannelIdDatabasePlugin(callbacks.Privmsg): remove = wrap(remove, ['user', 'channeldb', 'id']) def searchSerializeRecord(self, record): - text = utils.str.quoted(utils.str.ellipsisify(record.text, 50)) - return '#%s: %s' % (record.id, text) + text = utils.str.ellipsisify(record.text, 50) + return format('#%s: %q' % (record.id, text)) def search(self, irc, msg, args, channel, optlist, glob): """[] [--{regexp,by} ] [] diff --git a/sandbox/Debug/plugin.py b/sandbox/Debug/plugin.py index 29c76f414..eb5d2dfcf 100644 --- a/sandbox/Debug/plugin.py +++ b/sandbox/Debug/plugin.py @@ -67,7 +67,7 @@ class Debug(privmsgs.CapabilityCheckingPrivmsg): _evalEnv.update(globals()) def eval(self, irc, msg, args, s): """ - + Evaluates (which should be a Python expression) and returns its value. If an exception is raised, reports the exception (and logs the traceback to the bot's logfile). @@ -80,13 +80,12 @@ class Debug(privmsgs.CapabilityCheckingPrivmsg): self._evalEnv['_'] = x irc.reply(repr(x)) except SyntaxError, e: - irc.reply('%s: %s' % (utils.exnToString(e), - utils.quoted(s))) + irc.reply(format('%s: %q', utils.gen.exnToString(e), s)) eval = wrap(eval, ['text']) def _exec(self, irc, msg, args, s): """ - + Execs . Returns success if it didn't raise any exceptions. """ exec s @@ -163,7 +162,7 @@ class Debug(privmsgs.CapabilityCheckingPrivmsg): while times: L.append(gc.collect()) times -= 1 - irc.reply(utils.commaAndify(map(str, L))) + irc.reply(format('%L', map(str, L))) collect = wrap(collect, [additional('positiveInt', 1)]) diff --git a/scripts/supybot-wizard b/scripts/supybot-wizard index df9dd8771..25d270b9a 100644 --- a/scripts/supybot-wizard +++ b/scripts/supybot-wizard @@ -240,7 +240,7 @@ def main(): else.""") pluginDirs = conf.supybot.directories.plugins() output("""Currently, the bot knows about the following directories:""") - output(utils.commaAndify(pluginDirs)) + output(format('%L', pluginDirs)) while yn('Would you like to add another plugin directory?', default=False): (pluginDir, _) = getDirectoryName('plugins', basedir=basedir) @@ -422,8 +422,7 @@ def main(): addedBulk = False if advanced and yn('Would you like to add plugins en masse first?'): addedBulk = True - output("""The available plugins are: %s.""" % \ - utils.commaAndify(plugins)) + output(format("""The available plugins are: %L.""", plugins)) output("""What plugins would you like to add? If you've changed your mind and would rather not add plugins in bulk like this, just press enter and we'll move on to the individual plugin configuration.""") diff --git a/src/callbacks.py b/src/callbacks.py index a6b1f10ba..6f8dc9522 100644 --- a/src/callbacks.py +++ b/src/callbacks.py @@ -489,8 +489,8 @@ class RichReplyMethods(object): if 'Raise' not in kwargs: kwargs['Raise'] = True if isinstance(capability, basestring): # checkCommandCapability! - log.warning('Denying %s for lacking %s capability.', - self.msg.prefix, utils.str.quoted(capability)) + log.warning(format('Denying %s for lacking %q capability.', + self.msg.prefix, capability)) if not self._getConfig(conf.supybot.reply.error.noCapability): v = self._getConfig(conf.supybot.replies.noCapability) s = self.__makeReply(v % capability, s) @@ -866,7 +866,7 @@ class IrcObjectProxy(RichReplyMethods): response = msgs.pop() if msgs: n = ircutils.bold('(%s)') - n %= utils.str.nItems(len(msgs), 'message', 'more') + n %= format('%n', (len(msgs), 'message', 'more')) response = '%s %s' % (response, n) prefix = msg.prefix if self.to and ircutils.isNick(self.to): @@ -1118,8 +1118,7 @@ class Privmsg(irclib.IrcCallback): def getCommand(self, name): """Gets the given command from this plugin.""" name = canonicalName(name) - assert self.isCommand(name), '%s is not a command.' % \ - utils.str.quoted(name) + assert self.isCommand(name), format('%s is not a command.', name) return getattr(self, name) def callCommand(self, name, irc, msg, *L, **kwargs): @@ -1155,7 +1154,7 @@ class Privmsg(irclib.IrcCallback): elif hasattr(command, '__doc__'): return getHelp(command) else: - return 'The %s command has no help.' % utils.str.quoted(name) + return format('The %s command has no help.', name) def registryValue(self, name, channel=None, value=True): plugin = self.name() @@ -1286,9 +1285,9 @@ class PrivmsgRegexp(Privmsg): r = re.compile(value.__doc__, self.flags) self.res.append((r, name)) except re.error, e: - self.log.warning('Invalid regexp: %s (%s)', - utils.str.quoted(value.__doc__), e) - utils.sortBy(operator.itemgetter(1), self.res) + self.log.warning(format('Invalid regexp: %q (%s)', + value.__doc__, e)) + utils.gen.sortBy(operator.itemgetter(1), self.res) def callCommand(self, name, irc, msg, *L, **kwargs): try: diff --git a/src/ircdb.py b/src/ircdb.py index 93352f61e..b6f44b029 100644 --- a/src/ircdb.py +++ b/src/ircdb.py @@ -221,11 +221,10 @@ class IrcUser(object): self.hostmasks = hostmasks def __repr__(self): - return '%s(id=%s, ignore=%s, password="", name=%s, hashed=%r, ' \ - 'capabilities=%r, hostmasks=[], secure=%r)\n' % \ - (self.__class__.__name__, self.id, self.ignore, - utils.str.quoted(self.name), self.hashed, self.capabilities, - self.secure) + return format('%s(id=%s, ignore=%s, password="", name=%q, hashed=%r, ' + 'capabilities=%r, hostmasks=[], secure=%r)\n', + self.__class__.__name__, self.id, self.ignore, + self.name, self.hashed, self.capabilities, self.secure) def __hash__(self): return hash(self.id) @@ -652,8 +651,8 @@ class UsersDictionary(utils.IterableMap): log.error('Multiple matches found in user database. ' 'Removing the offending hostmasks.') for (id, hostmask) in ids.iteritems(): - log.error('Removing %s from user %s.', - utils.str.quoted(hostmask), id) + log.error(format('Removing %q from user %s.', hostmask, + id)) self.users[id].removeHostmask(hostmask) raise DuplicateHostmask, 'Ids %r matched.' % ids else: # Not a hostmask, must be a name. @@ -852,8 +851,7 @@ class IgnoresDB(object): expiration = 0 self.add(hostmask, expiration) except Exception, e: - log.error('Invalid line in ignores database: %s', - utils.str.quoted(line)) + log.error(format('Invalid line in ignores database: %q', line)) fd.close() def flush(self): diff --git a/src/irclib.py b/src/irclib.py index faf70378e..d9e1bb877 100644 --- a/src/irclib.py +++ b/src/irclib.py @@ -35,6 +35,7 @@ import operator import supybot.log as log import supybot.conf as conf +from utils.str import rsplit import supybot.utils as utils import supybot.world as world import supybot.ircdb as ircdb @@ -168,8 +169,8 @@ class IrcMsgQueue(object): if msg in self.msgs and \ not conf.supybot.protocols.irc.queueDuplicateMessages(): s = str(msg).strip() - log.info('Not adding message %s to queue, already added.', - utils.str.quoted(s)) + log.info( + format('Not adding message %q to queue, already added.', s)) return False else: self.msgs.add(msg) diff --git a/src/ircmsgs.py b/src/ircmsgs.py index 3132d86ac..12fb64a83 100644 --- a/src/ircmsgs.py +++ b/src/ircmsgs.py @@ -188,9 +188,8 @@ class IrcMsg(object): def __repr__(self): if self._repr is not None: return self._repr - self._repr = 'IrcMsg(prefix=%s, command=%s, args=%r)' % \ - (utils.str.quoted(self.prefix), - utils.str.quoted(self.command), self.args) + self._repr = format('IrcMsg(prefix=%q, command=%q, args=%r)', + self.prefix, self.command, self.args) return self._repr def __reduce__(self): diff --git a/src/plugin.py b/src/plugin.py index b6334a903..27724bf9d 100644 --- a/src/plugin.py +++ b/src/plugin.py @@ -48,8 +48,7 @@ def loadPluginModule(name, ignoreDeprecation=False): try: files.extend(os.listdir(dir)) except EnvironmentError: # OSError, IOError superclass. - log.warning('Invalid plugin directory: %s; removing.', - utils.str.quoted(dir)) + log.warning(format('Invalid plugin directory: %s; removing.', dir)) conf.supybot.directories.plugins().remove(dir) loweredFiles = map(str.lower, files) try: @@ -71,8 +70,8 @@ def loadPluginModule(name, ignoreDeprecation=False): if ignoreDeprecation: log.warning('Deprecated plugin loaded: %s', name) else: - raise Deprecated, 'Attempted to load deprecated plugin %s' % \ - utils.str.quoted(name) + raise Deprecated, format('Attempted to load deprecated plugin %s', + name) if module.__name__ in sys.modules: sys.modules[module.__name__] = module linecache.checkcache() diff --git a/src/registry.py b/src/registry.py index cd654447d..c84cededf 100644 --- a/src/registry.py +++ b/src/registry.py @@ -454,13 +454,12 @@ class OnlySomeStrings(String): 'This is a bug.' self.__parent = super(OnlySomeStrings, self) self.__parent.__init__(*args, **kwargs) - self.__doc__ = 'Valid values include %s.' % \ - utils.str.commaAndify(map(repr, self.validStrings)) + self.__doc__ = format('Valid values include %L.', + map(repr, self.validStrings)) def help(self): strings = [s for s in self.validStrings if s] - return '%s Valid strings: %s.' % \ - (self._help, utils.str.commaAndify(strings)) + return format('%s Valid strings: %L.', self._help, strings) def normalize(self, s): lowered = s.lower() diff --git a/src/test.py b/src/test.py index af5850fa6..fccb7b78f 100644 --- a/src/test.py +++ b/src/test.py @@ -96,7 +96,7 @@ class SupyTestCase(unittest.TestCase): def setUp(self): log.critical('Beginning test case %s', self.id()) threads = [t.getName() for t in threading.enumerate()] - log.critical('Threads: %s' % utils.str.commaAndify(threads)) + log.critical(format('Threads: %L', threads)) unittest.TestCase.setUp(self) def tearDown(self): diff --git a/src/utils/gen.py b/src/utils/gen.py index 5bdde8f92..9f489aa56 100644 --- a/src/utils/gen.py +++ b/src/utils/gen.py @@ -40,8 +40,8 @@ import UserDict import traceback from iter import imap +from str import format from file import mktemp -from str import quoted, nItems, commaAndify def abbrev(strings, d=None): """Returns a dictionary mapping unambiguous abbreviations to full forms.""" @@ -76,40 +76,40 @@ def timeElapsed(elapsed, short=False, leadingZeroes=False, years=True, be used. """ ret = [] - def format(s, i): + def Format(s, i): if i or leadingZeroes or ret: if short: ret.append('%s%s' % (i, s[0])) else: - ret.append(nItems(i, s)) + ret.append(format('%n', (i, s))) elapsed = int(elapsed) assert years or weeks or days or \ hours or minutes or seconds, 'One flag must be True' if years: (yrs, elapsed) = (elapsed // 31536000, elapsed % 31536000) - format('year', yrs) + Format('year', yrs) if weeks: (wks, elapsed) = (elapsed // 604800, elapsed % 604800) - format('week', wks) + Format('week', wks) if days: (ds, elapsed) = (elapsed // 86400, elapsed % 86400) - format('day', ds) + Format('day', ds) if hours: (hrs, elapsed) = (elapsed // 3600, elapsed % 3600) - format('hour', hrs) + Format('hour', hrs) if minutes or seconds: (mins, secs) = (elapsed // 60, elapsed % 60) if leadingZeroes or mins: - format('minute', mins) + Format('minute', mins) if seconds: leadingZeroes = True - format('second', secs) + Format('second', secs) if not ret: raise ValueError, 'Time difference not great enough to be noted.' if short: return ' '.join(ret) else: - return commaAndify(ret) + return format('%L', ret) def findBinaryInPath(s): """Return full path of a binary if it's in PATH, otherwise return None.""" @@ -150,7 +150,7 @@ def safeEval(s, namespace={'True': True, 'False': False, 'None': None}): if node.__class__ is compiler.ast.Module: return node.doc else: - raise ValueError, 'Unsafe string: %s' % quoted(s) + raise ValueError, format('Unsafe string: %q', s) node = nodes[0] if node.__class__ is not compiler.ast.Discard: raise ValueError, 'Invalid expression: %s' % quoted(s) diff --git a/src/utils/str.py b/src/utils/str.py index 7eba76169..b3a31bdd6 100644 --- a/src/utils/str.py +++ b/src/utils/str.py @@ -33,6 +33,7 @@ Simple utility functions related to strings. import re import new +import sys import string import textwrap