From a440bf395cedc38a542c31868a8ba8441a9cafdc Mon Sep 17 00:00:00 2001 From: "Brian S. Stephan" Date: Wed, 19 Dec 2012 19:53:41 -0600 Subject: [PATCH] Module: documentation and whitespace cleanups i've marked some stuff as deprecated, and there's even more of that kind of thing coming up within the next dozen or so commits --- Module.py | 249 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 192 insertions(+), 57 deletions(-) diff --git a/Module.py b/Module.py index 6aed549..20a8ad8 100644 --- a/Module.py +++ b/Module.py @@ -14,6 +14,7 @@ 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 NoSectionError, NoOptionError @@ -28,21 +29,30 @@ import MySQLdb as mdb from extlib import irclib class Module(object): - """Declare a base class used for creating classes that have real functionality.""" + + """Provide module base class with convenience functionality/bootstrap.""" def priority(self): return 50 def __init__(self, irc, config, server): - """Construct a feature module. Inheritors can do special things here, but - should be sure to call Module.__init__. + """Construct a feature module. + + Inheritors can do special things here, but should be sure to call + Module.__init__. + + Args: + irc DrBotIRC object for the running bot + config ConfigParser object, the entire config file + server DrBotServerConnection object + """ self.irc = irc self.config = config self.server = server - # reload file config every time + # reload logging config every time logging.config.fileConfig('logging.cfg') self.log = logging.getLogger('drbotzo.'+self.__class__.__name__.lower()) @@ -51,31 +61,37 @@ class Module(object): # set up database for this module self.db_init() - # print what was loaded, for debugging self.log.info("Loaded " + self.__class__.__name__) 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.: + """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) - 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. + 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()) + 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 unload, 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 reimplement this, e.g.: + """Unhook handler functions from the IRC library. + + Inverse of the above. This is called by unload, 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 reimplement this, e.g.: self.server.remove_global_handler('welcome', self.on_connect) + """ self.server.remove_global_handler('pubmsg', self.on_pub_or_privmsg) @@ -86,6 +102,14 @@ class Module(object): Sets up a couple variables and then calls do(), which by default we expect implementers to implement. + + Args: + connection the source connection for this event + event the event to handle + + Returns: + The results of handling the event. + """ nick = irclib.nm_to_n(event.source()) @@ -100,16 +124,28 @@ class Module(object): return self.do(connection, event, nick, userhost, what, admin_unlocked) - def reply(self, connection, event, replystr, stop_responding=False): + def reply(self, connection, event, replystr, stop=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. + 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. + + Args: + connection source connection + event incoming event + replystr the message to reply with + stop whether or not to let other handlers see this + + Returns: + The replystr if the event is inside recursion, or, potentially, + "NO MORE" to stop other event handlers from acting. + """ replypath = event.target() @@ -125,11 +161,18 @@ class Module(object): replies = replystr.split('\n') for reply in replies: connection.privmsg(replypath, reply) - if stop_responding: + if stop: return "NO MORE" def sendmsg(self, connection, target, msg): - """Send a privmsg over IRC to target.""" + """Send a privmsg over IRC to target. + + Args: + connection server connection to send the message to + target destination on the network + msg the message to send + + """ if msg is not None: if target is not None: @@ -141,42 +184,65 @@ class Module(object): """Save whatever the module may need to save. Sync files, etc. Implement this if you need it. + """ + pass + def shutdown(self): """Do pre-deletion type cleanup. - Implement this to close databases, write to disk, etc. Note that DrBotIRC - will call save() before this, so implement appropriately. + Implement this to close databases, write to disk, etc. Note that + DrBotIRC will call save() before this, so implement appropriately. + """ self.is_shutdown = True self.log.info("Unloading " + self.__class__.__name__) - def remove_metaoptions(self, list): - """Remove metaoptions from provided list, which was probably from a config file.""" + def remove_metaoptions(self, list_): + """Remove metaoptions from provided list, which was probably from a + config file. - list.remove('debug') + DEPRECATED + + This is a convenience method that can go away once we get module stuff + out of the config file and into the database. + + Args: + list_ the list to prune known keywords from + + """ + + list_.remove('debug') def retransmit_event(self, event): - """ - Pretend that some event the bot has generated is rather an incoming IRC - event. Why one would do this is unclear, but I wrote it and then realized + """Pretend that some event the bot has generated is rather an incoming + IRC event. + + DEPRECATED + + Why one would do this is unclear, but I wrote it and then realized I didn't need it. + + Args: + event the event to replay + """ self.server._handle_event(event) def get_db(self): - """ - Get a database connection to mdb. Once grabbed, it should be closed - when work is done. Modules that need a database connection should - test for and create (or, eventually, alter) required table structure - in their __init__ IF that structure does not already exist. Well-behaved - modules should use a prefix in their table names (eg "karma_log" rather - than "log") + """Get a database connection to mdb. + + Once grabbed, it should be closed when work is done. Modules that + need a database connection should test for and create (or, eventually, + alter) required table structure in their __init__ IF that structure + does not already exist. Well-behaved modules should use a prefix in + their table names (eg "karma_log" rather than "log") See also db_module_registered, below. + """ dbhost = self.config.get('dr.botzo', 'dbhost') @@ -188,9 +254,17 @@ class Module(object): return db def db_module_registered(self, modulename): - """ - ask the database for a version number for a module. Return that version - number if the module has registered, or None if not + """Ask the database for a version number for a module. + + Return that version number if the module has registered, or None if + not. + + Args: + modulename the name of the module to check + + Returns: + The version number stored for the module in the database, as a int + """ db = self.get_db() @@ -211,7 +285,16 @@ class Module(object): return version def db_register_module_version(self, modulename, version): - """Enter the given module name and version number into the database.""" + """Enter the given module name and version number into the database. + + The primary want for this is to record what the current revision the + tables are, to do upgrades. + + Args: + modulename the name of the module to update + version the version number to set as a int + + """ db = self.get_db() try: @@ -227,40 +310,92 @@ class Module(object): finally: cur.close() def db_init(self): - """ - Set up the database tables and so on, if subclass is planning on using it. + """Set up the database tables and so on. + + Modules interested in this should implement table setup here. + """ - def do(self, connection, event, nick, userhost, what, admin_unlocked): + pass + + def do(self, connection, event, nick, userhost, what, admin): """Do the primary thing this module was intended to do, in most cases. - Implement this method in your subclass to have a fairly-automatic hook into - IRC functionality. This is called by DrBotIRC during pubmsg and privmsg - events. + Implement this method in your subclass to have a fairly-automatic hook + into IRC functionality. This is called by DrBotIRC during pubmsg and + privmsg events. + + Args: + connection the connection instance to handle + event the event to handle + nick the nick of the originator of the event + userhost the userhost of the originator of the event + what the message body of the event + admin if the event was created by an admin + """ - self.log.error("looks like someone forgot to implement do!") + pass def help_description(self): - """Return a quick list of commands or other summary, should be - less than two lines. If you want the module hidden from "!help", - return None here""" + """Return a quick list of commands or other summary. + + DEPRECATED + + Should be less than two lines. If you want the module hidden from + "!help", return None here + + Returns: + The documentation for the module. + + """ + return "No description available" def help_summary(self): """Return a command summary or longer description of this module. - If this returns None, the summary will be - "no help available for module foo" + + DEPRECATED + + If this returns None, the summary will be "no help available for + module foo" + + Returns: + The documentation for the module. + """ + return None def help_detail(self, command): - """Return detailed help for the given command. Return None if there - is no suitable help available""" + """Return detailed help for the given command. + + DEPRECATED + + Return None if there is no suitable help available. + + Args: + command the command to provide documentation for + + Returns: + The documentation for the provided command. + + """ + return None def _unencode_xml(self, text): - """Convert <, >, & to their real entities.""" + """Convert <, >, & to their real entities. + + Convenience method for modules, I've been thinking about moving this. + + Args: + text the text to clean up + + Returns: + The provided text string, with the known entities replaced. + + """ text = text.replace('<', '<') text = text.replace('>', '>')