Pecan makes abundant use of `inspect.getargspec`, but unless you're very meticulous in the decorators you wrap your controllers with, the original argspec is not persisted (and pecan functionality can break in various ways). When a controller is decorated in a way that breaks argspec, we should instead attempt to locate the *actual* argspec for the method (not the wrapped function) and use it. Additionally, when controllers are missing **kwargs in the method signature to map optional GET and POST arguments, we shouldn't consider that a non-routable offense (an HTTP 400); instead, we should just *not* pass extraneous arguments to the function. Change-Id: I47fe0496ff6aa105359ee8e5b99f6c80476cc2e9
69 lines
2.0 KiB
Python
69 lines
2.0 KiB
Python
import functools
|
|
import inspect
|
|
import unittest
|
|
|
|
from pecan import expose
|
|
from pecan import util
|
|
|
|
|
|
class TestArgSpec(unittest.TestCase):
|
|
|
|
@property
|
|
def controller(self):
|
|
|
|
class RootController(object):
|
|
|
|
@expose()
|
|
def index(self, a, b, c=1, *args, **kwargs):
|
|
return 'Hello, World!'
|
|
|
|
return RootController()
|
|
|
|
def test_no_decorator(self):
|
|
expected = inspect.getargspec(self.controller.index.__func__)
|
|
actual = util.getargspec(self.controller.index.__func__)
|
|
assert expected == actual
|
|
|
|
def test_simple_decorator(self):
|
|
def dec(f):
|
|
return f
|
|
|
|
expected = inspect.getargspec(self.controller.index.__func__)
|
|
actual = util.getargspec(dec(self.controller.index.__func__))
|
|
assert expected == actual
|
|
|
|
def test_simple_wrapper(self):
|
|
def dec(f):
|
|
@functools.wraps(f)
|
|
def wrapped(*a, **kw):
|
|
return f(*a, **kw)
|
|
return wrapped
|
|
|
|
expected = inspect.getargspec(self.controller.index.__func__)
|
|
actual = util.getargspec(dec(self.controller.index.__func__))
|
|
assert expected == actual
|
|
|
|
def test_multiple_decorators(self):
|
|
def dec(f):
|
|
@functools.wraps(f)
|
|
def wrapped(*a, **kw):
|
|
return f(*a, **kw)
|
|
return wrapped
|
|
|
|
expected = inspect.getargspec(self.controller.index.__func__)
|
|
actual = util.getargspec(dec(dec(dec(self.controller.index.__func__))))
|
|
assert expected == actual
|
|
|
|
def test_decorator_with_args(self):
|
|
def dec(flag):
|
|
def inner(f):
|
|
@functools.wraps(f)
|
|
def wrapped(*a, **kw):
|
|
return f(*a, **kw)
|
|
return wrapped
|
|
return inner
|
|
|
|
expected = inspect.getargspec(self.controller.index.__func__)
|
|
actual = util.getargspec(dec(True)(self.controller.index.__func__))
|
|
assert expected == actual
|