Skip to content

Instantly share code, notes, and snippets.

@FurryHead
Created June 7, 2011 22:36
Show Gist options
  • Save FurryHead/1013349 to your computer and use it in GitHub Desktop.
Save FurryHead/1013349 to your computer and use it in GitHub Desktop.
New plugin loader
import os, inspect, collections
pList = { }
mList = collections.defaultdict(list)
class NoSuchPluginError(Exception): pass
def plugin(cls):
#Using inspect, figure out what file is calling this function (using @plugin)
clsFile = inspect.stack()[1][1]
#Split the path, because it will be in the form "plugins" + os.sep + "*.py"
modFile = clsFile.split(os.sep)[1]
#Append the class name to the list indexed by module file name
mList[modFile].append(cls.__name__)
#Set class (plugin) name to the class (plugin) reference
pList[cls.__name__] = cls
#return cls, since decorators must return the "new" type
return cls
def refresh(pluginName = None):
"""
Refreshes the list of module/class pairs, and plugin/class pairs.
If pluginName is not None, it can raise NoSuchPluginError.
Regardless of the value of pluginName, it can raise any error a python file can raise, samme as using import.
"""
#if we are asked to do a general refresh of list
if pluginName is None:
#we were asked to refresh, so clear out our lists so we can start fresh
pList.clear()
mList.clear()
#load every module in the plugins package
_files = [os.path.join("plugins", f) for f in os.listdir("plugins") if f != "__init__.py" and not f.endswith(".pyc") and not os.path.isdir(os.path.join("plugins",f))]
#for file (module) in the file list
for f in _files:
#Set "plugin" in the environment so that @plugin decorators work correctly
env = {"plugin":plugin}
#Execute the file. The file will automatically update the list of plugins, due to the @plugin decorator
execfile(f, {}, env)
else:
#We're trying to refresh a module, so use _reload instead.
found = _reload(pluginName)
#if it wasn't found, try refreshing all modules and try again
if not found:
refresh()
found = _reload(pluginName)
#if it's still not found, raise an error.
if not found:
raise NoSuchPluginError()
def _reload(pluginName):
#iterate over each "file", "module" pair in mList
for f,classes in mList:
#if the requested
if pluginName in classes:
#Set "plugin" in the environment so that @plugin decorators work correctly
env = {"plugin":plugin}
#Execute the file. The file will automatically update the list of plugins, due to the @plugin decorator
execfile(f, {}, env)
#return True, indicating we have found and reloaded the module.
return True
#Else, we have not found it, so return False.
return False
def getPlugin(name):
""" Helper function to get a plugin's class. """
try:
return pList[name]
except KeyError:
return None
refresh()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment