add a plugin system

A sample plugin can be found in samples/
This commit is contained in:
Benjamin Dauvergne 2014-02-27 11:24:17 +01:00
parent 3c1ce8f8b3
commit 9cddce0d37
8 changed files with 123 additions and 2 deletions

77
authentic2/plugins.py Normal file
View File

@ -0,0 +1,77 @@
"""
Use setuptools entrypoints to find plugins
Propose helper methods to load urls from plugins or modify INSTALLED_APPS
"""
import pkg_resources
import logging
from django.conf.urls import patterns, include, url
logger = logging.getLogger(__name__)
__ALL__ = ['get_plugins']
PLUGIN_CACHE = {}
class PluginError(Exception):
pass
def get_plugins(group_name, use_cache=True, *args, **kwargs):
'''Traverse all entry points for group_name and instantiate them using args
and kwargs.
'''
global PLUGIN_CACHE
if group_name in PLUGIN_CACHE and use_cache:
return PLUGIN_CACHE[group_name]
plugins = []
for entrypoint in pkg_resources.iter_entry_points(group_name):
try:
plugin_callable = entrypoint.load()
except Exception, e:
logger.exception('unable to load entrypoint %s', entrypoint)
raise PluginError('unable to load entrypoint %s' % entrypoint, e)
plugins.append(plugin_callable(*args, **kwargs))
PLUGIN_CACHE[group_name] = plugins
return plugins
def register_plugins_urls(group_name, urlpatterns):
'''Call get_before_urls and get_after_urls on all plugins providing them
and add those urls to the given urlpatterns.
URLs returned by get_before_urls() are added to the head of urlpatterns
and those returned by get_after_urls() are added to the tail of
urlpatterns.
'''
plugins = get_plugins(group_name)
before_urls = []
after_urls = []
for plugin in plugins:
if hasattr(plugin, 'get_before_urls'):
urls = plugin.get_before_urls()
before_urls.append(url('^', include(urls)))
if hasattr(plugin, 'get_after_urls'):
urls = plugin.get_after_urls()
after_urls.append(url('^', include(urls)))
before_patterns = patterns('', *before_urls)
after_patterns = patterns('', *after_urls)
return before_patterns + urlpatterns + after_patterns
def register_plugins_installed_apps(group_name, installed_apps):
'''Call get_apps() on all plugins of group_name and add the returned
applications path to the installed_apps sequence.
Applications already present are ignored.
'''
installed_apps = list(installed_apps)
for plugin in get_plugins(group_name):
if hasattr(plugin, 'get_apps'):
apps = plugin.get_apps()
for app in apps:
if app not in installed_apps:
installed_apps.append(app)
return installed_apps

View File

@ -1,8 +1,11 @@
# Django settings for authentic project.
import os
from django.core.exceptions import ImproperlyConfigured
import json
from django.core.exceptions import ImproperlyConfigured
from . import plugins
gettext_noop = lambda s: s
def to_boolean(name, default=True):
@ -149,6 +152,9 @@ INSTALLED_APPS = (
'south',
)
INSTALLED_APPS = plugins.register_plugins_installed_apps('authentic2.plugin',
INSTALLED_APPS)
MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage'

View File

@ -7,7 +7,7 @@ from authentic2.idp.decorators import prevent_access_to_transient_users
import authentic2.idp.views
from .admin import admin
from . import app_settings
from . import app_settings, plugins
admin.autodiscover()
handler500 = 'authentic2.views.server_error'
@ -56,3 +56,5 @@ try:
)
except:
pass
urlpatterns = plugins.register_plugins_urls('authentic2.plugin', urlpatterns)

View File

@ -0,0 +1,7 @@
class Plugin(object):
def get_before_urls(self):
from . import urls
return urls.urlpatterns
def get_apps(self):
return [__name__]

View File

@ -0,0 +1,4 @@
from django.db import models
class MyModel(models.Model):
a = models.TextField()

View File

@ -0,0 +1,4 @@
from django.conf.urls import patterns, url
urlpatterns = patterns('a2_test_plugin.views',
url('^test/', 'test'))

View File

@ -0,0 +1,4 @@
from django.http import HttpResponse
def test(request):
return HttpResponse('coucou')

17
samples/a2_test_plugin/setup.py Executable file
View File

@ -0,0 +1,17 @@
#!/usr/bin/python
from setuptools import setup, find_packages
import os
setup(name='authentic2-test-plugin',
version='1.0',
license='AGPLv3',
description='Authentic2 Test Plugin',
author="Entr'ouvert",
author_email="info@entrouvert.com",
packages=find_packages(os.path.dirname(__file__) or '.'),
entry_points={
'authentic2.plugin': [
'test-plugin = a2_test_plugin:Plugin',
],
},
)