1 # GNU MediaGoblin -- federated, autonomous media hosting
2 # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Affero General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU Affero General Public License for more details.
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
18 This module implements the plugin api bits and provides the plugin
21 Two things about things in this module:
23 1. they should be excessively well documented because we should pull
24 from this file for the docs
26 2. they should be well tested
32 Plugins are structured like any Python project. You create a Python package.
33 In that package, you define a high-level ``__init__.py`` that either defines
34 or imports modules that define classes that inherit from the ``Plugin`` class.
36 Additionally, you want a LICENSE file that specifies the license and a
37 ``setup.py`` that specifies the metadata for packaging your plugin. A rough
38 file structure could look like this::
41 |- setup.py # plugin project packaging metadata
42 |- README # holds plugin project information
43 |- LICENSE # holds license information
44 |- myplugin/ # plugin package directory
45 |- __init__.py # imports myplugin.main
46 |- main.py # code for plugin
52 1. All the modules listed as subsections of the ``plugins`` section in
53 the config file are imported. This causes any ``Plugin`` subclasses in
54 those modules to be defined and when the classes are defined they get
55 automatically registered with the ``PluginCache``.
57 2. After all plugin modules are imported, registered plugin classes are
58 instantiated and ``setup_plugin`` is called for each plugin object.
60 Plugins can do any setup they need to do in their ``setup_plugin``
66 from mediagoblin
import mg_globals
69 _log
= logging
.getLogger(__name__
)
72 class PluginCache(object):
73 """Cache of plugin things"""
75 # list of plugin classes
78 # list of plugin objects
81 # list of registered template paths
82 "template_paths": set(),
86 """This is only useful for testing."""
87 del self
.plugin_classes
[:]
88 del self
.plugin_objects
[:]
91 self
.__dict
__ = self
.__state
93 def register_plugin_class(self
, plugin_class
):
94 """Registers a plugin class"""
95 self
.plugin_classes
.append(plugin_class
)
97 def register_plugin_object(self
, plugin_obj
):
98 """Registers a plugin object"""
99 self
.plugin_objects
.append(plugin_obj
)
101 def register_template_path(self
, path
):
102 """Registers a template path"""
103 self
.template_paths
.add(path
)
105 def get_template_paths(self
):
106 """Returns a tuple of registered template paths"""
107 return tuple(self
.template_paths
)
110 class MetaPluginClass(type):
111 """Metaclass for PluginBase derivatives"""
112 def __new__(cls
, name
, bases
, attrs
):
113 new_class
= super(MetaPluginClass
, cls
).__new
__(cls
, name
, bases
, attrs
)
114 parents
= [b
for b
in bases
if isinstance(b
, MetaPluginClass
)]
117 PluginCache().register_plugin_class(new_class
)
121 class Plugin(object):
122 """Exttend this class for plugins.
126 from mediagoblin.tools.pluginapi import Plugin
128 class MyPlugin(Plugin):
131 def setup_plugin(self):
136 __metaclass__
= MetaPluginClass
138 def setup_plugin(self
):
142 def register_template_path(path
):
143 """Registers a path for template loading
145 If your plugin has templates, then you need to call this with
146 the absolute path of the root of templates directory.
150 >>> my_plugin_dir = os.path.dirname(__file__)
151 >>> template_dir = os.path.join(my_plugin_dir, 'templates')
152 >>> register_template_path(template_dir)
156 You can only do this in `setup_plugins()`. Doing this after
157 that will have no effect on template loading.
160 PluginCache().register_template_path(path
)
164 """Retrieves the configuration for a specified plugin by key
168 >>> get_config('mediagoblin.plugins.sampleplugin')
170 >>> get_config('myplugin')
172 >>> get_config('flatpages')
173 {'directory': '/srv/mediagoblin/pages', 'nesting': 1}}
177 global_config
= mg_globals
.global_config
178 plugin_section
= global_config
.get('plugins', {})
179 return plugin_section
.get(key
, {})