rewrite recursion/alias code for the 500th time.

more of a moving of the code, actually, it now exists in (an overridden)
_handle_event, so that recursions happen against irc events directly,
rather than an already partially interpreted object.

with this change, modules don't need to implement do() nor do we have a
need for the internal_bus, which was doing an additional walk of the
modules after the irc event was already handled and turned into text. now
the core event handler does the recursion scans.

to support this, we bring back the old replypath trick and use it again,
so we know when to send a privmsg reply and when to return text so that
it may be chained in recursion. this feels old hat by now, but if you
haven't been following along, you should really look at the diff.

that's the meat of the change. the rest is updating modules to use
self.reply() and reimplementing (un)register_handlers where appropriate
This commit is contained in:
Brian S. Stephan 2011-02-17 01:08:45 -06:00
parent 64df118c65
commit 2aa369add7
22 changed files with 208 additions and 116 deletions

View File

@ -17,6 +17,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import bisect
import copy
from ConfigParser import NoOptionError, NoSectionError
import re
import signal
@ -82,7 +83,6 @@ class DrBotIRC(irclib.IRC):
"""Implement a customized irclib IRC."""
modlist = []
internal_bus = []
config = None
server = None
@ -104,6 +104,31 @@ class DrBotIRC(irclib.IRC):
return self.server
def _handle_event(self, connection, event):
"""Override event handler to do recursion."""
self.try_recursion(connection, event)
self.try_alias(connection, event)
h = self.handlers
for handler in h.get("all_events", []) + h.get(event.eventtype(), []):
if handler[1](connection, event) == "NO MORE":
return
def try_to_replace_event_text_with_module_text(self, connection, event):
"""Do something very similar to _handle_event, but for recursion.
The intent here is that we replace [text] with whatever a module
provides to us.
"""
h = self.handlers
event._target = None
for handler in h.get("all_events", []) + h.get(event.eventtype(), []):
ret = handler[1](connection, event)
if ret:
event.arguments()[0] = ret
def on_pubmsg(self, connection, event):
"""See if there is an alias ("!command") in the text, and if so, translate it into
an internal bot command and run it.
@ -156,11 +181,10 @@ class DrBotIRC(irclib.IRC):
except NoOptionError: pass
except NoSectionError: pass
return self.reply(connection, replypath, self.try_recursion(connection, event, nick, userhost, what, admin_unlocked))
def try_alias(self, connection, event, nick, userhost, what, admin_unlocked):
def try_alias(self, connection, event):
# try doing alias work
try:
what = event.arguments()[0]
alias_list = self.config.options('Alias')
for alias in alias_list:
@ -168,19 +192,24 @@ class DrBotIRC(irclib.IRC):
if alias_re.search(what):
# we found an alias for our given string, doing a replace
command = re.sub(alias, self.config.get('Alias', alias), what)
event.arguments()[0] = command
# now we have to check it for recursions again
self.try_recursion(connection, event)
# i guess someone could have an alias of an alias... try again
command = self.try_alias(connection, event, nick, userhost, command, admin_unlocked)
return command
return self.try_alias(connection, event)
except NoOptionError: pass
except NoSectionError: pass
except IndexError: pass
# if we got here, there are no matching aliases, so return what we got
return what
return event
def reply(self, connection, replypath, replystr, stop_responding=False):
def reply(self, connection, event, replystr, stop_responding=False):
"""Reply over IRC to replypath or return a string with the reply."""
replypath = event.target()
if replystr is not None:
if replypath is None:
return replystr
@ -191,7 +220,7 @@ class DrBotIRC(irclib.IRC):
if stop_responding:
return "NO MORE"
def try_recursion(self, connection, event, nick, userhost, what, admin_unlocked):
def try_recursion(self, connection, event):
"""Scan message for subcommands to execute and use as part of this command.
Upon seeing a line intended for this module, see if there are subcommands
@ -203,44 +232,44 @@ class DrBotIRC(irclib.IRC):
where the output of anothercommand is command's arg2..n.
"""
attempt = what
try:
# begin recursion search
attempt = event.arguments()[0]
# check for aliases
attempt = self.try_alias(connection, event, nick, userhost, attempt, admin_unlocked)
start_idx = attempt.find('[')
subcmd = attempt[start_idx+1:]
end_idx = subcmd.rfind(']')
subcmd = subcmd[:end_idx]
# begin recursion search
if start_idx != -1 and end_idx != -1 and len(subcmd) > 0:
# found recursion candidate
# copy the event and see if IT has recursion to do
newevent = copy.deepcopy(event)
newevent.arguments()[0] = subcmd
self.try_recursion(connection, newevent)
start_idx = attempt.find('[')
subcmd = attempt[start_idx+1:]
end_idx = subcmd.rfind(']')
subcmd = subcmd[:end_idx]
# recursion over, check for aliases
self.try_alias(connection, newevent)
if start_idx == -1 or end_idx == -1 or len(subcmd) == 0:
# no recursion, so see if there's a module to handle this
return self.scan_modules(connection, event, nick, userhost, attempt, admin_unlocked)
else:
# found recursion, search again
ret = self.try_recursion(connection, event, nick, userhost, subcmd, admin_unlocked)
if ret is not None:
# recursion search had a hit, replace [foo] with it and re-recurse
return self.try_recursion(connection, event, nick, userhost, attempt.replace('['+subcmd+']', ret), admin_unlocked)
else:
# recursion search didn't have a hit, so see if there's a module to handle this
return self.scan_modules(connection, event, nick, userhost, attempt, admin_unlocked)
# now that we have a string that has been de-aliased and
# recursed all the way deeper into its text, see if any
# modules can do something with it. this calls the same
# event handlers in the same way as if this were a native
# event.
self.try_to_replace_event_text_with_module_text(connection, newevent)
def scan_modules(self, connection, event, nick, userhost, attempt, admin_unlocked):
"""Walk the loaded modules, see if any reply to input text."""
# we have done all we can do with the sub-event. whatever
# the text of that event now is, we should replace the parent
# event's [] section with it.
oldtext = event.arguments()[0]
newtext = oldtext.replace('['+subcmd+']', newevent.arguments()[0])
event.arguments()[0] = newtext
# aliases resolved. run result against each module
for (priority, handler) in self.internal_bus:
try:
ret = handler(connection, event, nick, userhost, attempt, admin_unlocked)
if ret is not None:
# a module had a result for us, post-alias, so return it
# TODO: scan all modules with compounding results
return ret
except Exception as e:
print('EXCEPTION: ' + str(e))
# we have now resolved the []. recursion will unfold, replacing
# it further and further, until we eventually get back to the
# original irc event in _handle_event, which will do one
# last search on the text.
except IndexError: pass
def quit_irc(self, connection, msg):
for module in self.modlist:
@ -277,8 +306,7 @@ class DrBotIRC(irclib.IRC):
module = sys.modules[modstr]
botmod = eval('module.' + modname + '(self, self.config, self.server)')
self.modlist.append(botmod)
bisect.insort(self.internal_bus, (botmod.priority(), botmod.do))
botmod.register_handlers(self.server)
botmod.register_handlers()
# might as well add it to the list
modset = set(self.config.get('dr.botzo', 'module_list').split(','))
@ -301,7 +329,6 @@ class DrBotIRC(irclib.IRC):
# remove module references
self.modlist.remove(module)
self.internal_bus.remove((module.priority(), module.do))
module.unregister_handlers()
# del it

View File

@ -57,27 +57,80 @@ class Module(object):
# print what was loaded, for debugging
print("loaded " + self.__class__.__name__)
def register_handlers(self, server):
def register_handlers(self):
"""Hook handler functions into the IRC library. This is called when the
module is loaded. Classes with special stuff to do could implement this
and set up the appropriate handlers, e.g.:
self.server.add_global_handler('welcome', self.on_connect)
Unless you're sure what you're doing, don't register pubmsg or privmsg.
They are handled by the alias support in DrBotIRC, and will call your
module's do().
By default, a module attaches to pubmsg/privmsg, which sets up some common
variables and then calls do(). You are free to implement do() (see below),
or override this and do whatever you want.
"""
self.server.add_global_handler('pubmsg', self.on_pub_or_privmsg, self.priority())
self.server.add_global_handler('privmsg', self.on_pub_or_privmsg, self.priority())
def unregister_handlers(self):
"""Unhook handler functions from the IRC library. Inverse of the above.
This is called by reload, to remove the soon-to-be old object from the server
global handlers (or whatever has been added via register_handlers). Classes
inheriting from Module could implement this, e.g.:
inheriting from Module could reimplement this, e.g.:
self.server.remove_global_handler('welcome', self.on_connect)
"""
self.server.remove_global_handler('pubmsg', self.on_pub_or_privmsg)
self.server.remove_global_handler('privmsg', self.on_pub_or_privmsg)
def on_pub_or_privmsg(self, connection, event):
"""Do a default thing on a pubmsg or privmsg.
Sets up a couple variables and then calls do(), which by default we
expect implementers to implement.
"""
nick = irclib.nm_to_n(event.source())
userhost = irclib.nm_to_uh(event.source())
replypath = event.target()
what = event.arguments()[0]
admin_unlocked = False
# privmsg
if replypath == connection.get_nickname():
replypath = nick
try:
if userhost == self.config.get('dr.botzo', 'admin_userhost'):
admin_unlocked = True
except NoOptionError: pass
return self.do(connection, event, nick, userhost, what, admin_unlocked)
def reply(self, connection, event, replystr, stop_responding=False):
"""Reply over IRC to replypath or return a string with the reply.
The primary utility for this is to properly handle recursion. The recursion
code in DrBotIRC will set up a couple hints that this method picks up on and
will appropriately send an IRC event or return a string.
Unless you know what you are doing, the modules you write should return
this method rather than send a privmsg reply, as failing to call this
method will certainly have recursion do odd things with your module.
"""
replypath = event.target()
if replystr is not None:
if replypath is None:
return replystr
else:
replies = replystr.split('\n')
for reply in replies:
connection.privmsg(replypath, reply)
if stop_responding:
return "NO MORE"
def save(self):
"""Save whatever the module may need to save. Sync files, etc.

View File

@ -44,7 +44,7 @@ class Countdown(Module):
self.config.set(self.__class__.__name__, item, target.astimezone(tzutc()).isoformat())
replystr = 'added countdown item ' + item
return replystr
return self.reply(connection, event, replystr)
match = re.search('^!countdown\s+remove\s+(\S+)$', what)
if match:
@ -52,7 +52,7 @@ class Countdown(Module):
item = match.group(1)
if self.config.remove_option(self.__class__.__name__, item):
replystr = 'removed countdown item ' + item
return replystr
return self.reply(connection, event, replystr)
except NoSectionError: pass
match = re.search('^!countdown\s+list$', what)
@ -62,7 +62,7 @@ class Countdown(Module):
self.remove_metaoptions(cdlist)
cdlist.sort()
liststr = ', '.join(cdlist)
return liststr
return self.reply(connection, event, liststr)
except NoSectionError: pass
match = re.search('^!countdown\s+(\S+)$', what)
@ -103,7 +103,7 @@ class Countdown(Module):
if rdelta.seconds > 1:
relstr += 's'
relstr += ', '
return relstr[0:-2]
return self.reply(connection, event, relstr[0:-2])
except NoOptionError: pass
# vi:tabstop=4:expandtab:autoindent

View File

@ -268,7 +268,7 @@ class Dice(Module):
yacc.parse(dicestr)
reply = self.get_result()
if reply is not "":
return nick + ': ' + reply
return self.reply(connection, event, nick + ': ' + reply)
match = re.search('^!ctech\s+(.*)$', what)
if match:
@ -373,7 +373,7 @@ class Dice(Module):
if count is not len(rollitrs)-1:
reply += "; "
if reply is not "":
return nick + ': ' + reply
return self.reply(connection, event, nick + ': ' + reply)
# vi:tabstop=4:expandtab:autoindent
# kate: indent-mode python;indent-width 4;replace-tabs on;

View File

@ -31,7 +31,7 @@ class Echo(Module):
match = re.search('^!echo\s+(.*)$', what)
if match:
return match.group(1)
return self.reply(connection, event, match.group(1))
# vi:tabstop=4:expandtab:autoindent
# kate: indent-mode python;indent-width 4;replace-tabs on;

View File

@ -63,7 +63,7 @@ class EightBall(Module):
match = re.search('^!8ball', what)
if match:
response = self.responses[random.randint(1,len(self.responses))-1]
return response
return self.reply(connection, event, response)
# vi:tabstop=4:expandtab:autoindent
# kate: indent-mode python;indent-width 4;replace-tabs on;

View File

@ -53,7 +53,7 @@ class FactFile(Module):
to_print = facts[random.randint(1, len(facts))-1]
# return text
return to_print.rstrip()
return self.reply(connection, event, to_print.rstrip())
else:
print('filename in config file for \'' + whats[0] + '\' is wrong')

View File

@ -70,7 +70,7 @@ class Facts(Module):
cur.execute('''INSERT INTO facts_facts (category, fact, who, userhost)
VALUES (?, ?, ?, ?)''', (category, fact, nick, userhost))
db.commit()
return category + ' added.'
return self.reply(connection, event, category + ' added.')
match = re.search('^!facts\s+(\S+)\s+(.*)$', what)
if match:
@ -80,7 +80,7 @@ class Facts(Module):
facts = category_facts.fetchall()
if len(facts) > 0:
fact = facts[random.randint(1,len(facts))-1]
return fact['fact'].rstrip().encode('utf-8', 'ignore')
return self.reply(connection, event, fact['fact'].rstrip().encode('utf-8', 'ignore'))
match = re.search('^!facts\s+(\S+)$', what)
if match:
@ -89,10 +89,10 @@ class Facts(Module):
facts = category_facts.fetchall()
if len(facts) > 0:
fact = facts[random.randint(1,len(facts))-1]
return fact['fact'].rstrip().encode('utf-8', 'ignore')
return self.reply(connection, event, fact['fact'].rstrip().encode('utf-8', 'ignore'))
except sqlite3.Error as e:
return "sqlite error: " + str(e)
return self.reply(connection, event, "sqlite error: " + str(e))
# vi:tabstop=4:expandtab:autoindent
# kate: indent-mode python;indent-width 4;replace-tabs on;

View File

@ -61,7 +61,7 @@ class GoogleTranslate(Module):
translation = translation.replace('\\u0026gt;', '>')
translation = translation.replace('\\u0026#39;', '\'')
return translation
return self.reply(connection, event, translation)
# vi:tabstop=4:expandtab:autoindent
# kate: indent-mode python;indent-width 4;replace-tabs on;

View File

@ -43,11 +43,11 @@ class Help(Module):
if match:
(module, key) = match.group(2,4)
if (module == None):
return self.handle_help_descriptions()
return self.reply(connection, event, self.handle_help_descriptions())
elif (key == None):
return self.handle_help_module(module)
return self.reply(connection, event, self.handle_help_module(module))
else:
return self.handle_help_detail(module, key)
return self.reply(connection, event, self.handle_help_detail(module, key))
def handle_help_descriptions(self):
"""print the general help"""

View File

@ -28,10 +28,14 @@ class IrcAdmin(Module):
"""Support miscellaneous IRC stuff --- joining channels, changing the nick, etc."""
def register_handlers(self, server):
server.add_global_handler('welcome', self.on_connect, self.priority())
def register_handlers(self):
self.server.add_global_handler('pubmsg', self.on_pub_or_privmsg, self.priority())
self.server.add_global_handler('privmsg', self.on_pub_or_privmsg, self.priority())
self.server.add_global_handler('welcome', self.on_connect, self.priority())
def unregister_handlers(self):
self.server.remove_global_handler('pubmsg', self.on_pub_or_privmsg)
self.server.remove_global_handler('privmsg', self.on_pub_or_privmsg)
self.server.remove_global_handler('welcome', self.on_connect)
def on_connect(self, connection, event):
@ -60,27 +64,27 @@ class IrcAdmin(Module):
whats = what.split(' ')
if whats[0] == '!join' and admin_unlocked and len(whats) >= 2:
return self.sub_join_channel(connection, event, nick, userhost, what, admin_unlocked)
return self.reply(connection, event, self.sub_join_channel(connection, event, nick, userhost, what, admin_unlocked))
elif whats[0] == '!part' and admin_unlocked and len(whats) >= 2:
return self.sub_part_channel(connection, event, nick, userhost, what, admin_unlocked)
return self.reply(connection, event, self.sub_part_channel(connection, event, nick, userhost, what, admin_unlocked))
elif whats[0] == '!quit' and admin_unlocked:
return self.sub_quit_irc(connection, event, nick, userhost, what, admin_unlocked)
return self.reply(connection, event, self.sub_quit_irc(connection, event, nick, userhost, what, admin_unlocked))
elif whats[0] == '!autojoin' and admin_unlocked and len(whats) >= 3:
return self.sub_autojoin_manipulate(connection, event, nick, userhost, what, admin_unlocked)
return self.reply(connection, event, self.sub_autojoin_manipulate(connection, event, nick, userhost, what, admin_unlocked))
elif whats[0] == '!save' and admin_unlocked:
self.irc.save_modules()
self.irc.save_config()
return 'Saved.'
return self.reply(connection, event, 'Saved.')
elif whats[0] == '!nick' and admin_unlocked and len(whats) >= 2:
return self.sub_change_nick(connection, event, nick, userhost, what, admin_unlocked)
return self.reply(connection, event, self.sub_change_nick(connection, event, nick, userhost, what, admin_unlocked))
elif whats[0] == '!load' and admin_unlocked and len(whats) >= 2:
return self.sub_load_module(connection, event, nick, userhost, what, admin_unlocked)
return self.reply(connection, event, self.sub_load_module(connection, event, nick, userhost, what, admin_unlocked))
elif whats[0] == '!reload' and admin_unlocked and len(whats) >= 2:
return self.sub_reload_module(connection, event, nick, userhost, what, admin_unlocked)
return self.reply(connection, event, self.sub_reload_module(connection, event, nick, userhost, what, admin_unlocked))
elif whats[0] == '!unload' and admin_unlocked and len(whats) >= 2:
return self.sub_unload_module(connection, event, nick, userhost, what, admin_unlocked)
return self.reply(connection, event, self.sub_unload_module(connection, event, nick, userhost, what, admin_unlocked))
elif whats[0] == '!modules':
return self.sub_list_modules(connection, event, nick, userhost, what, admin_unlocked)
return self.reply(connection, event, self.sub_list_modules(connection, event, nick, userhost, what, admin_unlocked))
def sub_join_channel(self, connection, event, nick, userhost, what, admin_unlocked):
whats = what.split(' ')

View File

@ -98,13 +98,13 @@ class Karma(Module):
"""look for karma strings at the start of messages"""
if (self.karmare.search(what)):
return self.handle_karma_change(connection, nick, userhost, what)
return self.reply(connection, event, self.handle_karma_change(connection, nick, userhost, what))
elif (self.queryre.search(what)):
return self.handle_karma_query(connection, nick, userhost, what)
return self.reply(connection, event, self.handle_karma_query(connection, nick, userhost, what))
elif (self.statre.search(what)):
return self.handle_stat_query(connection, nick, userhost, what)
return self.reply(connection, event, self.handle_stat_query(connection, nick, userhost, what))
elif (self.reportre.search(what)):
return self.handle_report_query(connection, nick, userhost, what)
return self.reply(connection, event, self.handle_report_query(connection, nick, userhost, what))
def handle_karma_change(self, connection, nick, userhost, what):
"""

View File

@ -68,13 +68,17 @@ class Markov(Module):
self.brain = {}
self.brain.setdefault((self.start1, self.start2), []).append(self.stop)
def register_handlers(self, server):
def register_handlers(self):
"""Handle pubmsg/privmsg, to learn and/or reply to IRC events."""
self.server.add_global_handler('pubmsg', self.on_pub_or_privmsg, self.priority())
self.server.add_global_handler('privmsg', self.on_pub_or_privmsg, self.priority())
self.server.add_global_handler('pubmsg', self.learn_from_irc_event)
self.server.add_global_handler('privmsg', self.learn_from_irc_event)
def unregister_handlers(self):
self.server.remove_global_handler('pubmsg', self.on_pub_or_privmsg)
self.server.remove_global_handler('privmsg', self.on_pub_or_privmsg)
self.server.remove_global_handler('pubmsg', self.learn_from_irc_event)
self.server.remove_global_handler('privmsg', self.learn_from_irc_event)
@ -100,11 +104,11 @@ class Markov(Module):
"""Handle commands and inputs."""
if self.trainre.search(what):
return self.markov_train(connection, event, nick, userhost, what, admin_unlocked)
return self.reply(connection, event, self.markov_train(connection, event, nick, userhost, what, admin_unlocked))
elif self.learnre.search(what):
return self.markov_learn(connection, event, nick, userhost, what, admin_unlocked)
return self.reply(connection, event, self.markov_learn(connection, event, nick, userhost, what, admin_unlocked))
elif self.replyre.search(what):
return self.markov_reply(connection, event, nick, userhost, what, admin_unlocked)
return self.reply(connection, event, self.markov_reply(connection, event, nick, userhost, what, admin_unlocked))
# not a command, so see if i'm being mentioned
if re.search(connection.get_nickname(), what, re.IGNORECASE) is not None:
@ -112,10 +116,10 @@ class Markov(Module):
addressed_re = re.compile(addressed_pattern)
if addressed_re.match(what):
# i was addressed directly, so respond, addressing the speaker
return '{0:s}: {1:s}'.format(nick, self._reply_to_line(addressed_re.match(what).group(1)))
return self.reply(connection, event, '{0:s}: {1:s}'.format(nick, self._reply_to_line(addressed_re.match(what).group(1))))
else:
# i wasn't addressed directly, so just respond
return '{0:s}'.format(self._reply_to_line(what))
return self.reply(connection, event, '{0:s}'.format(self._reply_to_line(what)))
def markov_train(self, connection, event, nick, userhost, what, admin_unlocked):
"""Learn lines from a file. Good for initializing a brain."""

View File

@ -39,13 +39,17 @@ class MegaHAL(Module):
mh_python.initbrain()
def register_handlers(self, server):
def register_handlers(self):
"""Handle pubmsg/privmsg, so we can learn only from IRC events."""
self.server.add_global_handler('pubmsg', self.on_pub_or_privmsg, self.priority())
self.server.add_global_handler('privmsg', self.on_pub_or_privmsg, self.priority())
self.server.add_global_handler('pubmsg', self.learn_from_irc_event)
self.server.add_global_handler('privmsg', self.learn_from_irc_event)
def unregister_handlers(self):
self.server.remove_global_handler('pubmsg', self.on_pub_or_privmsg)
self.server.remove_global_handler('privmsg', self.on_pub_or_privmsg)
self.server.remove_global_handler('pubmsg', self.learn_from_irc_event)
self.server.remove_global_handler('privmsg', self.learn_from_irc_event)
@ -81,7 +85,7 @@ class MegaHAL(Module):
if reply is not "":
if append_nick:
reply = nick + ": " + reply
return reply
return self.reply(connection, event, reply)
# vi:tabstop=4:expandtab:autoindent
# kate: indent-mode python;indent-width 4;replace-tabs on;

View File

@ -98,9 +98,9 @@ class Pi(Module):
db.commit()
except sqlite3.Error as e:
db.rollback()
return "sqlite error: " + str(e)
return self.reply(connection, event, "sqlite error: " + str(e))
return "({0:.10f}, {1:.10f}) is {2}within the circle. pi is {5:.10f}. (i:{3:d} p:{4:d})".format(x, y, "" if inside else "not ", count_inside, count, pi)
return self.reply(connection, event, "({0:.10f}, {1:.10f}) is {2}within the circle. pi is {5:.10f}. (i:{3:d} p:{4:d})".format(x, y, "" if inside else "not ", count_inside, count, pi))
# vi:tabstop=4:expandtab:autoindent
# kate: indent-mode python;indent-width 4;replace-tabs on;

View File

@ -44,7 +44,7 @@ class Seen(Module):
seendata = self.config.get(self.__class__.__name__, query).split('|:|')
converted = datetime.strptime(seendata[1], "%Y-%m-%dT%H:%M:%S.%f").replace(tzinfo=tzutc())
replystr = 'last saw ' + query + ' at ' + converted.astimezone(tzlocal()).strftime("%Y/%m/%d %H:%M:%S %Z") + ' saying \'' + seendata[2] + '\''
return replystr
return self.reply(connection, event, replystr)
except NoOptionError: pass
# vi:tabstop=4:expandtab:autoindent

View File

@ -162,21 +162,21 @@ class Storycraft(Module):
"""Pass storycraft control commands to the appropriate method based on input."""
if self.statusre.search(what):
return self.storycraft_status(connection, event, nick, userhost, what, admin_unlocked)
return self.reply(connection, event, self.storycraft_status(connection, event, nick, userhost, what, admin_unlocked))
elif self.newgamere.search(what):
return self.storycraft_newgame(connection, event, nick, userhost, what, admin_unlocked)
return self.reply(connection, event, self.storycraft_newgame(connection, event, nick, userhost, what, admin_unlocked))
elif self.joingamere.search(what):
return self.storycraft_joingame(connection, event, nick, userhost, what, admin_unlocked)
return self.reply(connection, event, self.storycraft_joingame(connection, event, nick, userhost, what, admin_unlocked))
elif self.listgamesre.search(what):
return self.storycraft_listgames(connection, event, nick, userhost, what, admin_unlocked)
return self.reply(connection, event, self.storycraft_listgames(connection, event, nick, userhost, what, admin_unlocked))
elif self.startgamere.search(what):
return self.storycraft_startgame(connection, event, nick, userhost, what, admin_unlocked)
return self.reply(connection, event, self.storycraft_startgame(connection, event, nick, userhost, what, admin_unlocked))
elif self.showlinere.search(what):
return self.storycraft_showline(connection, event, nick, userhost, what, admin_unlocked)
return self.reply(connection, event, self.storycraft_showline(connection, event, nick, userhost, what, admin_unlocked))
elif self.addlinere.search(what):
return self.storycraft_addline(connection, event, nick, userhost, what, admin_unlocked)
return self.reply(connection, event, self.storycraft_addline(connection, event, nick, userhost, what, admin_unlocked))
elif self.exportre.search(what):
return self.storycraft_export(connection, event, nick, userhost, what, admin_unlocked)
return self.reply(connection, event, self.storycraft_export(connection, event, nick, userhost, what, admin_unlocked))
def storycraft_status(self, connection, event, nick, userhost, what, admin_unlocked):
"""Print information about the storycraft games, or one specific game."""

View File

@ -37,11 +37,11 @@ class TextTransform(Module):
reply = ['']
if self.rot13(what, reply):
return reply[0]
return self.reply(connection, event, reply[0])
elif self.base64(what, reply):
return reply[0]
return self.reply(connection, event, reply[0])
elif self.upper(what, reply):
return reply[0]
return self.reply(connection, event, reply[0])
def rot13(self, what, reply):
"""

View File

@ -36,7 +36,7 @@ class Trigger(Module):
for trigger in trigger_list:
if re.search(trigger, what) is not None:
output = self.config.get(self.__class__.__name__, trigger)
return output
return self.reply(connection, event, output)
except NoOptionError: pass
except NoSectionError: pass

View File

@ -99,17 +99,17 @@ class Twitter(Module):
"""Attempt to do twitter things."""
if self.getstatusre.search(what):
return self.twitter_getstatus(connection, event, nick, userhost, what, admin_unlocked)
return self.reply(connection, event, self.twitter_getstatus(connection, event, nick, userhost, what, admin_unlocked))
elif self.getuserstatusre.search(what):
return self.twitter_getuserstatus(connection, event, nick, userhost, what, admin_unlocked)
return self.reply(connection, event, self.twitter_getuserstatus(connection, event, nick, userhost, what, admin_unlocked))
elif self.tweetre.search(what):
return self.twitter_tweet(connection, event, nick, userhost, what, admin_unlocked)
return self.reply(connection, event, self.twitter_tweet(connection, event, nick, userhost, what, admin_unlocked))
elif self.replytore.search(what):
return self.twitter_replyto(connection, event, nick, userhost, what, admin_unlocked)
return self.reply(connection, event, self.twitter_replyto(connection, event, nick, userhost, what, admin_unlocked))
elif self.gettokenre.search(what):
return self.twitter_gettoken(connection, event, nick, userhost, what, admin_unlocked)
return self.reply(connection, event, self.twitter_gettoken(connection, event, nick, userhost, what, admin_unlocked))
elif self.authre.search(what):
return self.twitter_auth(connection, event, nick, userhost, what, admin_unlocked)
return self.reply(connection, event, self.twitter_auth(connection, event, nick, userhost, what, admin_unlocked))
def twitter_getstatus(self, connection, event, nick, userhost, what, admin_unlocked):
"""Get a status by tweet ID."""

View File

@ -45,7 +45,7 @@ class Urls(Module):
urlstr = ' '.join(whats[2:]) + "\n"
file.write(urlstr)
return 'added url'
return self.reply(connection, event, 'added url')
# default: get a random url
@ -64,7 +64,7 @@ class Urls(Module):
to_print = urls[random.randint(1, len(urls))-1]
# return text
return to_print.rstrip()
return self.reply(connection, event, to_print.rstrip())
else:
print('filename in config file for urls is wrong')
except NoOptionError: pass

View File

@ -62,11 +62,11 @@ class Weather(Module):
for city in google_weather['forecasts']:
weatherstr += " " + city['day_of_week'].encode('utf-8') + ": " + city['condition'].encode('utf-8') + ". High " + city['high'].encode('utf-8') + "°F, Low " + city['low'].encode('utf-8') + "°F."
return weatherstr
return self.reply(connection, event, weatherstr)
except URLError as e:
return "error connecting to google weather:" + str(e)
return self.reply(connection, event, "error connecting to google weather:" + str(e))
except IndexError as e:
return "error in pywapi: " + str(e)
return self.reply(connection, event, "error in pywapi: " + str(e))
# vi:tabstop=4:expandtab:autoindent
# kate: indent-mode python;indent-width 4;replace-tabs on;