1 # Copyright (C) 2010-2012 W. Trevor King <wking@drexel.edu>
3 # This file is part of Hooke.
5 # Hooke is free software: you can redistribute it and/or modify it
6 # under the terms of the GNU Lesser General Public License as
7 # published by the Free Software Foundation, either version 3 of the
8 # License, or (at your option) any later version.
10 # Hooke is distributed in the hope that it will be useful, but WITHOUT
11 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
13 # 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
28 from ..config import Setting
29 from ..util.pluggable import IsSubclass, construct_graph
39 # ('massanalysis', True),
40 # ('multidistance', True),
43 ('polymer_fit', True),
44 # ('showconvoluted', True),
45 # ('superimpose', True),
50 """List of plugin modules and whether they should be included by
51 default. TODO: autodiscovery
66 """List of builtin modules. TODO: autodiscovery
69 PLUGIN_SETTING_SECTION = 'plugins'
70 """Name of the config section which controls plugin selection.
74 # Plugins and settings
76 class Plugin (object):
77 """A pluggable collection of Hooke commands.
79 Fulfills the same role for Hooke that a software package does for
80 an operating system: contains a chunk of related commands and
81 routines. Command configuration also happens on the `Plugin`
82 level, with per-plugin sections in the configuration file.
84 def __init__(self, name):
86 self.setting_section = '%s plugin' % self.name
90 def dependencies(self):
91 """Return a list of names of :class:`Plugin`\s we require."""
94 def default_settings(self):
95 """Return a list of :class:`hooke.config.Setting`\s for any
96 configurable plugin settings.
98 The suggested section setting is::
100 Setting(section=self.setting_section, help=self.__doc__)
105 """Return a list of :class:`hooke.command.Command`\s provided.
107 return list(self._commands)
110 class Builtin (Plugin):
111 """A required collection of Hooke commands.
113 These "core" plugins provide essential administrative commands
114 (playlist handling, etc.).
119 # Plugin utility functions
121 def argument_to_setting(section_name, argument):
122 """Convert an :class:`~hooke.command.Argument` to a
123 `~hooke.conf.Setting`.
125 This is useful if, for example, you want to define arguments with
126 configurable default values.
128 Conversion is lossy transition, because
129 :class:`~hooke.command.Argument`\s store more information than
130 `~hooke.conf.Setting`\s.
132 return Setting(section_name, option=argument.name, value=argument.default,
133 type=argument.type, count=argument.count,
137 # Construct plugin dependency graph and load plugin instances.
139 PLUGIN_GRAPH = construct_graph(
140 this_modname=__name__,
141 submodnames=[name for name,include in PLUGIN_MODULES] + BUILTIN_MODULES,
142 class_selector=IsSubclass(Plugin, blacklist=[Plugin, Builtin]))
143 """Topologically sorted list of all possible :class:`Plugin`\s and
147 def default_settings():
148 settings = [Setting(PLUGIN_SETTING_SECTION,
149 help='Enable/disable default plugins.')]
150 for pnode in PLUGIN_GRAPH:
151 if pnode.data.name in BUILTIN_MODULES:
152 continue # builtin inclusion is not optional
154 default_include = [di for mod_name,di in PLUGIN_MODULES
155 if mod_name == plugin.name][0]
156 help = 'Commands: ' + ', '.join([c.name for c in plugin.commands()])
157 settings.append(Setting(
158 section=PLUGIN_SETTING_SECTION,
160 value=str(default_include),
163 for pnode in PLUGIN_GRAPH:
165 settings.extend(plugin.default_settings())
168 def load_graph(graph, config, include_section):
174 include = config.getboolean(include_section, item.name)
175 except configparser.NoOptionError:
176 include = True # non-optional include (e.g. a Builtin)
177 enabled[item.name] = include
179 for dependency in node:
180 if enabled.get(dependency.data.name, None) != True:
181 log = logging.getLogger('hooke')
183 'could not setup plugin %s. unsatisfied dependency on %s.'
184 % (item.name, dependency.data.name))
185 enabled[item.name] = False