diff options
-rw-r--r-- | pecan/hooks.py | 11 | ||||
-rw-r--r-- | pecan/tests/test_hooks.py | 40 |
2 files changed, 50 insertions, 1 deletions
diff --git a/pecan/hooks.py b/pecan/hooks.py index 57392d7..f1f7073 100644 --- a/pecan/hooks.py +++ b/pecan/hooks.py @@ -1,3 +1,4 @@ +import types import sys from inspect import getmembers @@ -27,7 +28,15 @@ def walk_controller(root_class, controller, hooks): for hook in hooks: value._pecan.setdefault('hooks', set()).add(hook) elif hasattr(value, '__class__'): - if name.startswith('__') and name.endswith('__'): + # Skip non-exposed methods that are defined in parent classes; + # they're internal implementation details of that class, and + # not actual routable controllers, so we shouldn't bother + # assigning hooks to them. + if ( + isinstance(value, types.MethodType) and + any(filter(lambda c: value.__func__ in c.__dict__.values(), + value.im_class.mro()[1:])) + ): continue walk_controller(root_class, value, hooks) diff --git a/pecan/tests/test_hooks.py b/pecan/tests/test_hooks.py index 0bfd216..d3fe05b 100644 --- a/pecan/tests/test_hooks.py +++ b/pecan/tests/test_hooks.py @@ -1656,3 +1656,43 @@ class TestRequestViewerHook(PecanTestCase): viewer = RequestViewerHook(conf) assert viewer.items == ['url'] + + +class TestRestControllerWithHooks(PecanTestCase): + + def test_restcontroller_with_hooks(self): + + class SomeHook(PecanHook): + + def before(self, state): + state.response.headers['X-Testing'] = 'XYZ' + + class BaseController(rest.RestController): + + @expose() + def delete(self, _id): + return 'Deleting %s' % _id + + class RootController(BaseController, HookController): + + __hooks__ = [SomeHook()] + + @expose() + def get_all(self): + return 'Hello, World!' + + app = TestApp( + make_app( + RootController() + ) + ) + + response = app.get('/') + assert response.status_int == 200 + assert response.body == b_('Hello, World!') + assert response.headers['X-Testing'] == 'XYZ' + + response = app.delete('/100/') + assert response.status_int == 200 + assert response.body == b_('Deleting 100') + assert response.headers['X-Testing'] == 'XYZ' |