Merge branch '637_friendlier_hooks'
This commit is contained in:
commit
761e26bb29
@ -18,7 +18,7 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
from celery import Celery
|
from celery import Celery
|
||||||
from mediagoblin.tools.pluginapi import PluginManager
|
from mediagoblin.tools.pluginapi import callable_runall
|
||||||
|
|
||||||
|
|
||||||
MANDATORY_CELERY_IMPORTS = ['mediagoblin.processing.task']
|
MANDATORY_CELERY_IMPORTS = ['mediagoblin.processing.task']
|
||||||
@ -66,8 +66,7 @@ def setup_celery_app(app_config, global_config,
|
|||||||
celery_app = Celery()
|
celery_app = Celery()
|
||||||
celery_app.config_from_object(celery_settings)
|
celery_app.config_from_object(celery_settings)
|
||||||
|
|
||||||
for callable_hook in PluginManager().get_hook_callables('celery_setup'):
|
callable_runall('celery_setup', celery_app)
|
||||||
callable_hook(celery_app)
|
|
||||||
|
|
||||||
|
|
||||||
def setup_celery_from_config(app_config, global_config,
|
def setup_celery_from_config(app_config, global_config,
|
||||||
|
@ -22,7 +22,7 @@ from celery.signals import setup_logging
|
|||||||
|
|
||||||
from mediagoblin import app, mg_globals
|
from mediagoblin import app, mg_globals
|
||||||
from mediagoblin.init.celery import setup_celery_from_config
|
from mediagoblin.init.celery import setup_celery_from_config
|
||||||
from mediagoblin.tools.pluginapi import PluginManager
|
from mediagoblin.tools.pluginapi import callable_runall
|
||||||
|
|
||||||
|
|
||||||
OUR_MODULENAME = __name__
|
OUR_MODULENAME = __name__
|
||||||
@ -47,9 +47,7 @@ def setup_logging_from_paste_ini(loglevel, **kw):
|
|||||||
|
|
||||||
logging.config.fileConfig(logging_conf_file)
|
logging.config.fileConfig(logging_conf_file)
|
||||||
|
|
||||||
for callable_hook in \
|
callable_runall('celery_logging_setup')
|
||||||
PluginManager().get_hook_callables('celery_logging_setup'):
|
|
||||||
callable_hook()
|
|
||||||
|
|
||||||
|
|
||||||
setup_logging.connect(setup_logging_from_paste_ini)
|
setup_logging.connect(setup_logging_from_paste_ini)
|
||||||
|
@ -59,6 +59,4 @@ def setup_plugins():
|
|||||||
pman.register_hooks(plugin.hooks)
|
pman.register_hooks(plugin.hooks)
|
||||||
|
|
||||||
# Execute anything registered to the setup hook.
|
# Execute anything registered to the setup hook.
|
||||||
setup_list = pman.get_hook_callables('setup')
|
pluginapi.callable_runall('setup')
|
||||||
for fun in setup_list:
|
|
||||||
fun()
|
|
||||||
|
@ -15,7 +15,10 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from configobj import ConfigObj
|
from configobj import ConfigObj
|
||||||
|
import pytest
|
||||||
|
|
||||||
from mediagoblin import mg_globals
|
from mediagoblin import mg_globals
|
||||||
from mediagoblin.init.plugins import setup_plugins
|
from mediagoblin.init.plugins import setup_plugins
|
||||||
from mediagoblin.tools import pluginapi
|
from mediagoblin.tools import pluginapi
|
||||||
@ -172,3 +175,111 @@ def test_disabled_plugin():
|
|||||||
|
|
||||||
# Make sure we didn't load the plugin
|
# Make sure we didn't load the plugin
|
||||||
assert len(pman.plugins) == 0
|
assert len(pman.plugins) == 0
|
||||||
|
|
||||||
|
|
||||||
|
@with_cleanup()
|
||||||
|
def test_callable_runone():
|
||||||
|
"""
|
||||||
|
Test the callable_runone method
|
||||||
|
"""
|
||||||
|
cfg = build_config([
|
||||||
|
('mediagoblin', {}, []),
|
||||||
|
('plugins', {}, [
|
||||||
|
('mediagoblin.tests.testplugins.callables1', {}, []),
|
||||||
|
('mediagoblin.tests.testplugins.callables2', {}, []),
|
||||||
|
('mediagoblin.tests.testplugins.callables3', {}, []),
|
||||||
|
])
|
||||||
|
])
|
||||||
|
|
||||||
|
mg_globals.app_config = cfg['mediagoblin']
|
||||||
|
mg_globals.global_config = cfg
|
||||||
|
|
||||||
|
setup_plugins()
|
||||||
|
|
||||||
|
# Just one hook provided
|
||||||
|
call_log = []
|
||||||
|
assert pluginapi.callable_runone(
|
||||||
|
"just_one", call_log) == "Called just once"
|
||||||
|
assert call_log == ["expect this one call"]
|
||||||
|
|
||||||
|
# Nothing provided and unhandled not okay
|
||||||
|
call_log = []
|
||||||
|
with pytest.raises(pluginapi.UnhandledCallable):
|
||||||
|
pluginapi.callable_runone(
|
||||||
|
"nothing_handling", call_log)
|
||||||
|
assert call_log == []
|
||||||
|
|
||||||
|
# Nothing provided and unhandled okay
|
||||||
|
call_log = []
|
||||||
|
assert pluginapi.callable_runone(
|
||||||
|
"nothing_handling", call_log, unhandled_okay=True) is None
|
||||||
|
assert call_log == []
|
||||||
|
|
||||||
|
# Multiple provided, go with the first!
|
||||||
|
call_log = []
|
||||||
|
assert pluginapi.callable_runone(
|
||||||
|
"multi_handle", call_log) == "the first returns"
|
||||||
|
assert call_log == ["Hi, I'm the first"]
|
||||||
|
|
||||||
|
# Multiple provided, one has CantHandleIt
|
||||||
|
call_log = []
|
||||||
|
assert pluginapi.callable_runone(
|
||||||
|
"multi_handle_with_canthandle",
|
||||||
|
call_log) == "the second returns"
|
||||||
|
assert call_log == ["Hi, I'm the second"]
|
||||||
|
|
||||||
|
|
||||||
|
@with_cleanup()
|
||||||
|
def test_callable_runall():
|
||||||
|
"""
|
||||||
|
Test the callable_runall method
|
||||||
|
"""
|
||||||
|
cfg = build_config([
|
||||||
|
('mediagoblin', {}, []),
|
||||||
|
('plugins', {}, [
|
||||||
|
('mediagoblin.tests.testplugins.callables1', {}, []),
|
||||||
|
('mediagoblin.tests.testplugins.callables2', {}, []),
|
||||||
|
('mediagoblin.tests.testplugins.callables3', {}, []),
|
||||||
|
])
|
||||||
|
])
|
||||||
|
|
||||||
|
mg_globals.app_config = cfg['mediagoblin']
|
||||||
|
mg_globals.global_config = cfg
|
||||||
|
|
||||||
|
setup_plugins()
|
||||||
|
|
||||||
|
# Just one hook, check results
|
||||||
|
call_log = []
|
||||||
|
assert pluginapi.callable_runall(
|
||||||
|
"just_one", call_log) == ["Called just once", None, None]
|
||||||
|
assert call_log == ["expect this one call"]
|
||||||
|
|
||||||
|
# None provided, check results
|
||||||
|
call_log = []
|
||||||
|
assert pluginapi.callable_runall(
|
||||||
|
"nothing_handling", call_log) == []
|
||||||
|
assert call_log == []
|
||||||
|
|
||||||
|
# Multiple provided, check results
|
||||||
|
call_log = []
|
||||||
|
assert pluginapi.callable_runall(
|
||||||
|
"multi_handle", call_log) == [
|
||||||
|
"the first returns",
|
||||||
|
"the second returns",
|
||||||
|
"the third returns",
|
||||||
|
]
|
||||||
|
assert call_log == [
|
||||||
|
"Hi, I'm the first",
|
||||||
|
"Hi, I'm the second",
|
||||||
|
"Hi, I'm the third"]
|
||||||
|
|
||||||
|
# Multiple provided, one has CantHandleIt, check results
|
||||||
|
call_log = []
|
||||||
|
assert pluginapi.callable_runall(
|
||||||
|
"multi_handle_with_canthandle", call_log) == [
|
||||||
|
"the second returns",
|
||||||
|
"the third returns",
|
||||||
|
]
|
||||||
|
assert call_log == [
|
||||||
|
"Hi, I'm the second",
|
||||||
|
"Hi, I'm the third"]
|
||||||
|
15
mediagoblin/tests/testplugins/__init__.py
Normal file
15
mediagoblin/tests/testplugins/__init__.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# GNU MediaGoblin -- federated, autonomous media hosting
|
||||||
|
# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
41
mediagoblin/tests/testplugins/callables1/__init__.py
Normal file
41
mediagoblin/tests/testplugins/callables1/__init__.py
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
# GNU MediaGoblin -- federated, autonomous media hosting
|
||||||
|
# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from mediagoblin.tools.pluginapi import CantHandleIt
|
||||||
|
|
||||||
|
def setup_plugin():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def just_one(call_log):
|
||||||
|
call_log.append("expect this one call")
|
||||||
|
return "Called just once"
|
||||||
|
|
||||||
|
|
||||||
|
def multi_handle(call_log):
|
||||||
|
call_log.append("Hi, I'm the first")
|
||||||
|
return "the first returns"
|
||||||
|
|
||||||
|
def multi_handle_with_canthandle(call_log):
|
||||||
|
raise CantHandleIt("I just can't accept this stupid method")
|
||||||
|
|
||||||
|
|
||||||
|
hooks = {
|
||||||
|
'setup': setup_plugin,
|
||||||
|
'just_one': just_one,
|
||||||
|
'multi_handle': multi_handle,
|
||||||
|
'multi_handle_with_canthandle': multi_handle_with_canthandle,
|
||||||
|
}
|
38
mediagoblin/tests/testplugins/callables2/__init__.py
Normal file
38
mediagoblin/tests/testplugins/callables2/__init__.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# GNU MediaGoblin -- federated, autonomous media hosting
|
||||||
|
# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
def setup_plugin():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def just_one(call_log):
|
||||||
|
assert "SHOULD NOT HAPPEN"
|
||||||
|
|
||||||
|
def multi_handle(call_log):
|
||||||
|
call_log.append("Hi, I'm the second")
|
||||||
|
return "the second returns"
|
||||||
|
|
||||||
|
def multi_handle_with_canthandle(call_log):
|
||||||
|
call_log.append("Hi, I'm the second")
|
||||||
|
return "the second returns"
|
||||||
|
|
||||||
|
|
||||||
|
hooks = {
|
||||||
|
'setup': setup_plugin,
|
||||||
|
'just_one': just_one,
|
||||||
|
'multi_handle': multi_handle,
|
||||||
|
'multi_handle_with_canthandle': multi_handle_with_canthandle,
|
||||||
|
}
|
38
mediagoblin/tests/testplugins/callables3/__init__.py
Normal file
38
mediagoblin/tests/testplugins/callables3/__init__.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# GNU MediaGoblin -- federated, autonomous media hosting
|
||||||
|
# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
def setup_plugin():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def just_one(call_log):
|
||||||
|
assert "SHOULD NOT HAPPEN"
|
||||||
|
|
||||||
|
def multi_handle(call_log):
|
||||||
|
call_log.append("Hi, I'm the third")
|
||||||
|
return "the third returns"
|
||||||
|
|
||||||
|
def multi_handle_with_canthandle(call_log):
|
||||||
|
call_log.append("Hi, I'm the third")
|
||||||
|
return "the third returns"
|
||||||
|
|
||||||
|
|
||||||
|
hooks = {
|
||||||
|
'setup': setup_plugin,
|
||||||
|
'just_one': just_one,
|
||||||
|
'multi_handle': multi_handle,
|
||||||
|
'multi_handle_with_canthandle': multi_handle_with_canthandle,
|
||||||
|
}
|
@ -272,3 +272,70 @@ def get_hook_templates(hook_name):
|
|||||||
A list of strings representing template paths.
|
A list of strings representing template paths.
|
||||||
"""
|
"""
|
||||||
return PluginManager().get_template_hooks(hook_name)
|
return PluginManager().get_template_hooks(hook_name)
|
||||||
|
|
||||||
|
|
||||||
|
###########################
|
||||||
|
# Callable convenience code
|
||||||
|
###########################
|
||||||
|
|
||||||
|
class CantHandleIt(Exception):
|
||||||
|
"""
|
||||||
|
A callable may call this method if they look at the relevant
|
||||||
|
arguments passed and decide it's not possible for them to handle
|
||||||
|
things.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
class UnhandledCallable(Exception):
|
||||||
|
"""
|
||||||
|
Raise this method if no callables were available to handle the
|
||||||
|
specified hook. Only used by callable_runone.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def callable_runone(hookname, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Run the callable hook HOOKNAME... run until the first response,
|
||||||
|
then return.
|
||||||
|
|
||||||
|
This function will run stop at the first hook that handles the
|
||||||
|
result. Hooks raising CantHandleIt will be skipped.
|
||||||
|
|
||||||
|
Unless unhandled_okay is True, this will error out if no hooks
|
||||||
|
have been registered to handle this function.
|
||||||
|
"""
|
||||||
|
callables = PluginManager().get_hook_callables(hookname)
|
||||||
|
|
||||||
|
unhandled_okay = kwargs.pop("unhandled_okay", False)
|
||||||
|
|
||||||
|
for callable in callables:
|
||||||
|
try:
|
||||||
|
return callable(*args, **kwargs)
|
||||||
|
except CantHandleIt:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if unhandled_okay is False:
|
||||||
|
raise UnhandledCallable(
|
||||||
|
"No hooks registered capable of handling '%s'" % hookname)
|
||||||
|
|
||||||
|
|
||||||
|
def callable_runall(hookname, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Run all callables for HOOKNAME.
|
||||||
|
|
||||||
|
This method will run *all* hooks that handle this method (skipping
|
||||||
|
those that raise CantHandleIt), and will return a list of all
|
||||||
|
results.
|
||||||
|
"""
|
||||||
|
callables = PluginManager().get_hook_callables(hookname)
|
||||||
|
|
||||||
|
results = []
|
||||||
|
|
||||||
|
for callable in callables:
|
||||||
|
try:
|
||||||
|
results.append(callable(*args, **kwargs))
|
||||||
|
except CantHandleIt:
|
||||||
|
continue
|
||||||
|
|
||||||
|
return results
|
||||||
|
Loading…
x
Reference in New Issue
Block a user