diff options
author | Ryan Petrello <lists@ryanpetrello.com> | 2014-11-20 19:41:33 -0500 |
---|---|---|
committer | Ryan Petrello <lists@ryanpetrello.com> | 2014-11-20 21:40:35 -0500 |
commit | 9dbd23b33ecdeae3d93498b764952aeb0fd6560e (patch) | |
tree | bfcc56036c47aef7cbfbbf9d3f6b76ed3b504a6d | |
parent | 0fe902734d5f17d5f224e31850c5670e8a03e1ec (diff) | |
download | pecan-9dbd23b33ecdeae3d93498b764952aeb0fd6560e.tar.gz |
Improve detection of infinite recursion for PecanHook and pypy.
Fixes bug 1394344
Change-Id: I1c33598c4187e92f48691a8b6ef0663b09ce7240
-rw-r--r-- | pecan/hooks.py | 19 | ||||
-rw-r--r-- | pecan/tests/test_hooks.py | 13 |
2 files changed, 29 insertions, 3 deletions
diff --git a/pecan/hooks.py b/pecan/hooks.py index f1f7073..0b666d3 100644 --- a/pecan/hooks.py +++ b/pecan/hooks.py @@ -2,6 +2,7 @@ import types import sys from inspect import getmembers +import six from webob.exc import HTTPFound from .util import iscontroller, _cfg @@ -12,8 +13,20 @@ __all__ = [ ] -def walk_controller(root_class, controller, hooks): - if not isinstance(controller, (int, dict)): +def walk_controller(root_class, controller, hooks, seen=None): + seen = seen or set() + if type(controller) not in vars(six.moves.builtins).values(): + # Avoid recursion loops + try: + if controller in seen: + return + seen.add(controller) + except TypeError: + # If we discover an unhashable item (like a list), it's not + # something that we want to traverse because it's not the sort of + # thing we would add a hook to + return + for hook in getattr(controller, '__hooks__', []): # Append hooks from controller class definition hooks.add(hook) @@ -38,7 +51,7 @@ def walk_controller(root_class, controller, hooks): value.im_class.mro()[1:])) ): continue - walk_controller(root_class, value, hooks) + walk_controller(root_class, value, hooks, seen) class HookControllerMeta(type): diff --git a/pecan/tests/test_hooks.py b/pecan/tests/test_hooks.py index d3fe05b..a15368e 100644 --- a/pecan/tests/test_hooks.py +++ b/pecan/tests/test_hooks.py @@ -1681,6 +1681,19 @@ class TestRestControllerWithHooks(PecanTestCase): def get_all(self): return 'Hello, World!' + @staticmethod + def static(cls): + return 'static' + + @property + def foo(self): + return 'bar' + + def testing123(self): + return 'bar' + + unhashable = [1, 'two', 3] + app = TestApp( make_app( RootController() |