From 57090fdda4d5b976445d443336bef864ab4b3338 Mon Sep 17 00:00:00 2001 From: "Brian S. Stephan" Date: Thu, 29 Jul 2010 22:36:08 -0500 Subject: [PATCH] long list of changes to allow modular Module reloads: server as module variable, class appends self to module list, unregister_handlers method which must be overridden, reload method which does the magic to create the a new object of the re-read class. drop use of the main rehash and reload_modules, and don't pass rehash around anymore. load initial objects 'the old way' again. feature modules change for compatability and implementation of all of the above changes --- Module.py | 34 +++++++++++++++++++++--- dr.botzo.py | 53 +++++--------------------------------- modules/Countdown.py | 8 ++++-- modules/Dice.py | 8 ++++-- modules/FactFile.py | 8 ++++-- modules/GoogleTranslate.py | 8 ++++-- modules/IrcAdmin.py | 20 +++++--------- modules/Seen.py | 11 ++++++-- 8 files changed, 77 insertions(+), 73 deletions(-) diff --git a/Module.py b/Module.py index 07dead8..ef98c30 100644 --- a/Module.py +++ b/Module.py @@ -14,7 +14,9 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +import inspect import re +import sys from irclib import irclib @@ -31,12 +33,14 @@ class Module(object): # modules to call do and see if anything can handle text they may have seen (such # as in recursive commands). - def __init__(self, config, server, modlist, rehash): + def __init__(self, config, server, modlist): self.config = config + self.server = server self.modlist = modlist self.register_handlers(server) - # Should do some error handling here. - self.rehash = rehash # Is there another way to call the rehash function in dr.botzo? + + # add self to the object list + modlist.append(self) # print what was loaded, for debugging print("loaded " + self.__class__.__name__) @@ -53,6 +57,15 @@ class Module(object): def register_handlers(self, server): print "looks like someone forgot to implement register_handlers!" + # 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 should implement this, e.g.: + # + # server.remove_global_handler('privmsg', self.on_privmsg) + + def unregister_handlers(self): + print "looks like someone forgot to implement unregister_handlers!" + # Does some variable setup and initial sanity checking before calling Module.do, # which should be implemented by subclasses and what can be ultimately responsible # for the work. Of course, you are free to reimplement on_pubmsg on your own too. @@ -82,6 +95,9 @@ class Module(object): if replypath is not None: what = self.try_recursion(connection, event, nick, userhost, replypath, what, admin_unlocked) + # try reloading + self.reload(connection, event, nick, userhost, replypath, what, admin_unlocked) + self.do(connection, event, nick, userhost, replypath, what, admin_unlocked) # Does some variable setup and initial sanity checking before calling Module.do, @@ -106,6 +122,18 @@ class Module(object): self.do(connection, event, nick, userhost, replypath, what, admin_unlocked) + # If the command given was to reload, reload this module. + + def reload(self, connection, event, nick, userhost, replypath, what, admin_unlocked): + whats = what.split(' ') + if whats[0] == 'reload' and admin_unlocked: + reload(sys.modules[self.__module__]) + for name, obj in inspect.getmembers(sys.modules[self.__module__]): + if inspect.isclass(obj) and str(obj).find(self.__module__) > 0: + self.modlist.remove(self) + self.unregister_handlers() + obj(self.config, self.server, self.modlist) + # Upon seeing a line intended for this module, see if there are subcommands # that we should do what is basically a text replacement on. The intent is to # allow things like the following: diff --git a/dr.botzo.py b/dr.botzo.py index 77795d7..b61502e 100644 --- a/dr.botzo.py +++ b/dr.botzo.py @@ -39,45 +39,6 @@ class DrBotIRC(irclib.IRC): self.connections.append(c) return c -# This finds all the currently loaded modules that start with "modules" (as all -# the bot modules are currently in a subfolder called modules) and calls -# reload() on them. This will only work if the folder name doesn't change. - -def rehash(): - myre = re.compile('modules') - for i in sys.modules: - currMod = sys.modules[i] - if currMod is not None and myre.search(i): - reload(currMod) - - # Remove the pubmsg and privmsg handlers from the irclib object. - # If we don't do this we will see phantom messages - for obj in modObjs: - server.remove_global_handler('pubmsg', obj.on_pubmsg) - server.remove_global_handler('privmsg', obj.on_privmsg) - - reload_modules(moduleList) - -# Create the actual module objects, which will readd the handlers we removed -# earlier, and add them to the modObjs list, which we can use during the -# next rehash to remove the handlers. - -def reload_modules(moduleList): - for mod in moduleList: - cls = globals()[mod] - - # Importing the names imports a module since the file name and class - # name are the same. Look for the class definition in each module - # with the same name and create that object. - - if inspect.ismodule(cls): - for name, obj in inspect.getmembers(cls): - if inspect.isclass(obj) and re.search(mod, obj.__name__): - modObjs.append(obj(config, server, modlist, rehash)) - break - else: - modObjs.append(cls(config, server, modlist, rehash)) - # read config file config = ConfigParser({'debug': 'false'}) @@ -104,14 +65,12 @@ irclib.DEBUG = config.getboolean('IRC', 'debug') irc = DrBotIRC() server = irc.server().connect(botserver, botport, botnick, botircname) -reload_modules(moduleList) - -#count = Countdown(config, server, modlist) -#dice = Dice(config, server, modlist) -#fact = FactFile(config, server, modlist) -#admin = IrcAdmin(config, server, modlist) -#gt = GoogleTranslate(config, server, modlist) -#seen = Seen(config, server, modlist) +count = Countdown.Countdown(config, server, modlist) +dice = Dice.Dice(config, server, modlist) +fact = FactFile.FactFile(config, server, modlist) +admin = IrcAdmin.IrcAdmin(config, server, modlist) +gt = GoogleTranslate.GoogleTranslate(config, server, modlist) +seen = Seen.Seen(config, server, modlist) # loop forever irc.process_forever() diff --git a/modules/Countdown.py b/modules/Countdown.py index 02ac468..e01233d 100644 --- a/modules/Countdown.py +++ b/modules/Countdown.py @@ -24,14 +24,18 @@ from Module import Module class Countdown(Module): - def __init__(self, config, server, modlist, rehash): - super(Countdown, self).__init__(config, server, modlist, rehash) + def __init__(self, config, server, modlist): + super(Countdown, self).__init__(config, server, modlist) modlist.append(self) def register_handlers(self, server): server.add_global_handler('pubmsg', self.on_pubmsg) server.add_global_handler('privmsg', self.on_privmsg) + def unregister_handlers(self): + self.server.remove_global_handler('pubmsg', self.on_pubmsg) + self.server.remove_global_handler('privmsg', self.on_privmsg) + def do(self, connection, event, nick, userhost, replypath, what, admin_unlocked): whats = what.split(' ') if whats[0] == 'countdown' and len(whats) >= 2: diff --git a/modules/Dice.py b/modules/Dice.py index b872987..13de5de 100644 --- a/modules/Dice.py +++ b/modules/Dice.py @@ -25,14 +25,18 @@ from Module import Module class Dice(Module): - def __init__(self, config, server, modlist, rehash): - super(Dice, self).__init__(config, server, modlist, rehash) + def __init__(self, config, server, modlist): + super(Dice, self).__init__(config, server, modlist) modlist.append(self) def register_handlers(self, server): server.add_global_handler('pubmsg', self.on_pubmsg) server.add_global_handler('privmsg', self.on_privmsg) + def unregister_handlers(self): + self.server.remove_global_handler('pubmsg', self.on_pubmsg) + self.server.remove_global_handler('privmsg', self.on_privmsg) + def do(self, connection, event, nick, userhost, replypath, what, admin_unlocked): overallroll = what diff --git a/modules/FactFile.py b/modules/FactFile.py index 2a4dedc..9bbcb35 100644 --- a/modules/FactFile.py +++ b/modules/FactFile.py @@ -26,14 +26,18 @@ from Module import Module class FactFile(Module): - def __init__(self, config, server, modlist, rehash): - super(FactFile, self).__init__(config, server, modlist, rehash) + def __init__(self, config, server, modlist): + super(FactFile, self).__init__(config, server, modlist) modlist.append(self) def register_handlers(self, server): server.add_global_handler('pubmsg', self.on_pubmsg) server.add_global_handler('privmsg', self.on_privmsg) + def unregister_handlers(self): + self.server.remove_global_handler('pubmsg', self.on_pubmsg) + self.server.remove_global_handler('privmsg', self.on_privmsg) + def do(self, connection, event, nick, userhost, replypath, what, admin_unlocked): whats = what.split(' ') try: diff --git a/modules/GoogleTranslate.py b/modules/GoogleTranslate.py index 64c6834..d62686c 100644 --- a/modules/GoogleTranslate.py +++ b/modules/GoogleTranslate.py @@ -27,14 +27,18 @@ from Module import Module class GoogleTranslate(Module): - def __init__(self, config, server, modlist, rehash): - super(GoogleTranslate, self).__init__(config, server, modlist, rehash) + def __init__(self, config, server, modlist): + super(GoogleTranslate, self).__init__(config, server, modlist) modlist.append(self) def register_handlers(self, server): server.add_global_handler('pubmsg', self.on_pubmsg) server.add_global_handler('privmsg', self.on_privmsg) + def unregister_handlers(self): + self.server.remove_global_handler('pubmsg', self.on_pubmsg) + self.server.remove_global_handler('privmsg', self.on_privmsg) + def do(self, connection, event, nick, userhost, replypath, what, admin_unlocked): whats = what.split(' ') if whats[0] == 'translate' and len(whats) >= 4: diff --git a/modules/IrcAdmin.py b/modules/IrcAdmin.py index 8c3e157..82ae5a5 100644 --- a/modules/IrcAdmin.py +++ b/modules/IrcAdmin.py @@ -24,8 +24,8 @@ from Module import Module class IrcAdmin(Module): - def __init__(self, config, server, modlist, rehash): - super(IrcAdmin, self).__init__(config, server, modlist, rehash) + def __init__(self, config, server, modlist): + super(IrcAdmin, self).__init__(config, server, modlist) modlist.append(self) def register_handlers(self, server): @@ -33,6 +33,11 @@ class IrcAdmin(Module): server.add_global_handler('pubmsg', self.on_pubmsg) server.add_global_handler('privmsg', self.on_privmsg) + def unregister_handlers(self): + self.server.remove_global_handler('welcome', self.on_connect) + self.server.remove_global_handler('pubmsg', self.on_pubmsg) + self.server.remove_global_handler('privmsg', self.on_privmsg) + def on_connect(self, connection, event): """handler for when the bot has connected to IRC """ @@ -62,17 +67,6 @@ class IrcAdmin(Module): self.sub_autojoin_manipulate(connection, event, nick, userhost, replypath, what, admin_unlocked) self.sub_save_config(connection, event, nick, userhost, replypath, what, admin_unlocked) self.sub_change_nick(connection, event, nick, userhost, replypath, what, admin_unlocked) - self.sub_rehash(connection, event, nick, userhost, replypath, what, admin_unlocked) - - def sub_rehash(self, connection, event, nick, userhost, replypath, what, admin_unlocked): - whats = what.split(' ') - if whats[0] == 'rehash' and admin_unlocked: - self.rehash() - replystr = 'rehashed modules' - if replypath is None: - return replystr - else: - connection.privmsg(replypath, replystr) def sub_join_channel(self, connection, event, nick, userhost, replypath, what, admin_unlocked): whats = what.split(' ') diff --git a/modules/Seen.py b/modules/Seen.py index a97cf31..bf517d8 100644 --- a/modules/Seen.py +++ b/modules/Seen.py @@ -28,14 +28,18 @@ from Module import Module class Seen(Module): - def __init__(self, config, server, modlist, rehash): - super(Seen, self).__init__(config, server, modlist, rehash) + def __init__(self, config, server, modlist): + super(Seen, self).__init__(config, server, modlist) modlist.append(self) def register_handlers(self, server): server.add_global_handler('pubmsg', self.on_pubmsg) server.add_global_handler('privmsg', self.on_privmsg) + def unregister_handlers(self): + self.server.remove_global_handler('pubmsg', self.on_pubmsg) + self.server.remove_global_handler('privmsg', self.on_privmsg) + # Overriding the default because we need stuff to occur before the addressed # and so on checks. @@ -70,6 +74,9 @@ class Seen(Module): if replypath is not None: what = self.try_recursion(connection, event, nick, userhost, replypath, what, admin_unlocked) + # try reloading + self.reload(connection, event, nick, userhost, replypath, what, admin_unlocked) + self.do(connection, event, nick, userhost, replypath, what, admin_unlocked) def do(self, connection, event, nick, userhost, replypath, what, admin_unlocked):