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 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
37 # ('flatfilts-rolf', True),
40 # ('massanalysis', True),
41 # ('multidistance', True),
44 ('polymer_fit', 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
67 """List of builtin modules. TODO: autodiscovery
70 PLUGIN_SETTING_SECTION = 'plugins'
71 """Name of the config section which controls plugin selection.
75 # Plugins and settings
77 class Plugin (object):
78 """A pluggable collection of Hooke commands.
80 Fulfills the same role for Hooke that a software package does for
81 an operating system: contains a chunk of related commands and
82 routines. Command configuration also happens on the `Plugin`
83 level, with per-plugin sections in the configuration file.
85 def __init__(self, name):
87 self.setting_section = '%s plugin' % self.name
91 def dependencies(self):
92 """Return a list of names of :class:`Plugin`\s we require."""
95 def default_settings(self):
96 """Return a list of :class:`hooke.config.Setting`\s for any
97 configurable plugin settings.
99 The suggested section setting is::
101 Setting(section=self.setting_section, help=self.__doc__)
106 """Return a list of :class:`hooke.command.Command`\s provided.
108 return list(self._commands)
111 class Builtin (Plugin):
112 """A required collection of Hooke commands.
114 These "core" plugins provide essential administrative commands
115 (playlist handling, etc.).
120 # Plugin utility functions
122 def argument_to_setting(section_name, argument):
123 """Convert an :class:`~hooke.command.Argument` to a
124 `~hooke.conf.Setting`.
126 This is useful if, for example, you want to define arguments with
127 configurable default values.
129 Conversion is lossy transition, because
130 :class:`~hooke.command.Argument`\s store more information than
131 `~hooke.conf.Setting`\s.
133 return Setting(section_name, option=argument.name, value=argument.default,
134 type=argument.type, count=argument.count,
138 # Construct plugin dependency graph and load plugin instances.
140 PLUGIN_GRAPH = construct_graph(
141 this_modname=__name__,
142 submodnames=[name for name,include in PLUGIN_MODULES] + BUILTIN_MODULES,
143 class_selector=IsSubclass(Plugin, blacklist=[Plugin, Builtin]))
144 """Topologically sorted list of all possible :class:`Plugin`\s and
148 def default_settings():
149 settings = [Setting(PLUGIN_SETTING_SECTION,
150 help='Enable/disable default plugins.')]
151 for pnode in PLUGIN_GRAPH:
152 if pnode.data.name in BUILTIN_MODULES:
153 continue # builtin inclusion is not optional
155 default_include = [di for mod_name,di in PLUGIN_MODULES
156 if mod_name == plugin.name][0]
157 help = 'Commands: ' + ', '.join([c.name for c in plugin.commands()])
158 settings.append(Setting(
159 section=PLUGIN_SETTING_SECTION,
161 value=str(default_include),
164 for pnode in PLUGIN_GRAPH:
166 settings.extend(plugin.default_settings())
169 def load_graph(graph, config, include_section):
172 conditions = config.items('conditions')
176 include = config.getboolean(include_section, item.name)
177 except configparser.NoOptionError:
178 include = True # non-optional include (e.g. a Builtin)
179 enabled[item.name] = include
181 for dependency in node:
182 if enabled.get(dependency.data.name, None) != True:
183 log = logging.getLogger('hooke')
185 'could not setup plugin %s. unsatisfied dependency on %s.'
186 % (item.name, dependency.data.name))
187 enabled[item.name] = False
190 item.config = dict(config.items(item.setting_section))
191 except configparser.NoSectionError:
193 for key,value in conditions:
194 if key not in item.config:
195 item.config[key] = value