Added support for mapping parameters in the URI to parameters for a
controller, including validation support.
This commit is contained in:
		@@ -71,7 +71,7 @@ class Pecan(object):
 | 
			
		||||
    def route(self, node, path):
 | 
			
		||||
        path = path.split('/')[1:]
 | 
			
		||||
        node, remainder = lookup_controller(node, path)        
 | 
			
		||||
        return node
 | 
			
		||||
        return node, remainder
 | 
			
		||||
    
 | 
			
		||||
    def handle_security(self, controller):
 | 
			
		||||
        if controller.pecan.get('secured', False):
 | 
			
		||||
@@ -90,11 +90,20 @@ class Pecan(object):
 | 
			
		||||
        for hook in state.hooks:
 | 
			
		||||
            getattr(hook, hook_type)(*args)
 | 
			
		||||
    
 | 
			
		||||
    def get_params(self, all_params, argspec):
 | 
			
		||||
    def get_params(self, all_params, remainder, argspec):
 | 
			
		||||
        valid_params = dict()
 | 
			
		||||
        
 | 
			
		||||
        # handle params that are POST or GET variables first
 | 
			
		||||
        for param_name, param_value in all_params.iteritems():
 | 
			
		||||
            if param_name in argspec.args:
 | 
			
		||||
                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
 | 
			
		||||
    
 | 
			
		||||
    def validate(self, schema, params=None, json=False):
 | 
			
		||||
@@ -111,7 +120,7 @@ class Pecan(object):
 | 
			
		||||
        if '.' in path.split('/')[-1]:
 | 
			
		||||
            path, format = path.split('.')
 | 
			
		||||
            content_type = self.get_content_type(format)      
 | 
			
		||||
        controller = self.route(self.root, path)
 | 
			
		||||
        controller, remainder = self.route(self.root, path)
 | 
			
		||||
    
 | 
			
		||||
        # determine content type
 | 
			
		||||
        if content_type is None:
 | 
			
		||||
@@ -129,6 +138,7 @@ class Pecan(object):
 | 
			
		||||
        # fetch and validate any parameters
 | 
			
		||||
        params = self.get_params(
 | 
			
		||||
            dict(state.request.str_params), 
 | 
			
		||||
            remainder,
 | 
			
		||||
            controller.pecan['argspec']
 | 
			
		||||
        )
 | 
			
		||||
        if 'schema' in controller.pecan:
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,7 @@
 | 
			
		||||
from pecan import Pecan, expose, request, response, redirect
 | 
			
		||||
from webtest import TestApp
 | 
			
		||||
from formencode import Schema, validators
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestBase(object):
 | 
			
		||||
    
 | 
			
		||||
@@ -193,3 +195,45 @@ class TestEngines(object):
 | 
			
		||||
        r = r.follow()
 | 
			
		||||
        assert r.status_int == 200
 | 
			
		||||
        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'
 | 
			
		||||
		Reference in New Issue
	
	Block a user