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 under the
6 # terms of the GNU Lesser General Public License as published by the Free
7 # Software Foundation, either version 3 of the License, or (at your option) any
10 # Hooke is distributed in the hope that it will be useful, but WITHOUT ANY
11 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12 # A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
15 # You should have received a copy of the GNU Lesser General Public License
16 # along with Hooke. If not, see <http://www.gnu.org/licenses/>.
18 """The `plugin` module provides optional submodules that add new Hooke
21 All of the science happens in here.
24 import ConfigParser as configparser
27 from ..config import Setting
28 from ..util.pluggable import IsSubclass, construct_graph
38 # ('massanalysis', True),
39 # ('multidistance', True),
42 ('polymer_fit', True),
43 # ('showconvoluted', True),
44 # ('superimpose', True),
49 """List of plugin modules and whether they should be included by
50 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
79 an operating system: contains a chunk of related commands and
80 routines. Command configuration also happens on the `Plugin`
81 level, with per-plugin sections in the configuration file.
83 def __init__(self, name):
85 self.setting_section = '%s plugin' % self.name
89 def dependencies(self):
90 """Return a list of names of :class:`Plugin`\s we require."""
93 def default_settings(self):
94 """Return a list of :class:`hooke.config.Setting`\s for any
95 configurable plugin settings.
97 The suggested section setting is::
99 Setting(section=self.setting_section, help=self.__doc__)
104 """Return a list of :class:`hooke.command.Command`\s provided.
106 return list(self._commands)
109 class Builtin (Plugin):
110 """A required collection of Hooke commands.
112 These "core" plugins provide essential administrative commands
113 (playlist handling, etc.).
118 # Plugin utility functions
120 def argument_to_setting(section_name, argument):
121 """Convert an :class:`~hooke.command.Argument` to a
122 `~hooke.conf.Setting`.
124 This is useful if, for example, you want to define arguments with
125 configurable default values.
127 Conversion is lossy transition, because
128 :class:`~hooke.command.Argument`\s store more information than
129 `~hooke.conf.Setting`\s.
131 return Setting(section_name, option=argument.name, value=argument.default,
132 type=argument.type, count=argument.count,
136 # Construct plugin dependency graph and load plugin instances.
138 PLUGIN_GRAPH = construct_graph(
139 this_modname=__name__,
140 submodnames=[name for name,include in PLUGIN_MODULES] + BUILTIN_MODULES,
141 class_selector=IsSubclass(Plugin, blacklist=[Plugin, Builtin]))
142 """Topologically sorted list of all possible :class:`Plugin`\s and
146 def default_settings():
147 settings = [Setting(PLUGIN_SETTING_SECTION,
148 help='Enable/disable default plugins.')]
149 for pnode in PLUGIN_GRAPH:
150 if pnode.data.name in BUILTIN_MODULES:
151 continue # builtin inclusion is not optional
153 default_include = [di for mod_name,di in PLUGIN_MODULES
154 if mod_name == plugin.name][0]
155 help = 'Commands: ' + ', '.join([c.name for c in plugin.commands()])
156 settings.append(Setting(
157 section=PLUGIN_SETTING_SECTION,
159 value=str(default_include),
162 for pnode in PLUGIN_GRAPH:
164 settings.extend(plugin.default_settings())
167 def load_graph(graph, config, include_section):
173 include = config.getboolean(include_section, item.name)
174 except configparser.NoOptionError:
175 include = True # non-optional include (e.g. a Builtin)
176 enabled[item.name] = include
178 for dependency in node:
179 if enabled.get(dependency.data.name, None) != True:
180 log = logging.getLogger('hooke')
182 'could not setup plugin %s. unsatisfied dependency on %s.'
183 % (item.name, dependency.data.name))
184 enabled[item.name] = False