1 # Copyright (C) 2010 W. Trevor King <wking@drexel.edu>
3 # This file is part of Hooke.
5 # Hooke is free software: you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation, either
8 # version 3 of the License, or (at your option) any later version.
10 # Hooke is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with Hooke. If not, see
17 # <http://www.gnu.org/licenses/>.
19 """The `plugin` module provides optional submodules that add new Hooke
22 All of the science happens in here.
25 import ConfigParser as configparser
27 from ..config import Setting
28 from ..util.pluggable import IsSubclass, construct_graph
37 # ('flatfilts-rolf', True),
41 # ('massanalysis', True),
42 # ('multidistance', True),
45 # ('procplots', True),
47 # ('showconvoluted', True),
48 # ('superimpose', True),
53 """List of plugin modules and whether they should be included by
54 default. TODO: autodiscovery
65 """List of builtin modules. TODO: autodiscovery
68 PLUGIN_SETTING_SECTION = 'plugins'
69 """Name of the config section which controls plugin selection.
73 # Plugins and settings
75 class Plugin (object):
76 """A pluggable collection of Hooke commands.
78 Fulfills the same role for Hooke that a software package does for
81 def __init__(self, name):
83 self.setting_section = '%s plugin' % self.name
87 def dependencies(self):
88 """Return a list of names of :class:`Plugin`\s we require."""
91 def default_settings(self):
92 """Return a list of :class:`hooke.config.Setting`\s for any
93 configurable plugin settings.
95 The suggested section setting is::
97 Setting(section=self.setting_section, help=self.__doc__)
102 """Return a list of :class:`hooke.command.Command`\s provided.
104 return list(self._commands)
106 class Builtin (Plugin):
107 """A required collection of Hooke commands.
109 These "core" plugins provide essential administrative commands
110 (playlist handling, etc.).
114 # Plugin utility functions
116 def argument_to_setting(section_name, argument):
117 """Convert an :class:`~hooke.command.Argument` to a
118 `~hooke.conf.Setting`.
120 This is a lossy transition, because
121 :class:`~hooke.command.Argument`\s store more information than
122 `~hooke.conf.Setting`\s.
124 return Setting(section_name, option=argument.name, value=argument.default,
127 # Construct plugin dependency graph and load plugin instances.
129 PLUGIN_GRAPH = construct_graph(
130 this_modname=__name__,
131 submodnames=[name for name,include in PLUGIN_MODULES] + BUILTIN_MODULES,
132 class_selector=IsSubclass(Plugin, blacklist=[Plugin, Builtin]))
133 """Topologically sorted list of all possible :class:`Plugin`\s and
137 def default_settings():
138 settings = [Setting(PLUGIN_SETTING_SECTION,
139 help='Enable/disable default plugins.')]
140 for pnode in PLUGIN_GRAPH:
141 if pnode.data.name in BUILTIN_MODULES:
142 continue # builtin inclusion is not optional
144 default_include = [di for mod_name,di in PLUGIN_MODULES
145 if mod_name == plugin.name][0]
146 help = 'Commands: ' + ', '.join([c.name for c in plugin.commands()])
147 settings.append(Setting(
148 section=PLUGIN_SETTING_SECTION,
150 value=str(default_include),
153 for pnode in PLUGIN_GRAPH:
155 settings.extend(plugin.default_settings())
158 def load_graph(graph, config, include_section):
163 include = config.getboolean(include_section, item.name)
164 except configparser.NoOptionError:
165 include = True # non-optional include (e.g. a Builtin)
168 item.config = dict(config.items(item.setting_section))
169 except configparser.NoSectionError: