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
38 # ('flatfilts-rolf', True),
42 # ('massanalysis', True),
43 # ('multidistance', True),
46 # ('procplots', True),
48 # ('showconvoluted', True),
49 # ('superimpose', True),
54 """List of plugin modules and whether they should be included by
55 default. TODO: autodiscovery
68 """List of builtin modules. TODO: autodiscovery
71 PLUGIN_SETTING_SECTION = 'plugins'
72 """Name of the config section which controls plugin selection.
76 # Plugins and settings
78 class Plugin (object):
79 """A pluggable collection of Hooke commands.
81 Fulfills the same role for Hooke that a software package does for
82 an operating system: contains a chunk of related commands and
83 routines. Command configuration also happens on the `Plugin`
84 level, with per-plugin sections in the configuration file.
86 def __init__(self, name):
88 self.setting_section = '%s plugin' % self.name
92 def dependencies(self):
93 """Return a list of names of :class:`Plugin`\s we require."""
96 def default_settings(self):
97 """Return a list of :class:`hooke.config.Setting`\s for any
98 configurable plugin settings.
100 The suggested section setting is::
102 Setting(section=self.setting_section, help=self.__doc__)
107 """Return a list of :class:`hooke.command.Command`\s provided.
109 return list(self._commands)
112 class Builtin (Plugin):
113 """A required collection of Hooke commands.
115 These "core" plugins provide essential administrative commands
116 (playlist handling, etc.).
121 # Plugin utility functions
123 def argument_to_setting(section_name, argument):
124 """Convert an :class:`~hooke.command.Argument` to a
125 `~hooke.conf.Setting`.
127 This is a 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,
135 # Construct plugin dependency graph and load plugin instances.
137 PLUGIN_GRAPH = construct_graph(
138 this_modname=__name__,
139 submodnames=[name for name,include in PLUGIN_MODULES] + BUILTIN_MODULES,
140 class_selector=IsSubclass(Plugin, blacklist=[Plugin, Builtin]))
141 """Topologically sorted list of all possible :class:`Plugin`\s and
145 def default_settings():
146 settings = [Setting(PLUGIN_SETTING_SECTION,
147 help='Enable/disable default plugins.')]
148 for pnode in PLUGIN_GRAPH:
149 if pnode.data.name in BUILTIN_MODULES:
150 continue # builtin inclusion is not optional
152 default_include = [di for mod_name,di in PLUGIN_MODULES
153 if mod_name == plugin.name][0]
154 help = 'Commands: ' + ', '.join([c.name for c in plugin.commands()])
155 settings.append(Setting(
156 section=PLUGIN_SETTING_SECTION,
158 value=str(default_include),
161 for pnode in PLUGIN_GRAPH:
163 settings.extend(plugin.default_settings())
166 def load_graph(graph, config, include_section):
172 include = config.getboolean(include_section, item.name)
173 except configparser.NoOptionError:
174 include = True # non-optional include (e.g. a Builtin)
175 enabled[item.name] = include
176 print 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
187 item.config = dict(config.items(item.setting_section))
188 except configparser.NoSectionError: