diff --git a/Module.py b/Module.py index f26b84a..4316b8b 100644 --- a/Module.py +++ b/Module.py @@ -1,18 +1,20 @@ -# Module - dr.botzo modular functionality base class -# Copyright (C) 2010 Brian S. Stephan -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +""" +Module - dr.botzo modular functionality base class +Copyright (C) 2010 Brian S. Stephan + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +""" import inspect import re @@ -20,20 +22,21 @@ import sys from irclib import irclib -# Base class used for creating classes that have real functionality. - class Module(object): - - # Constructor for a feature module. Inheritors should not do anything special - # here, instead they should implement register_handlers and do, or else this will - # be a very uneventful affair. - # - # Classes that are interested in allowing an indirect call to their do routine - # should add themselves to modlist inside their __init__. This will allow other - # modules to call do and see if anything can handle text they may have seen (such - # as in recursive commands). + """Declare a base class used for creating classes that have real functionality.""" def __init__(self, config, server, modlist): + """ + Construct a feature module. Inheritors should not do anything special + here, instead they should implement register_handlers and do, or else this will + be a very uneventful affair. + + Classes that are interested in allowing an indirect call to their do routine + should add themselves to modlist inside their __init__. This will allow other + modules to call do and see if anything can handle text they may have seen (such + as in recursive commands). + """ + self.config = config self.server = server self.modlist = modlist @@ -45,32 +48,41 @@ class Module(object): # print what was loaded, for debugging print("loaded " + self.__class__.__name__) - # This is called by __init__ and sets up server.add_global_handlers. Classes - # inheriting from Module should implement this and set up the appropriate handlers, - # e.g.: - # - # server.add_global_handler('privmsg', self.on_privmsg) - # - # Module.on_pubmsg and Module.on_privmsg are defined so far, the rest, you're on your - # own. - def register_handlers(self, server): + """ + Hook handler functions into the IRC library. This is called by __init__ and sets + up server.add_global_handlers. Classes inheriting from Module should implement this + and set up the appropriate handlers, e.g.: + + server.add_global_handler('privmsg', self.on_privmsg) + + Module.on_pubmsg and Module.on_privmsg are defined so far, the rest, you're on your + own. + """ + 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): + """ + 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 should implement this, e.g.: + + server.remove_global_handler('privmsg', self.on_privmsg) + """ + 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. - def on_pubmsg(self, connection, event): + """ + Handle pubmsg events. 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. + """ + nick = irclib.nm_to_n(event.source()) userhost = irclib.nm_to_uh(event.source()) replypath = event.target() @@ -100,11 +112,15 @@ class Module(object): self.do(connection, event, nick, userhost, replypath, what, admin_unlocked) - # 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_privmsg on your own too. - def on_privmsg(self, connection, event): + """ + Handle privmsg events. 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_privmsg on your own too. + """ + nick = irclib.nm_to_n(event.source()) userhost = irclib.nm_to_uh(event.source()) replypath = nick @@ -122,9 +138,9 @@ 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): + """Reload this module's code and then create a new object of it, removing the old.""" + whats = what.split(' ') if whats[0] == 'reload' and admin_unlocked: # re-read and re-compile module from source on disk @@ -140,29 +156,35 @@ class Module(object): # create new object, like how we did initially obj(self.config, self.server, self.modlist) - # Utility method to do the proper type of reply (either to IRC, or as a return - # to caller) depending on the target. Pretty simple, and included in the base - # class for convenience. It should be the last step for callers: - # - # return self.reply(connection, replypath, 'hello') - def reply(self, connection, replypath, replystr): + """ + Reply over IRC to replypath or return a string with the reply. + Utility method to do the proper type of reply (either to IRC, or as a return + to caller) depending on the target. Pretty simple, and included in the base + class for convenience. It should be the last step for callers: + + return self.reply(connection, replypath, 'hello') + """ + if replypath is None: return replystr else: connection.privmsg(replypath, replystr) - # 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: - # - # command arg1 [anothercommand arg1 arg2] - # - # where the output of anothercommand is command's arg2..n. It's mostly for - # amusement purposes, but maybe there are legitimate uses. This is intended to - # be attempted after you've determined the line should be handled by your module. - def try_recursion(self, connection, event, nick, userhost, replypath, what, admin_unlocked): + """ + 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 + that we should do what is basically a text replacement on. The intent is to + allow things like the following: + + command arg1 [anothercommand arg1 arg2] + + where the output of anothercommand is command's arg2..n. It's mostly for + amusement purposes, but maybe there are legitimate uses. This is intended to + be attempted after you've determined the line should be handled by your module. + """ + start_idx = what.find('[') subcmd = what[start_idx+1:] end_idx = subcmd.rfind(']') @@ -195,10 +217,13 @@ class Module(object): else: return attempt - # Implement this method in your subclass to have a fairly-automatic hook into - # IRC functionality. This is called by the default on_pubmsg and on_privmsg - def do(self, connection, event, nick, userhost, replypath, what, admin_unlocked): + """ + Do the primary thing this module was intended to do. + Implement this method in your subclass to have a fairly-automatic hook into + IRC functionality. This is called by the default on_pubmsg and on_privmsg + """ + print "looks like someone forgot to implement do!" # vi:tabstop=4:expandtab:autoindent diff --git a/dr.botzo.py b/dr.botzo.py index 88aa853..899187a 100644 --- a/dr.botzo.py +++ b/dr.botzo.py @@ -1,18 +1,20 @@ -# dr.botzo - a pluggable IRC bot written in Python -# Copyright (C) 2010 Brian S. Stephan -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +""" +dr.botzo - a pluggable IRC bot written in Python +Copyright (C) 2010 Brian S. Stephan + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +""" from ConfigParser import ConfigParser, NoSectionError, NoOptionError import os @@ -28,13 +30,11 @@ modlist = [] moduleList = [ "Countdown", "Dice", "IrcAdmin", "GoogleTranslate", "Seen", "FactFile" ] modObjs = [] -# DrBotServerConnection subclasses irclib's ServerConnection, in order to expand -# privmsg. - class DrBotServerConnection(irclib.ServerConnection): + """Subclass irclib's ServerConnection, in order to expand privmsg.""" def privmsg(self, target, text): - # Send a PRIVMSG command. + """Send a PRIVMSG command.""" splitter = "..." # split messages that are too long. Max length is 512. @@ -55,9 +55,8 @@ class DrBotServerConnection(irclib.ServerConnection): else: self.send_raw("PRIVMSG %s :%s" % (target, text)) -# DrBotIRC subclasses irclib's IRC, in order to create a DrBotServerConnection. - class DrBotIRC(irclib.IRC): + """Subclass irclib's IRC, in order to create a DrBotServerConnection.""" def server(self): c = DrBotServerConnection(self)