Added support for mapping parameters in the URI to parameters for a

controller, including validation support.
This commit is contained in:
Jonathan LaCour
2010-10-22 09:57:27 -04:00
parent 0197aebd77
commit ced0eda4ba
2 changed files with 58 additions and 4 deletions

View File

@@ -71,7 +71,7 @@ class Pecan(object):
def route(self, node, path): def route(self, node, path):
path = path.split('/')[1:] path = path.split('/')[1:]
node, remainder = lookup_controller(node, path) node, remainder = lookup_controller(node, path)
return node return node, remainder
def handle_security(self, controller): def handle_security(self, controller):
if controller.pecan.get('secured', False): if controller.pecan.get('secured', False):
@@ -90,11 +90,20 @@ class Pecan(object):
for hook in state.hooks: for hook in state.hooks:
getattr(hook, hook_type)(*args) getattr(hook, hook_type)(*args)
def get_params(self, all_params, argspec): def get_params(self, all_params, remainder, argspec):
valid_params = dict() valid_params = dict()
# handle params that are POST or GET variables first
for param_name, param_value in all_params.iteritems(): for param_name, param_value in all_params.iteritems():
if param_name in argspec.args: if param_name in argspec.args:
valid_params[param_name] = param_value valid_params[param_name] = param_value
# handle positional arguments
for i, value in enumerate(remainder):
if len(argspec.args) > (i+1):
if valid_params.get(argspec.args[i+1]) is None:
valid_params[argspec.args[i+1]] = value
return valid_params return valid_params
def validate(self, schema, params=None, json=False): def validate(self, schema, params=None, json=False):
@@ -111,7 +120,7 @@ class Pecan(object):
if '.' in path.split('/')[-1]: if '.' in path.split('/')[-1]:
path, format = path.split('.') path, format = path.split('.')
content_type = self.get_content_type(format) content_type = self.get_content_type(format)
controller = self.route(self.root, path) controller, remainder = self.route(self.root, path)
# determine content type # determine content type
if content_type is None: if content_type is None:
@@ -129,6 +138,7 @@ class Pecan(object):
# fetch and validate any parameters # fetch and validate any parameters
params = self.get_params( params = self.get_params(
dict(state.request.str_params), dict(state.request.str_params),
remainder,
controller.pecan['argspec'] controller.pecan['argspec']
) )
if 'schema' in controller.pecan: if 'schema' in controller.pecan:

View File

@@ -1,5 +1,7 @@
from pecan import Pecan, expose, request, response, redirect from pecan import Pecan, expose, request, response, redirect
from webtest import TestApp from webtest import TestApp
from formencode import Schema, validators
class TestBase(object): class TestBase(object):
@@ -193,3 +195,45 @@ class TestEngines(object):
r = r.follow() r = r.follow()
assert r.status_int == 200 assert r.status_int == 200
assert r.body == 'it worked!' assert r.body == 'it worked!'
def test_uri_to_parameter_mapping(self):
class RootController(object):
@expose()
def test(self, one, two):
assert one == '1'
assert two == '2'
return 'it worked'
app = TestApp(Pecan(RootController()))
r = app.get('/test/1/2')
assert r.status_int == 200
assert r.body == 'it worked'
def test_uri_to_parameter_mapping_with_validation(self):
class TestSchema(Schema):
one = validators.Int(not_empty=True)
two = validators.Int(not_empty=True)
class RootController(object):
@expose(schema=TestSchema())
def test(self, one, two):
assert request.validation_error is None
assert one == 1
assert two == 2
return 'it worked'
@expose(schema=TestSchema())
def fail(self, one, two):
assert request.validation_error is not None
assert one == 'one'
assert two == 'two'
return 'it failed'
app = TestApp(Pecan(RootController()))
r = app.get('/test/1/2')
assert r.status_int == 200
assert r.body == 'it worked'
r = app.get('/fail/one/two')
assert r.status_int == 200
assert r.body == 'it failed'