Provide pecan.state.arguments
for inspecting controller call arguments
Change-Id: Ibbd8b2f075a875b109c7309bc42e0d1f1d5ae610
This commit is contained in:
@@ -71,6 +71,10 @@ response objects, and which controller was selected by Pecan's routing::
|
||||
# and used to generate the response body
|
||||
#
|
||||
assert state.controller.__func__ is RootController.index.__func__
|
||||
assert isinstance(state.arguments, inspect.Arguments)
|
||||
print state.arguments.args
|
||||
print state.arguments.varargs
|
||||
print state.arguments.keywords
|
||||
assert isinstance(state.request, webob.Request)
|
||||
assert isinstance(state.response, webob.Response)
|
||||
assert isinstance(state.hooks, list)
|
||||
|
@@ -2,6 +2,7 @@ try:
|
||||
from simplejson import dumps, loads
|
||||
except ImportError: # pragma: no cover
|
||||
from json import dumps, loads # noqa
|
||||
from inspect import Arguments
|
||||
from itertools import chain, tee
|
||||
from mimetypes import guess_type, add_type
|
||||
from os.path import splitext
|
||||
@@ -31,12 +32,14 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
class RoutingState(object):
|
||||
|
||||
def __init__(self, request, response, app, hooks=[], controller=None):
|
||||
def __init__(self, request, response, app, hooks=[], controller=None,
|
||||
arguments=None):
|
||||
self.request = request
|
||||
self.response = response
|
||||
self.app = app
|
||||
self.hooks = hooks
|
||||
self.controller = controller
|
||||
self.arguments = arguments
|
||||
|
||||
|
||||
class Request(WebObRequest):
|
||||
@@ -326,6 +329,7 @@ class PecanBase(object):
|
||||
passed the argument specification for the controller.
|
||||
'''
|
||||
args = []
|
||||
varargs = []
|
||||
kwargs = dict()
|
||||
valid_args = argspec.args[1:] # pop off `self`
|
||||
pecan_state = state.request.pecan
|
||||
@@ -354,7 +358,7 @@ class PecanBase(object):
|
||||
if [i for i in remainder if i]:
|
||||
if not argspec[1]:
|
||||
abort(404)
|
||||
args.extend(remainder)
|
||||
varargs.extend(remainder)
|
||||
|
||||
# get the default positional arguments
|
||||
if argspec[3]:
|
||||
@@ -377,7 +381,7 @@ class PecanBase(object):
|
||||
if name not in argspec[0]:
|
||||
kwargs[encode_if_needed(name)] = value
|
||||
|
||||
return args, kwargs
|
||||
return args, varargs, kwargs
|
||||
|
||||
def render(self, template, namespace):
|
||||
renderer = self.renderers.get(
|
||||
@@ -492,9 +496,6 @@ class PecanBase(object):
|
||||
)
|
||||
raise exc.HTTPNotFound
|
||||
|
||||
# handle "before" hooks
|
||||
self.handle_hooks(self.determine_hooks(controller), 'before', state)
|
||||
|
||||
# fetch any parameters
|
||||
if req.method == 'GET':
|
||||
params = dict(req.GET)
|
||||
@@ -502,15 +503,19 @@ class PecanBase(object):
|
||||
params = dict(req.params)
|
||||
|
||||
# fetch the arguments for the controller
|
||||
args, kwargs = self.get_args(
|
||||
args, varargs, kwargs = self.get_args(
|
||||
state,
|
||||
params,
|
||||
remainder,
|
||||
cfg['argspec'],
|
||||
im_self
|
||||
)
|
||||
state.arguments = Arguments(args, varargs, kwargs)
|
||||
|
||||
return controller, args, kwargs
|
||||
# handle "before" hooks
|
||||
self.handle_hooks(self.determine_hooks(controller), 'before', state)
|
||||
|
||||
return controller, args+varargs, kwargs
|
||||
|
||||
def invoke_controller(self, controller, args, kwargs, state):
|
||||
'''
|
||||
@@ -691,11 +696,11 @@ class ExplicitPecan(PecanBase):
|
||||
except IndexError:
|
||||
raise signature_error
|
||||
|
||||
args, kwargs = super(ExplicitPecan, self).get_args(
|
||||
args, varargs, kwargs = super(ExplicitPecan, self).get_args(
|
||||
state, all_params, remainder, argspec, im_self
|
||||
)
|
||||
args = [state.request, state.response] + args
|
||||
return args, kwargs
|
||||
return args, varargs, kwargs
|
||||
|
||||
|
||||
class Pecan(PecanBase):
|
||||
@@ -747,12 +752,14 @@ class Pecan(PecanBase):
|
||||
state.hooks = []
|
||||
state.app = self
|
||||
state.controller = None
|
||||
state.arguments = None
|
||||
return super(Pecan, self).__call__(environ, start_response)
|
||||
finally:
|
||||
del state.hooks
|
||||
del state.request
|
||||
del state.response
|
||||
del state.controller
|
||||
del state.arguments
|
||||
del state.app
|
||||
|
||||
def init_context_local(self, local_factory):
|
||||
@@ -766,6 +773,7 @@ class Pecan(PecanBase):
|
||||
state.response = _state.response
|
||||
controller, args, kw = super(Pecan, self).find_controller(_state)
|
||||
state.controller = controller
|
||||
state.arguments = _state.arguments
|
||||
return controller, args, kw
|
||||
|
||||
def handle_hooks(self, hooks, *args, **kw):
|
||||
|
@@ -1,11 +1,13 @@
|
||||
import inspect
|
||||
import operator
|
||||
|
||||
from webtest import TestApp
|
||||
from six import PY3
|
||||
from six import b as b_
|
||||
from six import u as u_
|
||||
from six.moves import cStringIO as StringIO
|
||||
|
||||
from webob import Response
|
||||
|
||||
from pecan import make_app, expose, redirect, abort
|
||||
from pecan import make_app, expose, redirect, abort, rest, Request, Response
|
||||
from pecan.hooks import (
|
||||
PecanHook, TransactionHook, HookController, RequestViewerHook
|
||||
)
|
||||
@@ -13,6 +15,9 @@ from pecan.configuration import Config
|
||||
from pecan.decorators import transactional, after_commit, after_rollback
|
||||
from pecan.tests import PecanTestCase
|
||||
|
||||
# The `inspect.Arguments` namedtuple is different between PY2/3
|
||||
kwargs = operator.attrgetter('varkw' if PY3 else 'keywords')
|
||||
|
||||
|
||||
class TestHooks(PecanTestCase):
|
||||
|
||||
@@ -412,6 +417,364 @@ class TestHooks(PecanTestCase):
|
||||
assert run_hook[3] == 'last - before hook', run_hook[3]
|
||||
|
||||
|
||||
class TestStateAccess(PecanTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestStateAccess, self).setUp()
|
||||
self.args = None
|
||||
|
||||
class RootController(object):
|
||||
@expose()
|
||||
def index(self):
|
||||
return 'Hello, World!'
|
||||
|
||||
@expose()
|
||||
def greet(self, name):
|
||||
return 'Hello, %s!' % name
|
||||
|
||||
@expose()
|
||||
def greetmore(self, *args):
|
||||
return 'Hello, %s!' % args[0]
|
||||
|
||||
@expose()
|
||||
def kwargs(self, **kw):
|
||||
return 'Hello, %s!' % kw['name']
|
||||
|
||||
@expose()
|
||||
def mixed(self, first, second, *args):
|
||||
return 'Mixed'
|
||||
|
||||
class SimpleHook(PecanHook):
|
||||
def before(inself, state):
|
||||
self.args = (state.controller, state.arguments)
|
||||
|
||||
self.root = RootController()
|
||||
self.app = TestApp(make_app(self.root, hooks=[SimpleHook()]))
|
||||
|
||||
def test_no_args(self):
|
||||
self.app.get('/')
|
||||
assert self.args[0] == self.root.index
|
||||
assert isinstance(self.args[1], inspect.Arguments)
|
||||
assert self.args[1].args == []
|
||||
assert self.args[1].varargs == []
|
||||
assert kwargs(self.args[1]) == {}
|
||||
|
||||
def test_single_arg(self):
|
||||
self.app.get('/greet/joe')
|
||||
assert self.args[0] == self.root.greet
|
||||
assert isinstance(self.args[1], inspect.Arguments)
|
||||
assert self.args[1].args == ['joe']
|
||||
assert self.args[1].varargs == []
|
||||
assert kwargs(self.args[1]) == {}
|
||||
|
||||
def test_single_vararg(self):
|
||||
self.app.get('/greetmore/joe')
|
||||
assert self.args[0] == self.root.greetmore
|
||||
assert isinstance(self.args[1], inspect.Arguments)
|
||||
assert self.args[1].args == []
|
||||
assert self.args[1].varargs == ['joe']
|
||||
assert kwargs(self.args[1]) == {}
|
||||
|
||||
def test_single_kw(self):
|
||||
self.app.get('/kwargs/?name=joe')
|
||||
assert self.args[0] == self.root.kwargs
|
||||
assert isinstance(self.args[1], inspect.Arguments)
|
||||
assert self.args[1].args == []
|
||||
assert self.args[1].varargs == []
|
||||
assert kwargs(self.args[1]) == {'name': 'joe'}
|
||||
|
||||
def test_single_kw_post(self):
|
||||
self.app.post('/kwargs/', params={'name': 'joe'})
|
||||
assert self.args[0] == self.root.kwargs
|
||||
assert isinstance(self.args[1], inspect.Arguments)
|
||||
assert self.args[1].args == []
|
||||
assert self.args[1].varargs == []
|
||||
assert kwargs(self.args[1]) == {'name': 'joe'}
|
||||
|
||||
def test_mixed_args(self):
|
||||
self.app.get('/mixed/foo/bar/spam/eggs')
|
||||
assert self.args[0] == self.root.mixed
|
||||
assert isinstance(self.args[1], inspect.Arguments)
|
||||
assert self.args[1].args == ['foo', 'bar']
|
||||
assert self.args[1].varargs == ['spam', 'eggs']
|
||||
|
||||
|
||||
class TestStateAccessWithoutThreadLocals(PecanTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestStateAccessWithoutThreadLocals, self).setUp()
|
||||
self.args = None
|
||||
|
||||
class RootController(object):
|
||||
@expose()
|
||||
def index(self, req, resp):
|
||||
return 'Hello, World!'
|
||||
|
||||
@expose()
|
||||
def greet(self, req, resp, name):
|
||||
return 'Hello, %s!' % name
|
||||
|
||||
@expose()
|
||||
def greetmore(self, req, resp, *args):
|
||||
return 'Hello, %s!' % args[0]
|
||||
|
||||
@expose()
|
||||
def kwargs(self, req, resp, **kw):
|
||||
return 'Hello, %s!' % kw['name']
|
||||
|
||||
@expose()
|
||||
def mixed(self, req, resp, first, second, *args):
|
||||
return 'Mixed'
|
||||
|
||||
class SimpleHook(PecanHook):
|
||||
def before(inself, state):
|
||||
self.args = (state.controller, state.arguments)
|
||||
|
||||
self.root = RootController()
|
||||
self.app = TestApp(make_app(
|
||||
self.root,
|
||||
hooks=[SimpleHook()],
|
||||
use_context_locals=False
|
||||
))
|
||||
|
||||
def test_no_args(self):
|
||||
self.app.get('/')
|
||||
assert self.args[0] == self.root.index
|
||||
assert isinstance(self.args[1], inspect.Arguments)
|
||||
assert len(self.args[1].args) == 2
|
||||
assert isinstance(self.args[1].args[0], Request)
|
||||
assert isinstance(self.args[1].args[1], Response)
|
||||
assert self.args[1].varargs == []
|
||||
assert kwargs(self.args[1]) == {}
|
||||
|
||||
def test_single_arg(self):
|
||||
self.app.get('/greet/joe')
|
||||
assert self.args[0] == self.root.greet
|
||||
assert isinstance(self.args[1], inspect.Arguments)
|
||||
assert len(self.args[1].args) == 3
|
||||
assert isinstance(self.args[1].args[0], Request)
|
||||
assert isinstance(self.args[1].args[1], Response)
|
||||
assert self.args[1].args[2] == 'joe'
|
||||
assert self.args[1].varargs == []
|
||||
assert kwargs(self.args[1]) == {}
|
||||
|
||||
def test_single_vararg(self):
|
||||
self.app.get('/greetmore/joe')
|
||||
assert self.args[0] == self.root.greetmore
|
||||
assert isinstance(self.args[1], inspect.Arguments)
|
||||
assert len(self.args[1].args) == 2
|
||||
assert isinstance(self.args[1].args[0], Request)
|
||||
assert isinstance(self.args[1].args[1], Response)
|
||||
assert self.args[1].varargs == ['joe']
|
||||
assert kwargs(self.args[1]) == {}
|
||||
|
||||
def test_single_kw(self):
|
||||
self.app.get('/kwargs/?name=joe')
|
||||
assert self.args[0] == self.root.kwargs
|
||||
assert isinstance(self.args[1], inspect.Arguments)
|
||||
assert len(self.args[1].args) == 2
|
||||
assert isinstance(self.args[1].args[0], Request)
|
||||
assert isinstance(self.args[1].args[1], Response)
|
||||
assert self.args[1].varargs == []
|
||||
assert kwargs(self.args[1]) == {'name': 'joe'}
|
||||
|
||||
def test_single_kw_post(self):
|
||||
self.app.post('/kwargs/', params={'name': 'joe'})
|
||||
assert self.args[0] == self.root.kwargs
|
||||
assert isinstance(self.args[1], inspect.Arguments)
|
||||
assert len(self.args[1].args) == 2
|
||||
assert isinstance(self.args[1].args[0], Request)
|
||||
assert isinstance(self.args[1].args[1], Response)
|
||||
assert self.args[1].varargs == []
|
||||
assert kwargs(self.args[1]) == {'name': 'joe'}
|
||||
|
||||
def test_mixed_args(self):
|
||||
self.app.get('/mixed/foo/bar/spam/eggs')
|
||||
assert self.args[0] == self.root.mixed
|
||||
assert isinstance(self.args[1], inspect.Arguments)
|
||||
assert len(self.args[1].args) == 4
|
||||
assert isinstance(self.args[1].args[0], Request)
|
||||
assert isinstance(self.args[1].args[1], Response)
|
||||
assert self.args[1].args[2:] == ['foo', 'bar']
|
||||
assert self.args[1].varargs == ['spam', 'eggs']
|
||||
|
||||
|
||||
class TestRestControllerStateAccess(PecanTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestRestControllerStateAccess, self).setUp()
|
||||
self.args = None
|
||||
|
||||
class RootController(rest.RestController):
|
||||
|
||||
@expose()
|
||||
def _default(self, _id, *args, **kw):
|
||||
return 'Default'
|
||||
|
||||
@expose()
|
||||
def get_all(self, **kw):
|
||||
return 'All'
|
||||
|
||||
@expose()
|
||||
def get_one(self, _id, *args, **kw):
|
||||
return 'One'
|
||||
|
||||
@expose()
|
||||
def post(self, *args, **kw):
|
||||
return 'POST'
|
||||
|
||||
@expose()
|
||||
def put(self, _id, *args, **kw):
|
||||
return 'PUT'
|
||||
|
||||
@expose()
|
||||
def delete(self, _id, *args, **kw):
|
||||
return 'DELETE'
|
||||
|
||||
class SimpleHook(PecanHook):
|
||||
def before(inself, state):
|
||||
self.args = (state.controller, state.arguments)
|
||||
|
||||
self.root = RootController()
|
||||
self.app = TestApp(make_app(self.root, hooks=[SimpleHook()]))
|
||||
|
||||
def test_get_all(self):
|
||||
self.app.get('/')
|
||||
assert self.args[0] == self.root.get_all
|
||||
assert isinstance(self.args[1], inspect.Arguments)
|
||||
assert self.args[1].args == []
|
||||
assert self.args[1].varargs == []
|
||||
assert kwargs(self.args[1]) == {}
|
||||
|
||||
def test_get_all_with_kwargs(self):
|
||||
self.app.get('/?foo=bar')
|
||||
assert self.args[0] == self.root.get_all
|
||||
assert isinstance(self.args[1], inspect.Arguments)
|
||||
assert self.args[1].args == []
|
||||
assert self.args[1].varargs == []
|
||||
assert kwargs(self.args[1]) == {'foo': 'bar'}
|
||||
|
||||
def test_get_one(self):
|
||||
self.app.get('/1')
|
||||
assert self.args[0] == self.root.get_one
|
||||
assert isinstance(self.args[1], inspect.Arguments)
|
||||
assert self.args[1].args == ['1']
|
||||
assert self.args[1].varargs == []
|
||||
assert kwargs(self.args[1]) == {}
|
||||
|
||||
def test_get_one_with_varargs(self):
|
||||
self.app.get('/1/2/3')
|
||||
assert self.args[0] == self.root.get_one
|
||||
assert isinstance(self.args[1], inspect.Arguments)
|
||||
assert self.args[1].args == ['1']
|
||||
assert self.args[1].varargs == ['2', '3']
|
||||
assert kwargs(self.args[1]) == {}
|
||||
|
||||
def test_get_one_with_kwargs(self):
|
||||
self.app.get('/1?foo=bar')
|
||||
assert self.args[0] == self.root.get_one
|
||||
assert isinstance(self.args[1], inspect.Arguments)
|
||||
assert self.args[1].args == ['1']
|
||||
assert self.args[1].varargs == []
|
||||
assert kwargs(self.args[1]) == {'foo': 'bar'}
|
||||
|
||||
def test_post(self):
|
||||
self.app.post('/')
|
||||
assert self.args[0] == self.root.post
|
||||
assert isinstance(self.args[1], inspect.Arguments)
|
||||
assert self.args[1].args == []
|
||||
assert self.args[1].varargs == []
|
||||
assert kwargs(self.args[1]) == {}
|
||||
|
||||
def test_post_with_varargs(self):
|
||||
self.app.post('/foo/bar')
|
||||
assert self.args[0] == self.root.post
|
||||
assert isinstance(self.args[1], inspect.Arguments)
|
||||
assert self.args[1].args == []
|
||||
assert self.args[1].varargs == ['foo', 'bar']
|
||||
assert kwargs(self.args[1]) == {}
|
||||
|
||||
def test_post_with_kwargs(self):
|
||||
self.app.post('/', params={'foo': 'bar'})
|
||||
assert self.args[0] == self.root.post
|
||||
assert isinstance(self.args[1], inspect.Arguments)
|
||||
assert self.args[1].args == []
|
||||
assert self.args[1].varargs == []
|
||||
assert kwargs(self.args[1]) == {'foo': 'bar'}
|
||||
|
||||
def test_put(self):
|
||||
self.app.put('/1')
|
||||
assert self.args[0] == self.root.put
|
||||
assert isinstance(self.args[1], inspect.Arguments)
|
||||
assert self.args[1].args == ['1']
|
||||
assert self.args[1].varargs == []
|
||||
assert kwargs(self.args[1]) == {}
|
||||
|
||||
def test_put_with_method_argument(self):
|
||||
self.app.post('/1?_method=put')
|
||||
assert self.args[0] == self.root.put
|
||||
assert isinstance(self.args[1], inspect.Arguments)
|
||||
assert self.args[1].args == ['1']
|
||||
assert self.args[1].varargs == []
|
||||
assert kwargs(self.args[1]) == {'_method': 'put'}
|
||||
|
||||
def test_put_with_varargs(self):
|
||||
self.app.put('/1/2/3')
|
||||
assert self.args[0] == self.root.put
|
||||
assert isinstance(self.args[1], inspect.Arguments)
|
||||
assert self.args[1].args == ['1']
|
||||
assert self.args[1].varargs == ['2', '3']
|
||||
assert kwargs(self.args[1]) == {}
|
||||
|
||||
def test_put_with_kwargs(self):
|
||||
self.app.put('/1?foo=bar')
|
||||
assert self.args[0] == self.root.put
|
||||
assert isinstance(self.args[1], inspect.Arguments)
|
||||
assert self.args[1].args == ['1']
|
||||
assert self.args[1].varargs == []
|
||||
assert kwargs(self.args[1]) == {'foo': 'bar'}
|
||||
|
||||
def test_delete(self):
|
||||
self.app.delete('/1')
|
||||
assert self.args[0] == self.root.delete
|
||||
assert isinstance(self.args[1], inspect.Arguments)
|
||||
assert self.args[1].args == ['1']
|
||||
assert self.args[1].varargs == []
|
||||
assert kwargs(self.args[1]) == {}
|
||||
|
||||
def test_delete_with_method_argument(self):
|
||||
self.app.post('/1?_method=delete')
|
||||
assert self.args[0] == self.root.delete
|
||||
assert isinstance(self.args[1], inspect.Arguments)
|
||||
assert self.args[1].args == ['1']
|
||||
assert self.args[1].varargs == []
|
||||
assert kwargs(self.args[1]) == {'_method': 'delete'}
|
||||
|
||||
def test_delete_with_varargs(self):
|
||||
self.app.delete('/1/2/3')
|
||||
assert self.args[0] == self.root.delete
|
||||
assert isinstance(self.args[1], inspect.Arguments)
|
||||
assert self.args[1].args == ['1']
|
||||
assert self.args[1].varargs == ['2', '3']
|
||||
assert kwargs(self.args[1]) == {}
|
||||
|
||||
def test_delete_with_kwargs(self):
|
||||
self.app.delete('/1?foo=bar')
|
||||
assert self.args[0] == self.root.delete
|
||||
assert isinstance(self.args[1], inspect.Arguments)
|
||||
assert self.args[1].args == ['1']
|
||||
assert self.args[1].varargs == []
|
||||
assert kwargs(self.args[1]) == {'foo': 'bar'}
|
||||
|
||||
def test_post_with_invalid_method_kwarg(self):
|
||||
self.app.post('/1?_method=invalid')
|
||||
assert self.args[0] == self.root._default
|
||||
assert isinstance(self.args[1], inspect.Arguments)
|
||||
assert self.args[1].args == ['1']
|
||||
assert self.args[1].varargs == []
|
||||
assert kwargs(self.args[1]) == {'_method': 'invalid'}
|
||||
|
||||
|
||||
class TestTransactionHook(PecanTestCase):
|
||||
def test_transaction_hook(self):
|
||||
run_hook = []
|
||||
|
Reference in New Issue
Block a user