Moved loadPlugin{Module,Class} to its own module in src/

This commit is contained in:
Jeremy Fincher 2005-01-19 23:22:35 +00:00
parent 8d415d7631
commit 863c0e6ad2
3 changed files with 125 additions and 94 deletions

View File

@ -46,6 +46,7 @@ import supybot.world as world
import supybot.ircdb as ircdb import supybot.ircdb as ircdb
from supybot.commands import * from supybot.commands import *
import supybot.irclib as irclib import supybot.irclib as irclib
import supybot.plugin as plugin
import supybot.drivers as drivers import supybot.drivers as drivers
import supybot.ircmsgs as ircmsgs import supybot.ircmsgs as ircmsgs
import supybot.ircutils as ircutils import supybot.ircutils as ircutils
@ -54,82 +55,6 @@ import supybot.registry as registry
import supybot.callbacks as callbacks import supybot.callbacks as callbacks
import supybot.structures as structures import supybot.structures as structures
class Deprecated(ImportError):
pass
def loadPluginModule(name, ignoreDeprecation=False):
"""Loads (and returns) the module for the plugin with the given name."""
files = []
pluginDirs = conf.supybot.directories.plugins()
for dir in pluginDirs:
try:
files.extend(os.listdir(dir))
except EnvironmentError: # OSError, IOError superclass.
log.warning('Invalid plugin directory: %s; removing.',
utils.quoted(dir))
conf.supybot.directories.plugins().remove(dir)
loweredFiles = map(str.lower, files)
try:
index = loweredFiles.index(name.lower()+'.py')
name = os.path.splitext(files[index])[0]
if name in sys.modules:
m = sys.modules[name]
if not hasattr(m, 'Class'):
raise ImportError, 'Module is not a plugin.'
except ValueError: # We'd rather raise the ImportError, so we'll let go...
pass
moduleInfo = imp.find_module(name, pluginDirs)
try:
module = imp.load_module(name, *moduleInfo)
except:
sys.modules.pop(name, None)
raise
if 'deprecated' in module.__dict__ and module.deprecated:
if ignoreDeprecation:
log.warning('Deprecated plugin loaded: %s', name)
else:
raise Deprecated, 'Attempted to load deprecated plugin %s' % \
utils.quoted(name)
if module.__name__ in sys.modules:
sys.modules[module.__name__] = module
linecache.checkcache()
return module
def loadPluginClass(irc, module, register=None):
"""Loads the plugin Class from the given module into the given Irc."""
try:
cb = module.Class()
except AttributeError, e:
if 'Class' in str(e):
raise callbacks.Error, \
'This plugin module doesn\'t have a "Class" ' \
'attribute to specify which plugin should be ' \
'instantiated. If you didn\'t write this ' \
'plugin, but received it with Supybot, file ' \
'a bug with us about this error.'
else:
raise
plugin = cb.name()
public = True
if hasattr(cb, 'public'):
public = cb.public
conf.registerPlugin(plugin, register, public)
assert not irc.getCallback(plugin)
try:
renames = registerRename(plugin)()
if renames:
for command in renames:
v = registerRename(plugin, command)
newName = v()
assert newName
renameCommand(cb, command, newName)
else:
conf.supybot.commands.renames.unregister(plugin)
except registry.NonExistentRegistryEntry, e:
pass # The plugin isn't there.
irc.addCallback(cb)
return cb
### ###
# supybot.commands. # supybot.commands.
### ###
@ -302,8 +227,9 @@ class Owner(callbacks.Privmsg):
# This is debug because each log logs its beginning. # This is debug because each log logs its beginning.
self.log.debug('Loading %s.' % name) self.log.debug('Loading %s.' % name)
try: try:
m = loadPluginModule(name, ignoreDeprecation=True) m = plugin.loadPluginModule(name,
loadPluginClass(irc, m) ignoreDeprecation=True)
plugin.loadPluginClass(irc, m)
except callbacks.Error, e: except callbacks.Error, e:
# This is just an error message. # This is just an error message.
log.warning(str(e)) log.warning(str(e))
@ -314,7 +240,7 @@ class Owner(callbacks.Privmsg):
else: else:
# Let's import the module so configuration is preserved. # Let's import the module so configuration is preserved.
try: try:
_ = loadPluginModule(name) _ = plugin.loadPluginModule(name)
except Exception, e: except Exception, e:
log.debug('Attempted to load %s to preserve its ' log.debug('Attempted to load %s to preserve its '
'configuration, but load failed: %s', 'configuration, but load failed: %s',
@ -492,8 +418,8 @@ class Owner(callbacks.Privmsg):
irc.error('%s is already loaded.' % name.capitalize()) irc.error('%s is already loaded.' % name.capitalize())
return return
try: try:
module = loadPluginModule(name, ignoreDeprecation) module = plugin.loadPluginModule(name, ignoreDeprecation)
except Deprecated: except plugin.Deprecated:
irc.error('%s is deprecated. Use --deprecated ' irc.error('%s is deprecated. Use --deprecated '
'to force it to load.' % name.capitalize()) 'to force it to load.' % name.capitalize())
return return
@ -503,7 +429,7 @@ class Owner(callbacks.Privmsg):
else: else:
irc.error(str(e)) irc.error(str(e))
return return
cb = loadPluginClass(irc, module) cb = plugin.loadPluginClass(irc, module)
name = cb.name() # Let's normalize this. name = cb.name() # Let's normalize this.
conf.registerPlugin(name, True) conf.registerPlugin(name, True)
irc.replySuccess() irc.replySuccess()
@ -521,14 +447,14 @@ class Owner(callbacks.Privmsg):
if hasattr(module, 'reload'): if hasattr(module, 'reload'):
x = module.reload() x = module.reload()
try: try:
module = loadPluginModule(name) module = plugin.loadPluginModule(name)
if hasattr(module, 'reload'): if hasattr(module, 'reload'):
module.reload(x) module.reload(x)
for callback in callbacks: for callback in callbacks:
callback.die() callback.die()
del callback del callback
gc.collect() # This makes sure the callback is collected. gc.collect() # This makes sure the callback is collected.
callback = loadPluginClass(irc, module) callback = plugin.loadPluginClass(irc, module)
irc.replySuccess() irc.replySuccess()
except ImportError: except ImportError:
for callback in callbacks: for callback in callbacks:

View File

@ -30,7 +30,7 @@
from supybot.test import * from supybot.test import *
import supybot.conf as conf import supybot.conf as conf
import supybot.plugins.Owner as Owner import supybot.plugin as plugin
class OwnerTestCase(PluginTestCase): class OwnerTestCase(PluginTestCase):
plugins = ('Utilities', 'Relay', 'Network', 'Admin', 'Channel') plugins = ('Utilities', 'Relay', 'Network', 'Admin', 'Channel')
@ -97,13 +97,4 @@ class OwnerTestCase(PluginTestCase):
self.assertError('defaultplugin foobar owner') self.assertError('defaultplugin foobar owner')
class FunctionsTestCase(SupyTestCase):
def testLoadPluginModule(self):
self.assertRaises(ImportError, Owner.loadPluginModule, 'asldj')
self.failUnless(Owner.loadPluginModule('Owner'))
self.failUnless(Owner.loadPluginModule('owner'))
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: # vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:

114
src/plugin.py Normal file
View File

@ -0,0 +1,114 @@
###
# Copyright (c) 2002-2005, Jeremiah Fincher
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions, and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions, and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the author of this software nor the name of
# contributors to this software may be used to endorse or promote products
# derived from this software without specific prior written consent.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
###
import os
import sys
import imp
import os.path
import linecache
import supybot.log as log
import supybot.conf as conf
import supybot.registry as registry
class Deprecated(ImportError):
pass
def loadPluginModule(name, ignoreDeprecation=False):
"""Loads (and returns) the module for the plugin with the given name."""
files = []
pluginDirs = conf.supybot.directories.plugins()
for dir in pluginDirs:
try:
files.extend(os.listdir(dir))
except EnvironmentError: # OSError, IOError superclass.
log.warning('Invalid plugin directory: %s; removing.',
utils.quoted(dir))
conf.supybot.directories.plugins().remove(dir)
loweredFiles = map(str.lower, files)
try:
index = loweredFiles.index(name.lower()+'.py')
name = os.path.splitext(files[index])[0]
if name in sys.modules:
m = sys.modules[name]
if not hasattr(m, 'Class'):
raise ImportError, 'Module is not a plugin.'
except ValueError: # We'd rather raise the ImportError, so we'll let go...
pass
moduleInfo = imp.find_module(name, pluginDirs)
try:
module = imp.load_module(name, *moduleInfo)
except:
sys.modules.pop(name, None)
raise
if 'deprecated' in module.__dict__ and module.deprecated:
if ignoreDeprecation:
log.warning('Deprecated plugin loaded: %s', name)
else:
raise Deprecated, 'Attempted to load deprecated plugin %s' % \
utils.quoted(name)
if module.__name__ in sys.modules:
sys.modules[module.__name__] = module
linecache.checkcache()
return module
def loadPluginClass(irc, module, register=None):
"""Loads the plugin Class from the given module into the given Irc."""
try:
cb = module.Class()
except AttributeError, e:
if 'Class' in str(e):
raise callbacks.Error, \
'This plugin module doesn\'t have a "Class" ' \
'attribute to specify which plugin should be ' \
'instantiated. If you didn\'t write this ' \
'plugin, but received it with Supybot, file ' \
'a bug with us about this error.'
else:
raise
plugin = cb.name()
public = True
if hasattr(cb, 'public'):
public = cb.public
conf.registerPlugin(plugin, register, public)
assert not irc.getCallback(plugin)
try:
renames = []#XXX registerRename(plugin)()
if renames:
for command in renames:
v = registerRename(plugin, command)
newName = v()
assert newName
renameCommand(cb, command, newName)
else:
conf.supybot.commands.renames.unregister(plugin)
except registry.NonExistentRegistryEntry, e:
pass # The plugin isn't there.
irc.addCallback(cb)
return cb