Removing formencode and the built-in validation functionality.
Eventually, we'll replace formencode w/ something else (that's still being actively maintained).
This commit is contained in:
		@@ -157,15 +157,9 @@ This is how it looks in the project template
 | 
				
			|||||||
(``test_project.controllers.root.RootController``)::
 | 
					(``test_project.controllers.root.RootController``)::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    from pecan import expose
 | 
					    from pecan import expose
 | 
				
			||||||
    from formencode import Schema, validators as v
 | 
					 | 
				
			||||||
    from webob.exc import status_map
 | 
					    from webob.exc import status_map
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class SampleForm(Schema):
 | 
					 | 
				
			||||||
        name = v.String(not_empty=True)
 | 
					 | 
				
			||||||
        age = v.Int(not_empty=True)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    class RootController(object):
 | 
					    class RootController(object):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        @expose(
 | 
					        @expose(
 | 
				
			||||||
@@ -175,13 +169,7 @@ This is how it looks in the project template
 | 
				
			|||||||
        def index(self):
 | 
					        def index(self):
 | 
				
			||||||
            return dict()
 | 
					            return dict()
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        @index.when(
 | 
					        @index.when(method='POST')
 | 
				
			||||||
            method          = 'POST',
 | 
					 | 
				
			||||||
            template        = 'success.html',
 | 
					 | 
				
			||||||
            schema          = SampleForm(),
 | 
					 | 
				
			||||||
            error_handler   = '/index',
 | 
					 | 
				
			||||||
            htmlfill        = dict(auto_insert_errors = True, prefix_error = False)
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        def index_post(self, name, age):
 | 
					        def index_post(self, name, age):
 | 
				
			||||||
            return dict(name=name)
 | 
					            return dict(name=name)
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -178,11 +178,6 @@ parameters, some of which can impact routing.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    expose(template        = None,
 | 
					    expose(template        = None,
 | 
				
			||||||
           content_type    = 'text/html',
 | 
					           content_type    = 'text/html',
 | 
				
			||||||
           schema          = None,
 | 
					 | 
				
			||||||
           json_schema     = None,
 | 
					 | 
				
			||||||
           variable_decode = False,
 | 
					 | 
				
			||||||
           error_handler   = None,
 | 
					 | 
				
			||||||
           htmlfill        = None,
 | 
					 | 
				
			||||||
           generic         = False)
 | 
					           generic         = False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,166 +2,5 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
Validation and Error Handling
 | 
					Validation and Error Handling
 | 
				
			||||||
=============================
 | 
					=============================
 | 
				
			||||||
Pecan provides a variety of tools to help you handle common form validation and
 | 
					TODO: Rewrite this (potentially as an extension/cookbook) to illustrate the
 | 
				
			||||||
error handling activities, like:
 | 
					new technique (without formencode).
 | 
				
			||||||
 | 
					 | 
				
			||||||
* Validating the presence of submitted form contents with a schema.
 | 
					 | 
				
			||||||
* Transforming strings from form submissions into useful Python objects.
 | 
					 | 
				
			||||||
* Simplifying the process of re-displaying form values and associated error messages inline.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Rather than re-inventing the wheel, Pecan uses `FormEncode <http://formencode.org/>`_ for schemas and form validation.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Writing and Applying Schemas
 | 
					 | 
				
			||||||
------------------------------
 | 
					 | 
				
			||||||
Here's a simple example of a schema and how to apply it to a controller method using
 | 
					 | 
				
			||||||
Pecan's ``expose`` decorator::
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    from pecan import expose
 | 
					 | 
				
			||||||
    from formencode import Schema, validators as v
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    class SimpleSchema(Schema):    
 | 
					 | 
				
			||||||
        username = v.String(not_empty=True)
 | 
					 | 
				
			||||||
        password = v.String(not_empty=True)
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
    class LoginController(object):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        @expose(schema=SimpleSchema)
 | 
					 | 
				
			||||||
        def login(self, **kw):
 | 
					 | 
				
			||||||
            if authenticate(
 | 
					 | 
				
			||||||
              kw['username'],
 | 
					 | 
				
			||||||
              kw['password']
 | 
					 | 
				
			||||||
            ):
 | 
					 | 
				
			||||||
              set_cookie()
 | 
					 | 
				
			||||||
            return dict()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Validating JSON Content
 | 
					 | 
				
			||||||
------------------------------
 | 
					 | 
				
			||||||
In addition to simple form arguments, Pecan also makes it easy to validate JSON request bodies.
 | 
					 | 
				
			||||||
Often, especially in AJAX requests, the request content is encoded as JSON in the request body.
 | 
					 | 
				
			||||||
Pecan's validation can handle the decoding for you and apply schema validation to the decoded
 | 
					 | 
				
			||||||
data structure::
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    from pecan import expose
 | 
					 | 
				
			||||||
    from formencode import Schema, validators as v
 | 
					 | 
				
			||||||
    from myproject.lib import authenticate
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    class JSONSchema(Schema):
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        This schema would decode a JSON request body
 | 
					 | 
				
			||||||
        that looked like:
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          'username' : 'pecan',
 | 
					 | 
				
			||||||
          'password' : 'dotpy
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        username = v.String(not_empty=True)
 | 
					 | 
				
			||||||
        password = v.String(not_empty=True)
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    class LoginController(object):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        @expose(json_schema=JSONSchema)
 | 
					 | 
				
			||||||
        def login(self, **kw):
 | 
					 | 
				
			||||||
            authenticate(
 | 
					 | 
				
			||||||
              kw['username'],
 | 
					 | 
				
			||||||
              kw['password']
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
            return dict()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Handling Schema Failures
 | 
					 | 
				
			||||||
------------------------------
 | 
					 | 
				
			||||||
When schema validation fails, the validation errors from FormEncode are applied to Pecan's
 | 
					 | 
				
			||||||
request object (``pecan.request.pecan``) as a dictionary.
 | 
					 | 
				
			||||||
The key where the actual errors go is ``validation_errors`` and this can be
 | 
					 | 
				
			||||||
inspected by your controller methods to react to errors appropiately::
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    from pecan import expose, request
 | 
					 | 
				
			||||||
    from myproject.schemas import SimpleSchema
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    class LoginController(object):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        @expose(schema=SimpleSchema)
 | 
					 | 
				
			||||||
        def login(self, **kw):
 | 
					 | 
				
			||||||
            if request.pecan['validation_errors']:
 | 
					 | 
				
			||||||
                pass # Don't Panic!
 | 
					 | 
				
			||||||
            return dict()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Error Handlers and Template Filling
 | 
					 | 
				
			||||||
------------------------------
 | 
					 | 
				
			||||||
When schema validation fails, Pecan allows you to redirect to another controller internally
 | 
					 | 
				
			||||||
for error handling via the `error_handler` keyword argument to ``@expose()``.
 | 
					 | 
				
			||||||
This is especially useful when used in combination with generic
 | 
					 | 
				
			||||||
controller methods::
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  from pecan import request, expose
 | 
					 | 
				
			||||||
  from formencode import Schema, validators as v
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  class ProfileSchema(Schema):    
 | 
					 | 
				
			||||||
      name = v.String(not_empty=True)
 | 
					 | 
				
			||||||
      email = v.String(not_empty=True)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  class ProfileController(object):
 | 
					 | 
				
			||||||
  
 | 
					 | 
				
			||||||
      @expose(generic=True)
 | 
					 | 
				
			||||||
      def index(self):
 | 
					 | 
				
			||||||
          pass
 | 
					 | 
				
			||||||
          
 | 
					 | 
				
			||||||
      @index.when(method="GET", template='profile.html')
 | 
					 | 
				
			||||||
      def index_get(self):
 | 
					 | 
				
			||||||
          """
 | 
					 | 
				
			||||||
          This method will be called to render the original template.
 | 
					 | 
				
			||||||
          It will also be used for generating a form pre-filled with values
 | 
					 | 
				
			||||||
          when schema failures occur.
 | 
					 | 
				
			||||||
          """
 | 
					 | 
				
			||||||
          return dict()
 | 
					 | 
				
			||||||
          
 | 
					 | 
				
			||||||
      @index.when(method="POST", schema=ProfileSchema(), error_handler=lambda: request.path)
 | 
					 | 
				
			||||||
      def index_post(self, **kw):
 | 
					 | 
				
			||||||
          """
 | 
					 | 
				
			||||||
          This method will do something with POST arguments.
 | 
					 | 
				
			||||||
          If the schema validation fails, an internal redirect will
 | 
					 | 
				
			||||||
          cause the `profile.html` template to be rendered via the
 | 
					 | 
				
			||||||
          ``index_get`` method.
 | 
					 | 
				
			||||||
          """
 | 
					 | 
				
			||||||
          
 | 
					 | 
				
			||||||
          name = kw.get('name')
 | 
					 | 
				
			||||||
          email = ke.get('email')
 | 
					 | 
				
			||||||
          
 | 
					 | 
				
			||||||
          redirect('/profile')
 | 
					 | 
				
			||||||
          
 | 
					 | 
				
			||||||
In this example, when form validation errors occur (for example, the email provided is invalid),
 | 
					 | 
				
			||||||
Pecan will handle pre-filling the form values in ``profile.html`` for you.  Additionally, inline
 | 
					 | 
				
			||||||
errors will be appended to the template using FormEncode's ``htmlfill``.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Bypassing ``htmlfill``
 | 
					 | 
				
			||||||
------------------------------
 | 
					 | 
				
			||||||
Sometimes you want certain fields in your templates to be ignored (i.e., not pre-filled) by ``htmlfill``.
 | 
					 | 
				
			||||||
A perfect use case for this is password and hidden input fields.  The default Pecan template namespace
 | 
					 | 
				
			||||||
includes a built-in function, ``static``, which allows you to enforce a static value for form fields,
 | 
					 | 
				
			||||||
preventing ``htmlfill`` from filling in submitted form variables::
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <form method="POST">
 | 
					 | 
				
			||||||
      <fieldset>
 | 
					 | 
				
			||||||
        <label>Username:</label>
 | 
					 | 
				
			||||||
          <input type="text" name="username" />
 | 
					 | 
				
			||||||
        <label>Password:</label>        
 | 
					 | 
				
			||||||
          <input type="password" name="password" value="${static('password', '')}" />
 | 
					 | 
				
			||||||
        <input type="hidden" name="ticket" value="${static('ticket', 'RANDOM_PER_REQUEST_VALUE')}" />
 | 
					 | 
				
			||||||
        <button>Login</button>
 | 
					 | 
				
			||||||
      </fieldset>
 | 
					 | 
				
			||||||
    </form>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Working with ``variabledecode``
 | 
					 | 
				
			||||||
------------------------------
 | 
					 | 
				
			||||||
Pecan also lets you take advantage of FormEncode's ``variabledecode`` for transforming flat HTML form
 | 
					 | 
				
			||||||
submissions into nested structures::
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    from pecan import expose
 | 
					 | 
				
			||||||
    from myproject import SimpleSchema
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    class ProfileController(object):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        @expose(schema=SimpleSchema(), variable_decode=True)
 | 
					 | 
				
			||||||
        def index(self):
 | 
					 | 
				
			||||||
            return dict()
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,8 +7,6 @@ from webob              import Request, Response, exc
 | 
				
			|||||||
from threading          import local
 | 
					from threading          import local
 | 
				
			||||||
from itertools          import chain
 | 
					from itertools          import chain
 | 
				
			||||||
from mimetypes          import guess_type, add_type
 | 
					from mimetypes          import guess_type, add_type
 | 
				
			||||||
from formencode         import htmlfill, Invalid, variabledecode
 | 
					 | 
				
			||||||
from formencode.schema  import merge_dicts
 | 
					 | 
				
			||||||
from paste.recursive    import ForwardRequestException
 | 
					from paste.recursive    import ForwardRequestException
 | 
				
			||||||
from urlparse           import urlsplit, urlunsplit
 | 
					from urlparse           import urlsplit, urlunsplit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -121,8 +119,7 @@ def redirect(location=None, internal=False, code=None, headers={},
 | 
				
			|||||||
def error_for(field):
 | 
					def error_for(field):
 | 
				
			||||||
    '''
 | 
					    '''
 | 
				
			||||||
    A convenience function for fetching the validation error for a
 | 
					    A convenience function for fetching the validation error for a
 | 
				
			||||||
    particular field in a form. Useful within templates when not using
 | 
					    particular field in a form.
 | 
				
			||||||
    ``htmlfill`` for forms.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    :param field: The name of the field to get the error for.
 | 
					    :param field: The name of the field to get the error for.
 | 
				
			||||||
    '''
 | 
					    '''
 | 
				
			||||||
@@ -130,22 +127,6 @@ def error_for(field):
 | 
				
			|||||||
    return request.pecan['validation_errors'].get(field, '')
 | 
					    return request.pecan['validation_errors'].get(field, '')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def static(name, value):
 | 
					 | 
				
			||||||
    '''
 | 
					 | 
				
			||||||
    When using ``htmlfill`` validation support, this function indicates
 | 
					 | 
				
			||||||
    that ``htmlfill`` should not fill in a value for this field, and
 | 
					 | 
				
			||||||
    should instead use the value specified.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    :param name: The name of the field.
 | 
					 | 
				
			||||||
    :param value: The value to specify.
 | 
					 | 
				
			||||||
    '''
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if 'pecan.params' not in request.environ:
 | 
					 | 
				
			||||||
        request.environ['pecan.params'] = dict(request.params)
 | 
					 | 
				
			||||||
    request.environ['pecan.params'][name] = value
 | 
					 | 
				
			||||||
    return value
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def render(template, namespace):
 | 
					def render(template, namespace):
 | 
				
			||||||
    '''
 | 
					    '''
 | 
				
			||||||
    Render the specified template using the Pecan rendering framework
 | 
					    Render the specified template using the Pecan rendering framework
 | 
				
			||||||
@@ -176,14 +157,11 @@ class ValidationException(ForwardRequestException):
 | 
				
			|||||||
            location = cfg['error_handler']
 | 
					            location = cfg['error_handler']
 | 
				
			||||||
            if callable(location):
 | 
					            if callable(location):
 | 
				
			||||||
                location = location()
 | 
					                location = location()
 | 
				
			||||||
        merge_dicts(request.pecan['validation_errors'], errors)
 | 
					 | 
				
			||||||
        if 'pecan.params' not in request.environ:
 | 
					        if 'pecan.params' not in request.environ:
 | 
				
			||||||
            request.environ['pecan.params'] = dict(request.params)
 | 
					            request.environ['pecan.params'] = dict(request.params)
 | 
				
			||||||
        request.environ[
 | 
					        request.environ[
 | 
				
			||||||
            'pecan.validation_errors'
 | 
					            'pecan.validation_errors'
 | 
				
			||||||
        ] = request.pecan['validation_errors']
 | 
					        ] = request.pecan['validation_errors']
 | 
				
			||||||
        if cfg.get('htmlfill') is not None:
 | 
					 | 
				
			||||||
            request.environ['pecan.htmlfill'] = cfg['htmlfill']
 | 
					 | 
				
			||||||
        request.environ['REQUEST_METHOD'] = 'GET'
 | 
					        request.environ['REQUEST_METHOD'] = 'GET'
 | 
				
			||||||
        request.environ['pecan.validation_redirected'] = True
 | 
					        request.environ['pecan.validation_redirected'] = True
 | 
				
			||||||
        ForwardRequestException.__init__(self, location)
 | 
					        ForwardRequestException.__init__(self, location)
 | 
				
			||||||
@@ -407,7 +385,6 @@ class Pecan(object):
 | 
				
			|||||||
            renderer = self.renderers.get('json', self.template_path)
 | 
					            renderer = self.renderers.get('json', self.template_path)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            namespace['error_for'] = error_for
 | 
					            namespace['error_for'] = error_for
 | 
				
			||||||
            namespace['static'] = static
 | 
					 | 
				
			||||||
        if ':' in template:
 | 
					        if ':' in template:
 | 
				
			||||||
            renderer = self.renderers.get(
 | 
					            renderer = self.renderers.get(
 | 
				
			||||||
                template.split(':')[0],
 | 
					                template.split(':')[0],
 | 
				
			||||||
@@ -416,45 +393,6 @@ class Pecan(object):
 | 
				
			|||||||
            template = template.split(':')[1]
 | 
					            template = template.split(':')[1]
 | 
				
			||||||
        return renderer.render(template, namespace)
 | 
					        return renderer.render(template, namespace)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def validate(self, schema, params, json=False, error_handler=None,
 | 
					 | 
				
			||||||
                 htmlfill=None, variable_decode=None):
 | 
					 | 
				
			||||||
        '''
 | 
					 | 
				
			||||||
        Performs validation against a schema for any passed params,
 | 
					 | 
				
			||||||
        including support for ``JSON``.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        :param schema: A ``formencode`` ``Schema`` object to validate against.
 | 
					 | 
				
			||||||
        :param params: The dictionary of parameters to validate.
 | 
					 | 
				
			||||||
        :param json: A boolean, indicating whether or not the validation should
 | 
					 | 
				
			||||||
        validate against JSON content.
 | 
					 | 
				
			||||||
        :param error_handler: The path to a controller which will handle
 | 
					 | 
				
			||||||
        errors. If not specified, validation errors will raise a
 | 
					 | 
				
			||||||
        ``ValidationException``.
 | 
					 | 
				
			||||||
        :param htmlfill: Specifies whether or not to use htmlfill.
 | 
					 | 
				
			||||||
        :param variable_decode: Indicates whether or not to decode variables
 | 
					 | 
				
			||||||
        when using htmlfill.
 | 
					 | 
				
			||||||
        '''
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        try:
 | 
					 | 
				
			||||||
            to_validate = params
 | 
					 | 
				
			||||||
            if json:
 | 
					 | 
				
			||||||
                to_validate = loads(request.body)
 | 
					 | 
				
			||||||
            if variable_decode is not None:
 | 
					 | 
				
			||||||
                to_validate = variabledecode.variable_decode(
 | 
					 | 
				
			||||||
                    to_validate, **variable_decode
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
            params = schema.to_python(to_validate)
 | 
					 | 
				
			||||||
        except Invalid, e:
 | 
					 | 
				
			||||||
            kwargs = {}
 | 
					 | 
				
			||||||
            if variable_decode is not None:
 | 
					 | 
				
			||||||
                kwargs['encode_variables'] = True
 | 
					 | 
				
			||||||
                kwargs.update(variable_decode)
 | 
					 | 
				
			||||||
            request.pecan['validation_errors'] = e.unpack_errors(**kwargs)
 | 
					 | 
				
			||||||
            if error_handler is not None:
 | 
					 | 
				
			||||||
                raise ValidationException()
 | 
					 | 
				
			||||||
        if json:
 | 
					 | 
				
			||||||
            params = dict(data=params)
 | 
					 | 
				
			||||||
        return params or {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def handle_request(self):
 | 
					    def handle_request(self):
 | 
				
			||||||
        '''
 | 
					        '''
 | 
				
			||||||
        The main request handler for Pecan applications.
 | 
					        The main request handler for Pecan applications.
 | 
				
			||||||
@@ -524,20 +462,8 @@ class Pecan(object):
 | 
				
			|||||||
        # handle "before" hooks
 | 
					        # handle "before" hooks
 | 
				
			||||||
        self.handle_hooks('before', state)
 | 
					        self.handle_hooks('before', state)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # fetch and validate any parameters
 | 
					        # fetch any parameters
 | 
				
			||||||
        params = dict(request.params)
 | 
					        params = dict(request.params)
 | 
				
			||||||
        if 'schema' in cfg:
 | 
					 | 
				
			||||||
            params = self.validate(
 | 
					 | 
				
			||||||
                        cfg['schema'],
 | 
					 | 
				
			||||||
                        params,
 | 
					 | 
				
			||||||
                        json=cfg['validate_json'],
 | 
					 | 
				
			||||||
                        error_handler=cfg.get('error_handler'),
 | 
					 | 
				
			||||||
                        htmlfill=cfg.get('htmlfill'),
 | 
					 | 
				
			||||||
                        variable_decode=cfg.get('variable_decode')
 | 
					 | 
				
			||||||
                    )
 | 
					 | 
				
			||||||
        elif 'pecan.validation_errors' in request.environ:
 | 
					 | 
				
			||||||
            errors = request.environ.pop('pecan.validation_errors')
 | 
					 | 
				
			||||||
            request.pecan['validation_errors'] = errors
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # fetch the arguments for the controller
 | 
					        # fetch the arguments for the controller
 | 
				
			||||||
        args, kwargs = self.get_args(
 | 
					        args, kwargs = self.get_args(
 | 
				
			||||||
@@ -575,23 +501,8 @@ class Pecan(object):
 | 
				
			|||||||
                request.pecan['content_type'] = 'application/json'
 | 
					                request.pecan['content_type'] = 'application/json'
 | 
				
			||||||
            result = self.render(template, result)
 | 
					            result = self.render(template, result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # pass the response through htmlfill (items are popped out of the
 | 
					 | 
				
			||||||
        # environment even if htmlfill won't run for proper cleanup)
 | 
					 | 
				
			||||||
        _htmlfill = cfg.get('htmlfill')
 | 
					 | 
				
			||||||
        if _htmlfill is None and 'pecan.htmlfill' in request.environ:
 | 
					 | 
				
			||||||
            _htmlfill = request.environ.pop('pecan.htmlfill')
 | 
					 | 
				
			||||||
        if 'pecan.params' in request.environ:
 | 
					        if 'pecan.params' in request.environ:
 | 
				
			||||||
            params = request.environ.pop('pecan.params')
 | 
					            params = request.environ.pop('pecan.params')
 | 
				
			||||||
        if request.pecan['validation_errors'] and _htmlfill is not None and \
 | 
					 | 
				
			||||||
            request.pecan['content_type'] == 'text/html':
 | 
					 | 
				
			||||||
            errors = request.pecan['validation_errors']
 | 
					 | 
				
			||||||
            result = htmlfill.render(
 | 
					 | 
				
			||||||
                result,
 | 
					 | 
				
			||||||
                defaults=params,
 | 
					 | 
				
			||||||
                errors=errors,
 | 
					 | 
				
			||||||
                text_as_default=True,
 | 
					 | 
				
			||||||
                **_htmlfill
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # If we are in a test request put the namespace where it can be
 | 
					        # If we are in a test request put the namespace where it can be
 | 
				
			||||||
        # accessed directly
 | 
					        # accessed directly
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,11 +20,6 @@ def when_for(controller):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
def expose(template=None,
 | 
					def expose(template=None,
 | 
				
			||||||
           content_type='text/html',
 | 
					           content_type='text/html',
 | 
				
			||||||
           schema=None,
 | 
					 | 
				
			||||||
           json_schema=None,
 | 
					 | 
				
			||||||
           variable_decode=False,
 | 
					 | 
				
			||||||
           error_handler=None,
 | 
					 | 
				
			||||||
           htmlfill=None,
 | 
					 | 
				
			||||||
           generic=False):
 | 
					           generic=False):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    '''
 | 
					    '''
 | 
				
			||||||
@@ -34,14 +29,6 @@ def expose(template=None,
 | 
				
			|||||||
    :param template: The path to a template, relative to the base template
 | 
					    :param template: The path to a template, relative to the base template
 | 
				
			||||||
    directory.
 | 
					    directory.
 | 
				
			||||||
    :param content_type: The content-type to use for this template.
 | 
					    :param content_type: The content-type to use for this template.
 | 
				
			||||||
    :param schema: A ``formencode`` ``Schema`` object to use for validation.
 | 
					 | 
				
			||||||
    :param json_schema: A ``formencode`` ``Schema`` object to use for
 | 
					 | 
				
			||||||
    validation of JSON POST/PUT content.
 | 
					 | 
				
			||||||
    :param variable_decode: A boolean indicating if you want to use
 | 
					 | 
				
			||||||
    ``htmlfill``'s variable decode capability of transforming flat HTML form
 | 
					 | 
				
			||||||
    structures into nested ones.
 | 
					 | 
				
			||||||
    :param htmlfill: Indicates whether or not you want to use ``htmlfill`` for
 | 
					 | 
				
			||||||
    this controller.
 | 
					 | 
				
			||||||
    :param generic: A boolean which flags this as a "generic" controller, which
 | 
					    :param generic: A boolean which flags this as a "generic" controller, which
 | 
				
			||||||
    uses generic functions based upon ``simplegeneric`` generic functions.
 | 
					    uses generic functions based upon ``simplegeneric`` generic functions.
 | 
				
			||||||
    Allows you to split a single controller into multiple paths based upon HTTP
 | 
					    Allows you to split a single controller into multiple paths based upon HTTP
 | 
				
			||||||
@@ -70,30 +57,8 @@ def expose(template=None,
 | 
				
			|||||||
        # store the arguments for this controller method
 | 
					        # store the arguments for this controller method
 | 
				
			||||||
        cfg['argspec'] = getargspec(f)
 | 
					        cfg['argspec'] = getargspec(f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # store the schema
 | 
					 | 
				
			||||||
        cfg['error_handler'] = error_handler
 | 
					 | 
				
			||||||
        if schema is not None:
 | 
					 | 
				
			||||||
            cfg['schema'] = schema
 | 
					 | 
				
			||||||
            cfg['validate_json'] = False
 | 
					 | 
				
			||||||
        elif json_schema is not None:
 | 
					 | 
				
			||||||
            cfg['schema'] = json_schema
 | 
					 | 
				
			||||||
            cfg['validate_json'] = True
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # store the variable decode configuration
 | 
					 | 
				
			||||||
        if isinstance(variable_decode, dict) or variable_decode == True:
 | 
					 | 
				
			||||||
            _variable_decode = dict(dict_char='.', list_char='-')
 | 
					 | 
				
			||||||
            if isinstance(variable_decode, dict):
 | 
					 | 
				
			||||||
                _variable_decode.update(variable_decode)
 | 
					 | 
				
			||||||
            cfg['variable_decode'] = _variable_decode
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # store the htmlfill configuration
 | 
					 | 
				
			||||||
        if isinstance(htmlfill, dict) or htmlfill == True or \
 | 
					 | 
				
			||||||
            schema is not None:
 | 
					 | 
				
			||||||
            _htmlfill = dict(auto_insert_errors=False)
 | 
					 | 
				
			||||||
            if isinstance(htmlfill, dict):
 | 
					 | 
				
			||||||
                _htmlfill.update(htmlfill)
 | 
					 | 
				
			||||||
            cfg['htmlfill'] = _htmlfill
 | 
					 | 
				
			||||||
        return f
 | 
					        return f
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return decorate
 | 
					    return decorate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,24 +1,14 @@
 | 
				
			|||||||
from pecan import expose, redirect
 | 
					from pecan import expose, redirect
 | 
				
			||||||
from formencode import Schema, validators as v
 | 
					 | 
				
			||||||
from webob.exc import status_map
 | 
					from webob.exc import status_map
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SearchForm(Schema):
 | 
					 | 
				
			||||||
    q = v.String(not_empty=True)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class RootController(object):
 | 
					class RootController(object):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @expose(generic=True, template='index.html')
 | 
					    @expose(generic=True, template='index.html')
 | 
				
			||||||
    def index(self):
 | 
					    def index(self):
 | 
				
			||||||
        return dict()
 | 
					        return dict()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @index.when(
 | 
					    @index.when(method='POST')
 | 
				
			||||||
        method='POST',
 | 
					 | 
				
			||||||
        schema=SearchForm(),
 | 
					 | 
				
			||||||
        error_handler='/index',
 | 
					 | 
				
			||||||
        htmlfill=dict(auto_insert_errors=True)
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    def index_post(self, q):
 | 
					    def index_post(self, q):
 | 
				
			||||||
        redirect('http://pecan.readthedocs.org/en/latest/search.html?q=%s' % q)
 | 
					        redirect('http://pecan.readthedocs.org/en/latest/search.html?q=%s' % q)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,2 +0,0 @@
 | 
				
			|||||||
<input type="text" id="username" name="username" />
 | 
					 | 
				
			||||||
<input type="password" id="password" name="password" value="${static('password', '')}" />
 | 
					 | 
				
			||||||
@@ -7,7 +7,6 @@ from pecan.hooks import (
 | 
				
			|||||||
from pecan.configuration import Config
 | 
					from pecan.configuration import Config
 | 
				
			||||||
from pecan.decorators import transactional, after_commit, after_rollback
 | 
					from pecan.decorators import transactional, after_commit, after_rollback
 | 
				
			||||||
from unittest import TestCase
 | 
					from unittest import TestCase
 | 
				
			||||||
from formencode import Schema, validators
 | 
					 | 
				
			||||||
from webtest import TestApp
 | 
					from webtest import TestApp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -329,125 +328,6 @@ class TestHooks(TestCase):
 | 
				
			|||||||
        assert run_hook[4] == 'after1'
 | 
					        assert run_hook[4] == 'after1'
 | 
				
			||||||
        assert run_hook[5] == 'after2'
 | 
					        assert run_hook[5] == 'after2'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_hooks_with_validation(self):
 | 
					 | 
				
			||||||
        run_hook = []
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        class RegistrationSchema(Schema):
 | 
					 | 
				
			||||||
            first_name = validators.String(not_empty=True)
 | 
					 | 
				
			||||||
            last_name = validators.String(not_empty=True)
 | 
					 | 
				
			||||||
            email = validators.Email()
 | 
					 | 
				
			||||||
            username = validators.PlainText()
 | 
					 | 
				
			||||||
            password = validators.String()
 | 
					 | 
				
			||||||
            password_confirm = validators.String()
 | 
					 | 
				
			||||||
            age = validators.Int()
 | 
					 | 
				
			||||||
            chained_validators = [
 | 
					 | 
				
			||||||
                validators.FieldsMatch('password', 'password_confirm')
 | 
					 | 
				
			||||||
            ]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        class SimpleHook(PecanHook):
 | 
					 | 
				
			||||||
            def on_route(self, state):
 | 
					 | 
				
			||||||
                run_hook.append('on_route')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            def before(self, state):
 | 
					 | 
				
			||||||
                run_hook.append('before')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            def after(self, state):
 | 
					 | 
				
			||||||
                run_hook.append('after')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            def on_error(self, state, e):
 | 
					 | 
				
			||||||
                run_hook.append('error')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        class RootController(object):
 | 
					 | 
				
			||||||
            @expose()
 | 
					 | 
				
			||||||
            def errors(self, *args, **kwargs):
 | 
					 | 
				
			||||||
                run_hook.append('inside')
 | 
					 | 
				
			||||||
                return 'errors'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(schema=RegistrationSchema())
 | 
					 | 
				
			||||||
            def index(self, first_name,
 | 
					 | 
				
			||||||
                            last_name,
 | 
					 | 
				
			||||||
                            email,
 | 
					 | 
				
			||||||
                            username,
 | 
					 | 
				
			||||||
                            password,
 | 
					 | 
				
			||||||
                            password_confirm,
 | 
					 | 
				
			||||||
                            age):
 | 
					 | 
				
			||||||
                run_hook.append('inside')
 | 
					 | 
				
			||||||
                return str(len(request.pecan['validation_errors']) > 0)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(schema=RegistrationSchema(), error_handler='/errors')
 | 
					 | 
				
			||||||
            def with_handler(self, first_name,
 | 
					 | 
				
			||||||
                            last_name,
 | 
					 | 
				
			||||||
                            email,
 | 
					 | 
				
			||||||
                            username,
 | 
					 | 
				
			||||||
                            password,
 | 
					 | 
				
			||||||
                            password_confirm,
 | 
					 | 
				
			||||||
                            age):
 | 
					 | 
				
			||||||
                run_hook.append('inside')
 | 
					 | 
				
			||||||
                return str(len(request.pecan['validation_errors']) > 0)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test that the hooks get properly run with no validation errors
 | 
					 | 
				
			||||||
        app = TestApp(make_app(RootController(), hooks=[SimpleHook()]))
 | 
					 | 
				
			||||||
        r = app.post('/', dict(
 | 
					 | 
				
			||||||
            first_name='Jonathan',
 | 
					 | 
				
			||||||
            last_name='LaCour',
 | 
					 | 
				
			||||||
            email='jonathan@cleverdevil.org',
 | 
					 | 
				
			||||||
            username='jlacour',
 | 
					 | 
				
			||||||
            password='123456',
 | 
					 | 
				
			||||||
            password_confirm='123456',
 | 
					 | 
				
			||||||
            age='31'
 | 
					 | 
				
			||||||
        ))
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'False'
 | 
					 | 
				
			||||||
        assert len(run_hook) == 4
 | 
					 | 
				
			||||||
        assert run_hook[0] == 'on_route'
 | 
					 | 
				
			||||||
        assert run_hook[1] == 'before'
 | 
					 | 
				
			||||||
        assert run_hook[2] == 'inside'
 | 
					 | 
				
			||||||
        assert run_hook[3] == 'after'
 | 
					 | 
				
			||||||
        run_hook = []
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test that the hooks get properly run with validation errors
 | 
					 | 
				
			||||||
        app = TestApp(make_app(RootController(), hooks=[SimpleHook()]))
 | 
					 | 
				
			||||||
        r = app.post('/', dict(
 | 
					 | 
				
			||||||
            first_name='Jonathan',
 | 
					 | 
				
			||||||
            last_name='LaCour',
 | 
					 | 
				
			||||||
            email='jonathan@cleverdevil.org',
 | 
					 | 
				
			||||||
            username='jlacour',
 | 
					 | 
				
			||||||
            password='654321',
 | 
					 | 
				
			||||||
            password_confirm='123456',
 | 
					 | 
				
			||||||
            age='31'
 | 
					 | 
				
			||||||
        ))
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'True'
 | 
					 | 
				
			||||||
        assert len(run_hook) == 4
 | 
					 | 
				
			||||||
        assert run_hook[0] == 'on_route'
 | 
					 | 
				
			||||||
        assert run_hook[1] == 'before'
 | 
					 | 
				
			||||||
        assert run_hook[2] == 'inside'
 | 
					 | 
				
			||||||
        assert run_hook[3] == 'after'
 | 
					 | 
				
			||||||
        run_hook = []
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test that the hooks get properly run with validation errors
 | 
					 | 
				
			||||||
        # and an error handler
 | 
					 | 
				
			||||||
        app = TestApp(make_app(RootController(), hooks=[SimpleHook()]))
 | 
					 | 
				
			||||||
        r = app.post('/with_handler', dict(
 | 
					 | 
				
			||||||
            first_name='Jonathan',
 | 
					 | 
				
			||||||
            last_name='LaCour',
 | 
					 | 
				
			||||||
            email='jonathan@cleverdevil.org',
 | 
					 | 
				
			||||||
            username='jlacour',
 | 
					 | 
				
			||||||
            password='654321',
 | 
					 | 
				
			||||||
            password_confirm='123456',
 | 
					 | 
				
			||||||
            age='31'
 | 
					 | 
				
			||||||
        ))
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'errors'
 | 
					 | 
				
			||||||
        assert len(run_hook) == 7
 | 
					 | 
				
			||||||
        assert run_hook[0] == 'on_route'
 | 
					 | 
				
			||||||
        assert run_hook[1] == 'before'
 | 
					 | 
				
			||||||
        assert run_hook[2] == 'after'
 | 
					 | 
				
			||||||
        assert run_hook[3] == 'on_route'
 | 
					 | 
				
			||||||
        assert run_hook[4] == 'before'
 | 
					 | 
				
			||||||
        assert run_hook[5] == 'inside'
 | 
					 | 
				
			||||||
        assert run_hook[6] == 'after'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestTransactionHook(TestCase):
 | 
					class TestTransactionHook(TestCase):
 | 
				
			||||||
    def test_transaction_hook(self):
 | 
					    def test_transaction_hook(self):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,8 +7,6 @@ try:
 | 
				
			|||||||
except:
 | 
					except:
 | 
				
			||||||
    from json import dumps, loads  # noqa
 | 
					    from json import dumps, loads  # noqa
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import formencode
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestRestController(TestCase):
 | 
					class TestRestController(TestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -856,58 +854,3 @@ class TestRestController(TestCase):
 | 
				
			|||||||
        r = app.get('/foos/bars/bazs/final/named')
 | 
					        r = app.get('/foos/bars/bazs/final/named')
 | 
				
			||||||
        assert r.status_int == 200
 | 
					        assert r.status_int == 200
 | 
				
			||||||
        assert r.body == 'NAMED'
 | 
					        assert r.body == 'NAMED'
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_rest_with_validation_redirects(self):
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        Fixing a bug:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        When schema validation fails, pecan can use an internal redirect
 | 
					 | 
				
			||||||
        (paste.recursive.ForwardRequestException) to send you to another
 | 
					 | 
				
			||||||
        controller to "handle" the display of error messages.  Additionally,
 | 
					 | 
				
			||||||
        pecan overwrites the request method as GET.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        In some circumstances, RestController's special `_method` parameter
 | 
					 | 
				
			||||||
        prevents the redirected request from routing to the appropriate
 | 
					 | 
				
			||||||
        `error_handler` controller.
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        class SampleSchema(formencode.Schema):
 | 
					 | 
				
			||||||
            name = formencode.validators.String()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        class UserController(RestController):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose()
 | 
					 | 
				
			||||||
            def get_one(self, id):
 | 
					 | 
				
			||||||
                return "FORM VALIDATION FAILED"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(
 | 
					 | 
				
			||||||
                schema=SampleSchema(),
 | 
					 | 
				
			||||||
                error_handler=lambda: request.path
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
            def put(self, id):
 | 
					 | 
				
			||||||
                raise AssertionError("Schema validation should fail.")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(
 | 
					 | 
				
			||||||
                schema=SampleSchema(),
 | 
					 | 
				
			||||||
                error_handler=lambda: request.path
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
            def delete(self, id):
 | 
					 | 
				
			||||||
                raise AssertionError("Schema validation should fail.")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        class RootController(object):
 | 
					 | 
				
			||||||
            users = UserController()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # create the app
 | 
					 | 
				
			||||||
        app = TestApp(make_app(RootController()))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # create the app
 | 
					 | 
				
			||||||
        app = TestApp(make_app(RootController()))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test proper internal redirection
 | 
					 | 
				
			||||||
        r = app.post('/users/1?_method=put')
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == "FORM VALIDATION FAILED"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        r = app.post('/users/1?_method=delete')
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == "FORM VALIDATION FAILED"
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,27 +0,0 @@
 | 
				
			|||||||
import os
 | 
					 | 
				
			||||||
from pecan import expose, make_app
 | 
					 | 
				
			||||||
from unittest import TestCase
 | 
					 | 
				
			||||||
from webtest import TestApp
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class TestStatic(TestCase):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_simple_static(self):
 | 
					 | 
				
			||||||
        class RootController(object):
 | 
					 | 
				
			||||||
            @expose()
 | 
					 | 
				
			||||||
            def index(self):
 | 
					 | 
				
			||||||
                return 'Hello, World!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # make sure Cascade is working properly
 | 
					 | 
				
			||||||
        text = os.path.join(os.path.dirname(__file__), 'static/text.txt')
 | 
					 | 
				
			||||||
        static_root = os.path.join(os.path.dirname(__file__), 'static')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        app = TestApp(make_app(RootController(), static_root=static_root))
 | 
					 | 
				
			||||||
        response = app.get('/index.html')
 | 
					 | 
				
			||||||
        assert response.status_int == 200
 | 
					 | 
				
			||||||
        assert response.body == 'Hello, World!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # get a static resource
 | 
					 | 
				
			||||||
        response = app.get('/text.txt')
 | 
					 | 
				
			||||||
        assert response.status_int == 200
 | 
					 | 
				
			||||||
        assert response.body == open(text, 'rb').read()
 | 
					 | 
				
			||||||
@@ -1,885 +0,0 @@
 | 
				
			|||||||
from formencode import ForEach, Schema, validators
 | 
					 | 
				
			||||||
from webtest import TestApp
 | 
					 | 
				
			||||||
from unittest import TestCase
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import os.path
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from pecan import make_app, expose, request, ValidationException
 | 
					 | 
				
			||||||
from pecan.templating import _builtin_renderers as builtin_renderers
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
try:
 | 
					 | 
				
			||||||
    from simplejson import dumps
 | 
					 | 
				
			||||||
except ImportError:
 | 
					 | 
				
			||||||
    from json import dumps  # noqa
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class TestValidation(TestCase):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    template_path = os.path.join(os.path.dirname(__file__), 'templates')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_simple_validation(self):
 | 
					 | 
				
			||||||
        class RegistrationSchema(Schema):
 | 
					 | 
				
			||||||
            first_name = validators.String(not_empty=True)
 | 
					 | 
				
			||||||
            last_name = validators.String(not_empty=True)
 | 
					 | 
				
			||||||
            email = validators.Email()
 | 
					 | 
				
			||||||
            username = validators.PlainText()
 | 
					 | 
				
			||||||
            password = validators.String()
 | 
					 | 
				
			||||||
            password_confirm = validators.String()
 | 
					 | 
				
			||||||
            age = validators.Int()
 | 
					 | 
				
			||||||
            chained_validators = [
 | 
					 | 
				
			||||||
                validators.FieldsMatch('password', 'password_confirm')
 | 
					 | 
				
			||||||
            ]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        class RootController(object):
 | 
					 | 
				
			||||||
            @expose(schema=RegistrationSchema())
 | 
					 | 
				
			||||||
            def index(self, first_name,
 | 
					 | 
				
			||||||
                            last_name,
 | 
					 | 
				
			||||||
                            email,
 | 
					 | 
				
			||||||
                            username,
 | 
					 | 
				
			||||||
                            password,
 | 
					 | 
				
			||||||
                            password_confirm,
 | 
					 | 
				
			||||||
                            age):
 | 
					 | 
				
			||||||
                assert isinstance(last_name, unicode)
 | 
					 | 
				
			||||||
                assert isinstance(first_name, unicode)
 | 
					 | 
				
			||||||
                assert age == 31
 | 
					 | 
				
			||||||
                assert isinstance(age, int)
 | 
					 | 
				
			||||||
                return 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(json_schema=RegistrationSchema())
 | 
					 | 
				
			||||||
            def json(self, data):
 | 
					 | 
				
			||||||
                assert data['age'] == 31
 | 
					 | 
				
			||||||
                assert isinstance(data['age'], int)
 | 
					 | 
				
			||||||
                return 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test form submissions
 | 
					 | 
				
			||||||
        app = TestApp(make_app(RootController()))
 | 
					 | 
				
			||||||
        r = app.post('/', dict(
 | 
					 | 
				
			||||||
            first_name='Jonathan',
 | 
					 | 
				
			||||||
            last_name='LaCour',
 | 
					 | 
				
			||||||
            email='jonathan@cleverdevil.org',
 | 
					 | 
				
			||||||
            username='jlacour',
 | 
					 | 
				
			||||||
            password='123456',
 | 
					 | 
				
			||||||
            password_confirm='123456',
 | 
					 | 
				
			||||||
            age='31'
 | 
					 | 
				
			||||||
        ))
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test JSON submissions
 | 
					 | 
				
			||||||
        r = app.post('/json', dumps(dict(
 | 
					 | 
				
			||||||
            first_name='Jonathan',
 | 
					 | 
				
			||||||
            last_name='LaCour',
 | 
					 | 
				
			||||||
            email='jonathan@cleverdevil.org',
 | 
					 | 
				
			||||||
            username='jlacour',
 | 
					 | 
				
			||||||
            password='123456',
 | 
					 | 
				
			||||||
            password_confirm='123456',
 | 
					 | 
				
			||||||
            age='31'
 | 
					 | 
				
			||||||
        )), [('content-type', 'application/json')])
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_validation_with_none_type(self):
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        formencode schemas can be configured to return NoneType in some
 | 
					 | 
				
			||||||
        circumstances.  We use the output of formencode's validate() to
 | 
					 | 
				
			||||||
        determine wildcard arguments, so we should protect ourselves
 | 
					 | 
				
			||||||
        from this scenario.
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        class RegistrationSchema(Schema):
 | 
					 | 
				
			||||||
            if_empty = None
 | 
					 | 
				
			||||||
            first_name = validators.String(not_empty=True)
 | 
					 | 
				
			||||||
            last_name = validators.String(not_empty=True)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        class RootController(object):
 | 
					 | 
				
			||||||
            @expose(schema=RegistrationSchema())
 | 
					 | 
				
			||||||
            def index(self, **kw):
 | 
					 | 
				
			||||||
                assert 'first_name' not in kw
 | 
					 | 
				
			||||||
                assert 'last_name' not in kw
 | 
					 | 
				
			||||||
                return 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test form submissions
 | 
					 | 
				
			||||||
        app = TestApp(make_app(RootController()))
 | 
					 | 
				
			||||||
        r = app.post('/', dict())
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_simple_failure(self):
 | 
					 | 
				
			||||||
        class RegistrationSchema(Schema):
 | 
					 | 
				
			||||||
            first_name = validators.String(not_empty=True)
 | 
					 | 
				
			||||||
            last_name = validators.String(not_empty=True)
 | 
					 | 
				
			||||||
            email = validators.Email()
 | 
					 | 
				
			||||||
            username = validators.PlainText()
 | 
					 | 
				
			||||||
            password = validators.String()
 | 
					 | 
				
			||||||
            password_confirm = validators.String()
 | 
					 | 
				
			||||||
            age = validators.Int()
 | 
					 | 
				
			||||||
            chained_validators = [
 | 
					 | 
				
			||||||
                validators.FieldsMatch('password', 'password_confirm')
 | 
					 | 
				
			||||||
            ]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        class RootController(object):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose()
 | 
					 | 
				
			||||||
            def errors(self, *args, **kwargs):
 | 
					 | 
				
			||||||
                assert len(request.pecan['validation_errors']) > 0
 | 
					 | 
				
			||||||
                return 'There was an error!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(schema=RegistrationSchema())
 | 
					 | 
				
			||||||
            def index(self, first_name,
 | 
					 | 
				
			||||||
                            last_name,
 | 
					 | 
				
			||||||
                            email,
 | 
					 | 
				
			||||||
                            username,
 | 
					 | 
				
			||||||
                            password,
 | 
					 | 
				
			||||||
                            password_confirm,
 | 
					 | 
				
			||||||
                            age):
 | 
					 | 
				
			||||||
                assert len(request.pecan['validation_errors']) > 0
 | 
					 | 
				
			||||||
                return 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(schema=RegistrationSchema(), error_handler='/errors')
 | 
					 | 
				
			||||||
            def with_handler(self, first_name,
 | 
					 | 
				
			||||||
                            last_name,
 | 
					 | 
				
			||||||
                            email,
 | 
					 | 
				
			||||||
                            username,
 | 
					 | 
				
			||||||
                            password,
 | 
					 | 
				
			||||||
                            password_confirm,
 | 
					 | 
				
			||||||
                            age):
 | 
					 | 
				
			||||||
                assert len(request.pecan['validation_errors']) > 0
 | 
					 | 
				
			||||||
                return 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(json_schema=RegistrationSchema())
 | 
					 | 
				
			||||||
            def json(self, data):
 | 
					 | 
				
			||||||
                assert len(request.pecan['validation_errors']) > 0
 | 
					 | 
				
			||||||
                return 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(json_schema=RegistrationSchema(), error_handler='/errors')
 | 
					 | 
				
			||||||
            def json_with_handler(self, data):
 | 
					 | 
				
			||||||
                assert len(request.pecan['validation_errors']) > 0
 | 
					 | 
				
			||||||
                return 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test without error handler
 | 
					 | 
				
			||||||
        app = TestApp(make_app(RootController()))
 | 
					 | 
				
			||||||
        r = app.post('/', dict(
 | 
					 | 
				
			||||||
            first_name='Jonathan',
 | 
					 | 
				
			||||||
            last_name='LaCour',
 | 
					 | 
				
			||||||
            email='jonathan@cleverdevil.org',
 | 
					 | 
				
			||||||
            username='jlacour',
 | 
					 | 
				
			||||||
            password='123456',
 | 
					 | 
				
			||||||
            password_confirm='654321',
 | 
					 | 
				
			||||||
            age='31'
 | 
					 | 
				
			||||||
        ))
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test with error handler
 | 
					 | 
				
			||||||
        r = app.post('/with_handler', dict(
 | 
					 | 
				
			||||||
            first_name='Jonathan',
 | 
					 | 
				
			||||||
            last_name='LaCour',
 | 
					 | 
				
			||||||
            email='jonathan@cleverdevil.org',
 | 
					 | 
				
			||||||
            username='jlacour',
 | 
					 | 
				
			||||||
            password='123456',
 | 
					 | 
				
			||||||
            password_confirm='654321',
 | 
					 | 
				
			||||||
            age='31'
 | 
					 | 
				
			||||||
        ))
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'There was an error!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test JSON without error handler
 | 
					 | 
				
			||||||
        r = app.post('/json', dumps(dict(
 | 
					 | 
				
			||||||
            first_name='Jonathan',
 | 
					 | 
				
			||||||
            last_name='LaCour',
 | 
					 | 
				
			||||||
            email='jonathan@cleverdevil.org',
 | 
					 | 
				
			||||||
            username='jlacour',
 | 
					 | 
				
			||||||
            password='123456',
 | 
					 | 
				
			||||||
            password_confirm='654321',
 | 
					 | 
				
			||||||
            age='31'
 | 
					 | 
				
			||||||
        )), [('content-type', 'application/json')])
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test JSON with error handler
 | 
					 | 
				
			||||||
        r = app.post('/json_with_handler', dumps(dict(
 | 
					 | 
				
			||||||
            first_name='Jonathan',
 | 
					 | 
				
			||||||
            last_name='LaCour',
 | 
					 | 
				
			||||||
            email='jonathan@cleverdevil.org',
 | 
					 | 
				
			||||||
            username='jlacour',
 | 
					 | 
				
			||||||
            password='123456',
 | 
					 | 
				
			||||||
            password_confirm='654321',
 | 
					 | 
				
			||||||
            age='31'
 | 
					 | 
				
			||||||
        )), [('content-type', 'application/json')])
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'There was an error!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_with_variable_decode(self):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        class ColorSchema(Schema):
 | 
					 | 
				
			||||||
            colors = ForEach(validators.String(not_empty=True))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        class RootController(object):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose()
 | 
					 | 
				
			||||||
            def errors(self, *args, **kwargs):
 | 
					 | 
				
			||||||
                errs = ', '.join(request.pecan['validation_errors'].keys())
 | 
					 | 
				
			||||||
                return 'Error with %s!' % errs
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(schema=ColorSchema(),
 | 
					 | 
				
			||||||
                    variable_decode=True)
 | 
					 | 
				
			||||||
            def index(self, **kwargs):
 | 
					 | 
				
			||||||
                if request.pecan['validation_errors']:
 | 
					 | 
				
			||||||
                    return ', '.join(request.pecan['validation_errors'].keys())
 | 
					 | 
				
			||||||
                else:
 | 
					 | 
				
			||||||
                    return 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(schema=ColorSchema(),
 | 
					 | 
				
			||||||
                    error_handler='/errors',
 | 
					 | 
				
			||||||
                    variable_decode=True)
 | 
					 | 
				
			||||||
            def with_handler(self, **kwargs):
 | 
					 | 
				
			||||||
                if request.pecan['validation_errors']:
 | 
					 | 
				
			||||||
                    return ', '.join(request.pecan['validation_errors'].keys())
 | 
					 | 
				
			||||||
                else:
 | 
					 | 
				
			||||||
                    return 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(json_schema=ColorSchema(),
 | 
					 | 
				
			||||||
                    variable_decode=True)
 | 
					 | 
				
			||||||
            def json(self, data):
 | 
					 | 
				
			||||||
                if request.pecan['validation_errors']:
 | 
					 | 
				
			||||||
                    return ', '.join(request.pecan['validation_errors'].keys())
 | 
					 | 
				
			||||||
                else:
 | 
					 | 
				
			||||||
                    return 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(json_schema=ColorSchema(),
 | 
					 | 
				
			||||||
                    error_handler='/errors',
 | 
					 | 
				
			||||||
                    variable_decode=True)
 | 
					 | 
				
			||||||
            def json_with_handler(self, data):
 | 
					 | 
				
			||||||
                if request.pecan['validation_errors']:
 | 
					 | 
				
			||||||
                    return ', '.join(request.pecan['validation_errors'].keys())
 | 
					 | 
				
			||||||
                else:
 | 
					 | 
				
			||||||
                    return 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(schema=ColorSchema(),
 | 
					 | 
				
			||||||
                    variable_decode=dict())
 | 
					 | 
				
			||||||
            def custom(self, **kwargs):
 | 
					 | 
				
			||||||
                if request.pecan['validation_errors']:
 | 
					 | 
				
			||||||
                    return ', '.join(request.pecan['validation_errors'].keys())
 | 
					 | 
				
			||||||
                else:
 | 
					 | 
				
			||||||
                    return 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(schema=ColorSchema(),
 | 
					 | 
				
			||||||
                    error_handler='/errors',
 | 
					 | 
				
			||||||
                    variable_decode=dict())
 | 
					 | 
				
			||||||
            def custom_with_handler(self, **kwargs):
 | 
					 | 
				
			||||||
                if request.pecan['validation_errors']:
 | 
					 | 
				
			||||||
                    return ', '.join(request.pecan['validation_errors'].keys())
 | 
					 | 
				
			||||||
                else:
 | 
					 | 
				
			||||||
                    return 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(json_schema=ColorSchema(),
 | 
					 | 
				
			||||||
                    variable_decode=dict())
 | 
					 | 
				
			||||||
            def custom_json(self, data):
 | 
					 | 
				
			||||||
                if request.pecan['validation_errors']:
 | 
					 | 
				
			||||||
                    return ', '.join(request.pecan['validation_errors'].keys())
 | 
					 | 
				
			||||||
                else:
 | 
					 | 
				
			||||||
                    return 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(json_schema=ColorSchema(),
 | 
					 | 
				
			||||||
                    error_handler='/errors',
 | 
					 | 
				
			||||||
                    variable_decode=dict())
 | 
					 | 
				
			||||||
            def custom_json_with_handler(self, data):
 | 
					 | 
				
			||||||
                if request.pecan['validation_errors']:
 | 
					 | 
				
			||||||
                    return ', '.join(request.pecan['validation_errors'].keys())
 | 
					 | 
				
			||||||
                else:
 | 
					 | 
				
			||||||
                    return 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(schema=ColorSchema(),
 | 
					 | 
				
			||||||
                    variable_decode=dict(dict_char='-', list_char='.'))
 | 
					 | 
				
			||||||
            def alternate(self, **kwargs):
 | 
					 | 
				
			||||||
                if request.pecan['validation_errors']:
 | 
					 | 
				
			||||||
                    return ', '.join(request.pecan['validation_errors'].keys())
 | 
					 | 
				
			||||||
                else:
 | 
					 | 
				
			||||||
                    return 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(schema=ColorSchema(),
 | 
					 | 
				
			||||||
                    error_handler='/errors',
 | 
					 | 
				
			||||||
                    variable_decode=dict(dict_char='-', list_char='.'))
 | 
					 | 
				
			||||||
            def alternate_with_handler(self, **kwargs):
 | 
					 | 
				
			||||||
                if request.pecan['validation_errors']:
 | 
					 | 
				
			||||||
                    return ', '.join(request.pecan['validation_errors'].keys())
 | 
					 | 
				
			||||||
                else:
 | 
					 | 
				
			||||||
                    return 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(json_schema=ColorSchema(),
 | 
					 | 
				
			||||||
                    variable_decode=dict(dict_char='-', list_char='.'))
 | 
					 | 
				
			||||||
            def alternate_json(self, data):
 | 
					 | 
				
			||||||
                if request.pecan['validation_errors']:
 | 
					 | 
				
			||||||
                    return ', '.join(request.pecan['validation_errors'].keys())
 | 
					 | 
				
			||||||
                else:
 | 
					 | 
				
			||||||
                    return 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(json_schema=ColorSchema(),
 | 
					 | 
				
			||||||
                    error_handler='/errors',
 | 
					 | 
				
			||||||
                    variable_decode=dict(dict_char='-', list_char='.'))
 | 
					 | 
				
			||||||
            def alternate_json_with_handler(self, data):
 | 
					 | 
				
			||||||
                if request.pecan['validation_errors']:
 | 
					 | 
				
			||||||
                    return ', '.join(request.pecan['validation_errors'].keys())
 | 
					 | 
				
			||||||
                else:
 | 
					 | 
				
			||||||
                    return 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test without error handler
 | 
					 | 
				
			||||||
        app = TestApp(make_app(RootController()))
 | 
					 | 
				
			||||||
        r = app.post('/', {
 | 
					 | 
				
			||||||
            'colors-0': 'blue',
 | 
					 | 
				
			||||||
            'colors-1': 'red'
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test failure without error handler
 | 
					 | 
				
			||||||
        r = app.post('/', {
 | 
					 | 
				
			||||||
            'colors-0': 'blue',
 | 
					 | 
				
			||||||
            'colors-1': ''
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'colors-1'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test with error handler
 | 
					 | 
				
			||||||
        r = app.post('/with_handler', {
 | 
					 | 
				
			||||||
            'colors-0': 'blue',
 | 
					 | 
				
			||||||
            'colors-1': 'red'
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test failure with error handler
 | 
					 | 
				
			||||||
        r = app.post('/with_handler', {
 | 
					 | 
				
			||||||
            'colors-0': '',
 | 
					 | 
				
			||||||
            'colors-1': 'red'
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'Error with colors-0!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test JSON without error handler
 | 
					 | 
				
			||||||
        r = app.post('/json', dumps({
 | 
					 | 
				
			||||||
            'colors-0': 'blue',
 | 
					 | 
				
			||||||
            'colors-1': 'red'
 | 
					 | 
				
			||||||
        }), [('content-type', 'application/json')])
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test JSON failure without error handler
 | 
					 | 
				
			||||||
        r = app.post('/json', dumps({
 | 
					 | 
				
			||||||
            'colors-0': 'blue',
 | 
					 | 
				
			||||||
            'colors-1': ''
 | 
					 | 
				
			||||||
        }), [('content-type', 'application/json')])
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'colors-1'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test JSON with error handler
 | 
					 | 
				
			||||||
        r = app.post('/json_with_handler', dumps({
 | 
					 | 
				
			||||||
            'colors-0': 'blue',
 | 
					 | 
				
			||||||
            'colors-1': 'red'
 | 
					 | 
				
			||||||
        }), [('content-type', 'application/json')])
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test JSON failure with error handler
 | 
					 | 
				
			||||||
        r = app.post('/json_with_handler', dumps({
 | 
					 | 
				
			||||||
            'colors-0': '',
 | 
					 | 
				
			||||||
            'colors-1': 'red'
 | 
					 | 
				
			||||||
        }), [('content-type', 'application/json')])
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'Error with colors-0!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test custom without error handler
 | 
					 | 
				
			||||||
        r = app.post('/custom', {
 | 
					 | 
				
			||||||
            'colors-0': 'blue',
 | 
					 | 
				
			||||||
            'colors-1': 'red'
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test custom failure without error handler
 | 
					 | 
				
			||||||
        r = app.post('/custom', {
 | 
					 | 
				
			||||||
            'colors-0': 'blue',
 | 
					 | 
				
			||||||
            'colors-1': ''
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'colors-1'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test custom with error handler
 | 
					 | 
				
			||||||
        r = app.post('/custom_with_handler', {
 | 
					 | 
				
			||||||
            'colors-0': 'blue',
 | 
					 | 
				
			||||||
            'colors-1': 'red'
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test custom failure with error handler
 | 
					 | 
				
			||||||
        r = app.post('/custom_with_handler', {
 | 
					 | 
				
			||||||
            'colors-0': '',
 | 
					 | 
				
			||||||
            'colors-1': 'red'
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'Error with colors-0!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test custom JSON without error handler
 | 
					 | 
				
			||||||
        r = app.post('/custom_json', dumps({
 | 
					 | 
				
			||||||
            'colors-0': 'blue',
 | 
					 | 
				
			||||||
            'colors-1': 'red'
 | 
					 | 
				
			||||||
        }), [('content-type', 'application/json')])
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test custom JSON failure without error handler
 | 
					 | 
				
			||||||
        r = app.post('/custom_json', dumps({
 | 
					 | 
				
			||||||
            'colors-0': 'blue',
 | 
					 | 
				
			||||||
            'colors-1': ''
 | 
					 | 
				
			||||||
        }), [('content-type', 'application/json')])
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'colors-1'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test custom JSON with error handler
 | 
					 | 
				
			||||||
        r = app.post('/custom_json_with_handler', dumps({
 | 
					 | 
				
			||||||
            'colors-0': 'blue',
 | 
					 | 
				
			||||||
            'colors-1': 'red'
 | 
					 | 
				
			||||||
        }), [('content-type', 'application/json')])
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test custom JSON failure with error handler
 | 
					 | 
				
			||||||
        r = app.post('/custom_json_with_handler', dumps({
 | 
					 | 
				
			||||||
            'colors-0': '',
 | 
					 | 
				
			||||||
            'colors-1': 'red'
 | 
					 | 
				
			||||||
        }), [('content-type', 'application/json')])
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'Error with colors-0!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test alternate without error handler
 | 
					 | 
				
			||||||
        r = app.post('/alternate', {
 | 
					 | 
				
			||||||
            'colors.0': 'blue',
 | 
					 | 
				
			||||||
            'colors.1': 'red'
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test alternate failure without error handler
 | 
					 | 
				
			||||||
        r = app.post('/alternate', {
 | 
					 | 
				
			||||||
            'colors.0': 'blue',
 | 
					 | 
				
			||||||
            'colors.1': ''
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'colors.1'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test alternate with error handler
 | 
					 | 
				
			||||||
        r = app.post('/alternate_with_handler', {
 | 
					 | 
				
			||||||
            'colors.0': 'blue',
 | 
					 | 
				
			||||||
            'colors.1': 'red'
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test alternate failure with error handler
 | 
					 | 
				
			||||||
        r = app.post('/alternate_with_handler', {
 | 
					 | 
				
			||||||
            'colors.0': '',
 | 
					 | 
				
			||||||
            'colors.1': 'red'
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'Error with colors.0!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test alternate JSON without error handler
 | 
					 | 
				
			||||||
        r = app.post('/alternate_json', dumps({
 | 
					 | 
				
			||||||
            'colors.0': 'blue',
 | 
					 | 
				
			||||||
            'colors.1': 'red'
 | 
					 | 
				
			||||||
        }), [('content-type', 'application/json')])
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test alternate JSON failure without error handler
 | 
					 | 
				
			||||||
        r = app.post('/alternate_json', dumps({
 | 
					 | 
				
			||||||
            'colors.0': 'blue',
 | 
					 | 
				
			||||||
            'colors.1': ''
 | 
					 | 
				
			||||||
        }), [('content-type', 'application/json')])
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'colors.1'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test alternate JSON with error handler
 | 
					 | 
				
			||||||
        r = app.post('/alternate_json_with_handler', dumps({
 | 
					 | 
				
			||||||
            'colors.0': 'blue',
 | 
					 | 
				
			||||||
            'colors.1': 'red'
 | 
					 | 
				
			||||||
        }), [('content-type', 'application/json')])
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test alternate JSON failure with error handler
 | 
					 | 
				
			||||||
        r = app.post('/alternate_json_with_handler', dumps({
 | 
					 | 
				
			||||||
            'colors.0': '',
 | 
					 | 
				
			||||||
            'colors.1': 'red'
 | 
					 | 
				
			||||||
        }), [('content-type', 'application/json')])
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'Error with colors.0!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_htmlfill(self):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if 'mako' not in builtin_renderers:
 | 
					 | 
				
			||||||
            return
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        class ColorSchema(Schema):
 | 
					 | 
				
			||||||
            colors = ForEach(validators.String(not_empty=True))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        class NameSchema(Schema):
 | 
					 | 
				
			||||||
            name = validators.String(not_empty=True)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        class RootController(object):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(template='mako:form_colors.html',
 | 
					 | 
				
			||||||
                    schema=ColorSchema(),
 | 
					 | 
				
			||||||
                    variable_decode=True)
 | 
					 | 
				
			||||||
            def index(self, **kwargs):
 | 
					 | 
				
			||||||
                if request.pecan['validation_errors']:
 | 
					 | 
				
			||||||
                    return dict()
 | 
					 | 
				
			||||||
                else:
 | 
					 | 
				
			||||||
                    return dict(data=kwargs)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(schema=ColorSchema(),
 | 
					 | 
				
			||||||
                    error_handler='/errors_with_handler',
 | 
					 | 
				
			||||||
                    variable_decode=True)
 | 
					 | 
				
			||||||
            def with_handler(self, **kwargs):
 | 
					 | 
				
			||||||
                return ', '.join(kwargs['colors'])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose('mako:form_colors.html')
 | 
					 | 
				
			||||||
            def errors_with_handler(self):
 | 
					 | 
				
			||||||
                return dict()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(template='mako:form_name.html',
 | 
					 | 
				
			||||||
                    schema=NameSchema(),
 | 
					 | 
				
			||||||
                    htmlfill=dict(auto_insert_errors=True))
 | 
					 | 
				
			||||||
            def with_errors(self, **kwargs):
 | 
					 | 
				
			||||||
                return kwargs
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(schema=NameSchema(),
 | 
					 | 
				
			||||||
                    error_handler='/errors_with_handler_and_errors',
 | 
					 | 
				
			||||||
                    htmlfill=dict(auto_insert_errors=True))
 | 
					 | 
				
			||||||
            def with_handler_and_errors(self, **kwargs):
 | 
					 | 
				
			||||||
                return kwargs['name']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose('mako:form_name.html')
 | 
					 | 
				
			||||||
            def errors_with_handler_and_errors(self):
 | 
					 | 
				
			||||||
                return dict()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(template='json',
 | 
					 | 
				
			||||||
                    schema=NameSchema(),
 | 
					 | 
				
			||||||
                    htmlfill=dict(auto_insert_errors=True))
 | 
					 | 
				
			||||||
            def json(self, **kwargs):
 | 
					 | 
				
			||||||
                if request.pecan['validation_errors']:
 | 
					 | 
				
			||||||
                    return dict(
 | 
					 | 
				
			||||||
                        error_with=request.pecan['validation_errors'].keys()
 | 
					 | 
				
			||||||
                    )
 | 
					 | 
				
			||||||
                else:
 | 
					 | 
				
			||||||
                    return kwargs
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def _get_contents(filename):
 | 
					 | 
				
			||||||
            return open(os.path.join(self.template_path, filename), 'r').read()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test without error handler
 | 
					 | 
				
			||||||
        app = TestApp(
 | 
					 | 
				
			||||||
            make_app(RootController(), template_path=self.template_path)
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        r = app.post('/', {
 | 
					 | 
				
			||||||
            'colors-0': 'blue',
 | 
					 | 
				
			||||||
            'colors-1': 'red'
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == _get_contents('form_colors_valid.html')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test failure without error handler
 | 
					 | 
				
			||||||
        r = app.post('/', {
 | 
					 | 
				
			||||||
            'colors-0': 'blue',
 | 
					 | 
				
			||||||
            'colors-1': ''
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == _get_contents('form_colors_invalid.html')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test with error handler
 | 
					 | 
				
			||||||
        r = app.post('/with_handler', {
 | 
					 | 
				
			||||||
            'colors-0': 'blue',
 | 
					 | 
				
			||||||
            'colors-1': 'red'
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'blue, red'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test failure with error handler
 | 
					 | 
				
			||||||
        r = app.post('/with_handler', {
 | 
					 | 
				
			||||||
            'colors-0': 'blue',
 | 
					 | 
				
			||||||
            'colors-1': ''
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == _get_contents('form_colors_invalid.html')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test with errors
 | 
					 | 
				
			||||||
        r = app.post('/with_errors', {
 | 
					 | 
				
			||||||
            'name': 'Yoann'
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == _get_contents('form_name_valid.html')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test failure with errors
 | 
					 | 
				
			||||||
        r = app.post('/with_errors', {
 | 
					 | 
				
			||||||
            'name': ''
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == _get_contents('form_name_invalid.html')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test with error handler and errors
 | 
					 | 
				
			||||||
        r = app.post('/with_handler_and_errors', {
 | 
					 | 
				
			||||||
            'name': 'Yoann'
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'Yoann'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test failure with error handler and errors
 | 
					 | 
				
			||||||
        r = app.post('/with_handler_and_errors', {
 | 
					 | 
				
			||||||
            'name': ''
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == _get_contents('form_name_invalid.html')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test JSON
 | 
					 | 
				
			||||||
        r = app.post('/json', {
 | 
					 | 
				
			||||||
            'name': 'Yoann'
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == dumps(dict(name='Yoann'))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test JSON failure
 | 
					 | 
				
			||||||
        r = app.post('/json', {
 | 
					 | 
				
			||||||
            'name': ''
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == dumps(dict(error_with=['name']))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_htmlfill_static(self):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if 'mako' not in builtin_renderers:
 | 
					 | 
				
			||||||
            return
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        class LoginSchema(Schema):
 | 
					 | 
				
			||||||
            username = validators.String(not_empty=True)
 | 
					 | 
				
			||||||
            password = validators.String(not_empty=True)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        class RootController(object):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(template='mako:form_login.html',
 | 
					 | 
				
			||||||
                    schema=LoginSchema())
 | 
					 | 
				
			||||||
            def index(self, **kwargs):
 | 
					 | 
				
			||||||
                if request.pecan['validation_errors']:
 | 
					 | 
				
			||||||
                    return dict()
 | 
					 | 
				
			||||||
                else:
 | 
					 | 
				
			||||||
                    return dict(data=kwargs)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(schema=LoginSchema(),
 | 
					 | 
				
			||||||
                    error_handler='/errors_with_handler')
 | 
					 | 
				
			||||||
            def with_handler(self, **kwargs):
 | 
					 | 
				
			||||||
                return '%s:%s' % (kwargs['username'], kwargs['password'])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose('mako:form_login.html')
 | 
					 | 
				
			||||||
            def errors_with_handler(self):
 | 
					 | 
				
			||||||
                return dict()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def _get_contents(filename):
 | 
					 | 
				
			||||||
            return open(os.path.join(self.template_path, filename), 'r').read()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test without error handler
 | 
					 | 
				
			||||||
        app = TestApp(
 | 
					 | 
				
			||||||
            make_app(RootController(), template_path=self.template_path)
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        r = app.post('/', {
 | 
					 | 
				
			||||||
            'username': 'ryan',
 | 
					 | 
				
			||||||
            'password': 'password'
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == _get_contents('form_login_valid.html')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test failure without error handler
 | 
					 | 
				
			||||||
        r = app.post('/', {
 | 
					 | 
				
			||||||
            'username': 'ryan',
 | 
					 | 
				
			||||||
            'password': ''
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == _get_contents('form_login_invalid.html')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test with error handler
 | 
					 | 
				
			||||||
        r = app.post('/with_handler', {
 | 
					 | 
				
			||||||
            'username': 'ryan',
 | 
					 | 
				
			||||||
            'password': 'password'
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'ryan:password'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test failure with error handler
 | 
					 | 
				
			||||||
        r = app.post('/with_handler', {
 | 
					 | 
				
			||||||
            'username': 'ryan',
 | 
					 | 
				
			||||||
            'password': ''
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == _get_contents('form_login_invalid.html')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_error_for(self):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if 'mako' not in builtin_renderers:
 | 
					 | 
				
			||||||
            return
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        class ColorSchema(Schema):
 | 
					 | 
				
			||||||
            colors = ForEach(validators.String(not_empty=True))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        class RootController(object):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(template='mako:error_for.html')
 | 
					 | 
				
			||||||
            def errors(self, *args, **kwargs):
 | 
					 | 
				
			||||||
                return dict()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(template='mako:error_for.html',
 | 
					 | 
				
			||||||
                    schema=ColorSchema(),
 | 
					 | 
				
			||||||
                    variable_decode=True)
 | 
					 | 
				
			||||||
            def index(self, **kwargs):
 | 
					 | 
				
			||||||
                return dict()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(schema=ColorSchema(),
 | 
					 | 
				
			||||||
                    error_handler='/errors',
 | 
					 | 
				
			||||||
                    variable_decode=True)
 | 
					 | 
				
			||||||
            def with_handler(self, **kwargs):
 | 
					 | 
				
			||||||
                return dict()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(template='mako:error_for.html',
 | 
					 | 
				
			||||||
                    json_schema=ColorSchema(),
 | 
					 | 
				
			||||||
                    variable_decode=True)
 | 
					 | 
				
			||||||
            def json(self, data):
 | 
					 | 
				
			||||||
                return dict()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(json_schema=ColorSchema(),
 | 
					 | 
				
			||||||
                    error_handler='/errors',
 | 
					 | 
				
			||||||
                    variable_decode=True)
 | 
					 | 
				
			||||||
            def json_with_handler(self, data):
 | 
					 | 
				
			||||||
                return dict()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test without error handler
 | 
					 | 
				
			||||||
        app = TestApp(
 | 
					 | 
				
			||||||
            make_app(RootController(), template_path=self.template_path)
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        r = app.post('/', {
 | 
					 | 
				
			||||||
            'colors-0': 'blue',
 | 
					 | 
				
			||||||
            'colors-1': 'red'
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == ''
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test failure without error handler
 | 
					 | 
				
			||||||
        r = app.post('/', {
 | 
					 | 
				
			||||||
            'colors-0': 'blue',
 | 
					 | 
				
			||||||
            'colors-1': ''
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'Please enter a value'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test failure with error handler
 | 
					 | 
				
			||||||
        r = app.post('/with_handler', {
 | 
					 | 
				
			||||||
            'colors-0': 'blue',
 | 
					 | 
				
			||||||
            'colors-1': ''
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'Please enter a value'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test JSON failure without error handler
 | 
					 | 
				
			||||||
        r = app.post('/json', dumps({
 | 
					 | 
				
			||||||
            'colors-0': 'blue',
 | 
					 | 
				
			||||||
            'colors-1': ''
 | 
					 | 
				
			||||||
        }), [('content-type', 'application/json')])
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'Please enter a value'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test JSON failure with error handler
 | 
					 | 
				
			||||||
        r = app.post('/json_with_handler', dumps({
 | 
					 | 
				
			||||||
            'colors-0': 'blue',
 | 
					 | 
				
			||||||
            'colors-1': ''
 | 
					 | 
				
			||||||
        }), [('content-type', 'application/json')])
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'Please enter a value'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_callable_error_handler(self):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        class ColorSchema(Schema):
 | 
					 | 
				
			||||||
            colors = ForEach(validators.String(not_empty=True))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        class RootController(object):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose()
 | 
					 | 
				
			||||||
            def errors(self, *args, **kwargs):
 | 
					 | 
				
			||||||
                return 'There was an error!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(schema=ColorSchema(),
 | 
					 | 
				
			||||||
                    error_handler=lambda: '/errors',
 | 
					 | 
				
			||||||
                    variable_decode=True)
 | 
					 | 
				
			||||||
            def index(self, **kwargs):
 | 
					 | 
				
			||||||
                return 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test with error handler
 | 
					 | 
				
			||||||
        app = TestApp(make_app(RootController()))
 | 
					 | 
				
			||||||
        r = app.post('/', {
 | 
					 | 
				
			||||||
            'colors-0': 'blue',
 | 
					 | 
				
			||||||
            'colors-1': 'red'
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test with error handler
 | 
					 | 
				
			||||||
        r = app.post('/', {
 | 
					 | 
				
			||||||
            'colors-0': 'blue',
 | 
					 | 
				
			||||||
            'colors-1': ''
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'There was an error!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_validation_exception(self):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if 'mako' not in builtin_renderers:
 | 
					 | 
				
			||||||
            return
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        class NameSchema(Schema):
 | 
					 | 
				
			||||||
            name = validators.String(not_empty=True)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        class SubController(object):
 | 
					 | 
				
			||||||
            @expose()
 | 
					 | 
				
			||||||
            def _route(self, *args):
 | 
					 | 
				
			||||||
                raise ValidationException('/success')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        class RootController(object):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            sub = SubController()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose('mako:form_name.html')
 | 
					 | 
				
			||||||
            def errors_name(self):
 | 
					 | 
				
			||||||
                return dict()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose(schema=NameSchema(),
 | 
					 | 
				
			||||||
                    error_handler='/errors_name',
 | 
					 | 
				
			||||||
                    htmlfill=dict(auto_insert_errors=True))
 | 
					 | 
				
			||||||
            def name(self, name):
 | 
					 | 
				
			||||||
                raise ValidationException(
 | 
					 | 
				
			||||||
                    errors={'name': 'Names must be unique'}
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @expose()
 | 
					 | 
				
			||||||
            def success(self):
 | 
					 | 
				
			||||||
                return 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        def _get_contents(filename):
 | 
					 | 
				
			||||||
            return open(os.path.join(self.template_path, filename), 'r').read()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test exception with no controller
 | 
					 | 
				
			||||||
        app = TestApp(
 | 
					 | 
				
			||||||
            make_app(RootController(), template_path=self.template_path)
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        r = app.get('/sub')
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == 'Success!'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # test exception with additional errors
 | 
					 | 
				
			||||||
        r = app.post('/name', {'name': 'Yoann'})
 | 
					 | 
				
			||||||
        assert r.status_int == 200
 | 
					 | 
				
			||||||
        assert r.body == _get_contents('form_name_invalid_custom.html')
 | 
					 | 
				
			||||||
		Reference in New Issue
	
	Block a user