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:
@@ -1,3 +1,4 @@
|
|||||||
|
import types
|
||||||
import sys
|
import sys
|
||||||
from inspect import getmembers
|
from inspect import getmembers
|
||||||
|
|
||||||
@@ -27,7 +28,15 @@ def walk_controller(root_class, controller, hooks):
|
|||||||
for hook in hooks:
|
for hook in hooks:
|
||||||
value._pecan.setdefault('hooks', set()).add(hook)
|
value._pecan.setdefault('hooks', set()).add(hook)
|
||||||
elif hasattr(value, '__class__'):
|
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
|
continue
|
||||||
walk_controller(root_class, value, hooks)
|
walk_controller(root_class, value, hooks)
|
||||||
|
|
||||||
|
@@ -1656,3 +1656,43 @@ class TestRequestViewerHook(PecanTestCase):
|
|||||||
viewer = RequestViewerHook(conf)
|
viewer = RequestViewerHook(conf)
|
||||||
|
|
||||||
assert viewer.items == ['url']
|
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'
|
||||||
|
Reference in New Issue
Block a user