From 1a546f0240ada065b56029d33f76c83b9fdc801a Mon Sep 17 00:00:00 2001 From: Ryan Petrello Date: Mon, 1 Sep 2014 19:15:25 -0400 Subject: Fix a bug in generic function handling when context locals are disabled. Fixes bug 1364113 Change-Id: I192c75b73ae95338dc2f1ea019e83a42fb8da87b --- pecan/core.py | 20 +++++++++++----- pecan/tests/test_no_thread_locals.py | 45 ++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 6 deletions(-) diff --git a/pecan/core.py b/pecan/core.py index a52dae2..9174c50 100644 --- a/pecan/core.py +++ b/pecan/core.py @@ -684,15 +684,23 @@ class ExplicitPecan(PecanBase): # When comparing the argspec of the method to GET/POST params, # ignore the implicit (req, resp) at the beginning of the function # signature - signature_error = TypeError( - 'When `use_context_locals` is `False`, pecan passes an explicit ' - 'reference to the request and response as the first two arguments ' - 'to the controller.\nChange the `%s.%s.%s` signature to accept ' - 'exactly 2 initial arguments (req, resp)' % ( + if hasattr(state.controller, '__self__'): + _repr = '.'.join(( state.controller.__self__.__class__.__module__, state.controller.__self__.__class__.__name__, state.controller.__name__ - ) + )) + else: + _repr = '.'.join(( + state.controller.__module__, + state.controller.__name__ + )) + + signature_error = TypeError( + 'When `use_context_locals` is `False`, pecan passes an explicit ' + 'reference to the request and response as the first two arguments ' + 'to the controller.\nChange the `%s` signature to accept exactly ' + '2 initial arguments (req, resp)' % _repr ) try: positional = argspec.args[:] diff --git a/pecan/tests/test_no_thread_locals.py b/pecan/tests/test_no_thread_locals.py index e9fcf75..a114840 100644 --- a/pecan/tests/test_no_thread_locals.py +++ b/pecan/tests/test_no_thread_locals.py @@ -24,6 +24,21 @@ class TestThreadingLocalUsage(PecanTestCase): assert isinstance(resp, webob.Response) return 'Hello, World!' + @expose() + def warning(self): + return ("This should be unroutable because (req, resp) are not" + " arguments. It should raise a TypeError.") + + @expose(generic=True) + def generic(self): + return ("This should be unroutable because (req, resp) are not" + " arguments. It should raise a TypeError.") + + @generic.when(method='PUT') + def generic_put(self, _id): + return ("This should be unroutable because (req, resp) are not" + " arguments. It should raise a TypeError.") + return RootController def test_locals_are_not_used(self): @@ -36,6 +51,36 @@ class TestThreadingLocalUsage(PecanTestCase): self.assertRaises(AssertionError, Pecan, self.root) + def test_threadlocal_argument_warning(self): + with mock.patch('threading.local', side_effect=AssertionError()): + + app = TestApp(Pecan(self.root(), use_context_locals=False)) + self.assertRaises( + TypeError, + app.get, + '/warning/' + ) + + def test_threadlocal_argument_warning_on_generic(self): + with mock.patch('threading.local', side_effect=AssertionError()): + + app = TestApp(Pecan(self.root(), use_context_locals=False)) + self.assertRaises( + TypeError, + app.get, + '/generic/' + ) + + def test_threadlocal_argument_warning_on_generic_delegate(self): + with mock.patch('threading.local', side_effect=AssertionError()): + + app = TestApp(Pecan(self.root(), use_context_locals=False)) + self.assertRaises( + TypeError, + app.put, + '/generic/' + ) + class TestIndexRouting(PecanTestCase): -- cgit v1.2.1