-
Notifications
You must be signed in to change notification settings - Fork 2k
/
core.py
185 lines (141 loc) · 4.88 KB
/
core.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
"""
Provides plugin services to the CKAN
"""
import logging
from inspect import isclass
from itertools import chain
from pkg_resources import iter_entry_points
from pyutilib.component.core import PluginGlobals, implements
from pyutilib.component.core import ExtensionPoint as PluginImplementations
from pyutilib.component.core import SingletonPlugin as _pca_SingletonPlugin
from pyutilib.component.core import Plugin as _pca_Plugin
from ckan.plugins.interfaces import IPluginObserver, IGenshiStreamFilter
__all__ = [
'PluginImplementations', 'implements',
'PluginNotFoundException', 'Plugin', 'SingletonPlugin',
'load', 'load_all', 'unload', 'unload_all',
'reset'
]
log = logging.getLogger(__name__)
# Entry point group.
PLUGINS_ENTRY_POINT_GROUP = "ckan.plugins"
# Entry point group for system plugins (those that are part of core ckan and do
# not need to be explicitly enabled by the user)
SYSTEM_PLUGINS_ENTRY_POINT_GROUP = "ckan.system_plugins"
class PluginNotFoundException(Exception):
"""
Raised when a requested plugin cannot be found.
"""
class Plugin(_pca_Plugin):
"""
Base class for plugins which require multiple instances.
Unless you need multiple instances of your plugin object you should
probably use SingletonPlugin.
"""
class SingletonPlugin(_pca_SingletonPlugin):
"""
Base class for plugins which are singletons (ie most of them)
One singleton instance of this class will be created when the plugin is
loaded. Subsequent calls to the class constructor will always return the
same singleton instance.
"""
def _get_service(plugin):
"""
Return a service (ie an instance of a plugin class).
:param plugin: any of: the name of a plugin entry point; a plugin class; an
instantiated plugin object.
:return: the service object
"""
if isinstance(plugin, basestring):
try:
name = plugin
(plugin,) = iter_entry_points(
group=PLUGINS_ENTRY_POINT_GROUP,
name=name
)
except ValueError:
raise PluginNotFoundException(plugin)
return plugin.load()(name=name)
elif isinstance(plugin, _pca_Plugin):
return plugin
elif isclass(plugin) and issubclass(plugin, _pca_Plugin):
return plugin()
else:
raise TypeError("Expected a plugin name, class or instance", plugin)
def load_all(config):
"""
Load all plugins listed in the 'ckan.plugins' config directive.
"""
plugins = chain(
find_system_plugins(),
find_user_plugins(config)
)
# PCA default behaviour is to activate SingletonPlugins at import time. We
# only want to activate those listed in the config, so clear
# everything then activate only those we want.
unload_all()
for plugin in plugins:
load(plugin)
def reset():
"""
Clear and reload all configured plugins
"""
from pylons import config
load_all(config)
def load(plugin):
"""
Load a single plugin, given a plugin name, class or instance
"""
observers = PluginImplementations(IPluginObserver)
for observer_plugin in observers:
observer_plugin.before_load(plugin)
service = _get_service(plugin)
service.activate()
for observer_plugin in observers:
observer_plugin.after_load(service)
if IGenshiStreamFilter in service.__interfaces__:
log.warn("Plugin '%s' is using deprecated interface IGenshiStreamFilter" % plugin)
return service
def unload_all():
"""
Unload (deactivate) all loaded plugins
"""
for env in PluginGlobals.env_registry.values():
for service in env.services.copy():
unload(service)
def unload(plugin):
"""
Unload a single plugin, given a plugin name, class or instance
"""
observers = PluginImplementations(IPluginObserver)
service = _get_service(plugin)
for observer_plugin in observers:
observer_plugin.before_unload(service)
service.deactivate()
for observer_plugin in observers:
observer_plugin.after_unload(service)
return service
def find_user_plugins(config):
"""
Return all plugins specified by the user in the 'ckan.plugins' config
directive.
"""
plugins = []
for name in config.get('ckan.plugins', '').split():
entry_points = list(
iter_entry_points(group=PLUGINS_ENTRY_POINT_GROUP, name=name)
)
if not entry_points:
raise PluginNotFoundException(name)
plugins.extend(ep.load() for ep in entry_points)
return plugins
def find_system_plugins():
"""
Return all plugins in the ckan.system_plugins entry point group.
These are essential for operation and therefore cannot be enabled/disabled
through the configuration file.
"""
return (
ep.load()
for ep in iter_entry_points(group=SYSTEM_PLUGINS_ENTRY_POINT_GROUP)
)