Assorted changes so import hooke.plugin works ;).
authorW. Trevor King <wking@drexel.edu>
Sat, 8 May 2010 12:48:02 +0000 (08:48 -0400)
committerW. Trevor King <wking@drexel.edu>
Sat, 8 May 2010 12:48:02 +0000 (08:48 -0400)
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
hooke/plugin/cut.py

index 42a758c5ea6459feccb6b8dc0620023946859ab5..585969ea7f04fc5cf3a6386cab569ff193826f50 100644 (file)
@@ -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
index 33010e4ff8cc8e9478f0d0ae73a472a63a1405ab..351ac18592e9931c9157f8d8fb375d632cf61c10 100644 (file)
@@ -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']])