Fix an infinite recursion error in PecanHook application.

Subclassing both `rest.RestController` and `hooks.HookController` results in an
infinite recursion error in hook application (which prevents your application
from starting).

Fixes bug 1357540

Change-Id: I6e26c6d8771b4b35943bfb85bf41e73d0982e74c
This commit is contained in:
Ryan Petrello
2014-08-15 16:20:11 -04:00
parent 01c9a110fc
commit 11703d3740
2 changed files with 50 additions and 1 deletions

View File

@@ -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)

View File

@@ -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'