From 45cba75f46ae4c309f1807e58d2843b99971617d Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Sat, 8 May 2010 08:48:02 -0400 Subject: [PATCH] Assorted changes so import hooke.plugin works ;). Uncommenting the cut entry in PLUGIN_MODULES exposed a number of bugs which I fixed: * def Plugin (object): -> class Plugin (object): * plugin initialization must occur *after* Command/Argument definition. That way the neccessary classes are defined when we go to load the plugin modules. * Broken default_settings() fixed. Also did some docstring cleanup. --- hooke/plugin/__init__.py | 95 ++++++++++++++++++++++++++-------------- hooke/plugin/cut.py | 14 +++--- 2 files changed, 68 insertions(+), 41 deletions(-) diff --git a/hooke/plugin/__init__.py b/hooke/plugin/__init__.py index 42a758c..585969e 100644 --- a/hooke/plugin/__init__.py +++ b/hooke/plugin/__init__.py @@ -13,7 +13,7 @@ from ..util.graph import Node, Graph PLUGIN_MODULES = [ # ('autopeak', True), # ('curvetools', True), -# ('cut', True), + ('cut', True), # ('fit', True), # ('flatfilts-rolf', True), # ('flatfilts', True), @@ -39,7 +39,7 @@ default. TODO: autodiscovery # Plugins and settings -def Plugin (object): +class Plugin (object): """The pluggable collection of Hooke commands. Fulfills the same role for Hooke that a software package does for @@ -49,46 +49,23 @@ def Plugin (object): self.name = name def dependencies(self): - """Return a list of Plugins we require.""" + """Return a list of :class:`Plugin`\s we require.""" return [] def default_settings(self): - """Return a list of hooke.config.Settings() for any - configurable module settings.""" + """Return a list of :class:`hooke.config.Setting`\s for any + configurable plugin settings. + + The suggested section setting is:: + + Setting(section='%s plugin' % self.name, help=self.__doc__) + """ return [] def commands(self): - """Return a list of Commands provided.""" + """Return a list of :class:`Commands` provided.""" return [] -PLUGINS = {} -"""(name,instance) :class:`dict` of all possible :class:`Plugin`\s. -""" - -print __name__ -for plugin_modname,value in PLUGIN_MODULES: - this_mod = __import__(__name__, fromlist=[plugin_modname]) - plugin_mod = getattr(this_mod, plugin_modname) - for objname in dir(plugin_mod): - obj = getattr(plugin_mod, objname) - if type(obj) == Plugin: - obj.module_name = plugin_modname - PLUGINS[p.name] = p - -PLUGIN_GRAPH = Graph([Node([PLUGINS[name] for name in p.dependencies()]) - for p in PLUGINS.values()]) -PLUGIN_GRAPH.topological_sort() - - -def default_settings(self): - settings = [Setting( - 'plugins', help='Enable/disable default plugins.')] - for pnode in PLUGIN_GRAPH: - settings.append(Setting(p.name, str(PLUGIN_MODULES[p.module_name][1]))) - for pnode in PLUGIN_GRAPH: - plugin = pnode.data - settings.extend(plugin.default_settings()) - return settings # Commands and arguments @@ -276,3 +253,53 @@ class PrintQueue (NullQueue): """Print `item` and then dump it into the void. """ print 'ITEM:\n%s' % item + + +# Construct plugin dependency graph and load default plugins. + +PLUGINS = {} +"""(name,instance) :class:`dict` of all possible :class:`Plugin`\s. +""" + +for plugin_modname,default_include in PLUGIN_MODULES: + assert len([mod_name for mod_name,di in PLUGIN_MODULES]) == 1, \ + 'Multiple %s entries in PLUGIN_MODULES' % mod_name + this_mod = __import__(__name__, fromlist=[plugin_modname]) + plugin_mod = getattr(this_mod, plugin_modname) + for objname in dir(plugin_mod): + obj = getattr(plugin_mod, objname) + try: + subclass = issubclass(obj, Plugin) + except TypeError: + continue + if subclass == True and obj != Plugin: + p = obj() + if p.name != plugin_modname: + raise Exception('Plugin name %s does not match module name %s' + % (p.name, plugin_modname)) + PLUGINS[p.name] = p + +PLUGIN_GRAPH = Graph([Node([PLUGINS[name] for name in p.dependencies()], + data=p) + for p in PLUGINS.values()]) +PLUGIN_GRAPH.topological_sort() + + +def default_settings(): + settings = [Setting( + 'plugins', help='Enable/disable default plugins.')] + for pnode in PLUGIN_GRAPH: + plugin = pnode.data + default_include = [di for mod_name,di in PLUGIN_MODULES + if mod_name == plugin.name][0] + help = 'Commands: ' + ', '.join([c.name for c in p.commands()]) + settings.append(Setting( + section='plugins', + option=plugin.name, + value=str(default_include), + help=help, + )) + for pnode in PLUGIN_GRAPH: + plugin = pnode.data + settings.extend(plugin.default_settings()) + return settings diff --git a/hooke/plugin/cut.py b/hooke/plugin/cut.py index 33010e4..351ac18 100644 --- a/hooke/plugin/cut.py +++ b/hooke/plugin/cut.py @@ -1,7 +1,7 @@ """Defines :class:`CutPlugin` and :class:`CutCommand`. """ -from . import Plugin, Command, Argument +from ..plugin import Plugin, Command, Argument class CutPlugin (Plugin): @@ -12,6 +12,11 @@ class CutPlugin (Plugin): return [CutCommand()] class CutCommand (Command): + """Cut the selected signal between two points and write it to a file. + + The data is saved in TAB-delimited ASCII text, where the first column + is "x" and the second is "y". There is no header row. + """ def __init__(self): super(CutCommand, self).__init__( name='cut', @@ -33,12 +38,7 @@ Indicies of points bounding the selected data. File name for the output data. """.strip()), ], - help=""" -Cut the selected signal between two points and write it to a file. - -The data is saved in TAB-delimited ASCII text, where the first column -is "x" and the second is "y". There is no header row. -""".strip()) + help=self.__doc__) def _run(inqueue, outqueue, params): i_min = min([p.index for p in params['points']]) -- 2.26.2