Adding optional argument to ValidationException to specify custom field errors

This commit is contained in:
Yoann Roman
2011-01-25 17:59:00 -05:00
parent 6b0656e755
commit 8922dc4d7d
5 changed files with 89 additions and 46 deletions

View File

@@ -7,6 +7,7 @@ from webob import Request, Response, exc
from threading import local
from itertools import chain
from formencode import htmlfill, Invalid, variabledecode
from formencode.schema import merge_dicts
from paste.recursive import ForwardRequestException
try:
@@ -58,12 +59,13 @@ def redirect(location, internal=False, code=None, headers={}):
def error_for(field):
if request.validation_errors is None: return ''
if not request.validation_errors:
return ''
return request.validation_errors.get(field, '')
class ValidationException(ForwardRequestException):
def __init__(self, location=None):
def __init__(self, location=None, errors={}):
if hasattr(state, 'controller'):
cfg = _cfg(state.controller)
else:
@@ -72,6 +74,7 @@ class ValidationException(ForwardRequestException):
location = cfg['error_handler']
if callable(location):
location = location()
merge_dicts(request.validation_errors, errors)
request.environ['pecan.params'] = dict(request.str_params)
request.environ['pecan.validation_errors'] = request.validation_errors
if cfg.get('htmlfill') is not None:
@@ -178,7 +181,7 @@ class Pecan(object):
def validate(self, schema, params, json=False, error_handler=None,
htmlfill=None, variable_decode=None):
request.validation_errors = None
request.validation_errors = {}
try:
to_validate = params
if json:

View File

@@ -0,0 +1,3 @@
<!-- for: name -->
<span class="error-message">Names must be unique</span><br />
<input type="text" id="name" name="name" value="Yoann" class="error" />

View File

@@ -3,7 +3,7 @@ from paste.recursive import ForwardRequestException
from unittest import TestCase
from webtest import TestApp
from pecan import Pecan, expose, request, response, redirect, abort, make_app, ValidationException
from pecan import Pecan, expose, request, response, redirect, abort, make_app
from pecan.templating import _builtin_renderers as builtin_renderers
import os
@@ -543,25 +543,6 @@ class TestBase(TestCase):
app = make_app(RootController(), wrap_app=wrap, debug=True)
assert len(wrapped_apps) == 1
def test_validation_exception(self):
class SubController(object):
@expose()
def _route(self, *args):
raise ValidationException('/success')
class RootController(object):
sub = SubController()
@expose()
def success(self):
return 'Success!'
app = TestApp(make_app(RootController()))
r = app.get('/sub')
assert r.status_int == 200
assert r.body == 'Success!'
class TestEngines(object):

View File

@@ -696,7 +696,7 @@ class TestHooks(object):
password_confirm,
age):
run_hook.append('inside')
return str(request.validation_errors is not None)
return str(len(request.validation_errors) > 0)
@expose(schema=RegistrationSchema(), error_handler='/errors')
def with_handler(self, first_name,
@@ -707,7 +707,7 @@ class TestHooks(object):
password_confirm,
age):
run_hook.append('inside')
return str(request.validation_errors is not None)
return str(len(request.validation_errors) > 0)
# test that the hooks get properly run with no validation errors
app = TestApp(make_app(RootController(), hooks=[SimpleHook()]))

View File

@@ -3,7 +3,7 @@ from webtest import TestApp
import os.path
from pecan import make_app, expose, request, response, redirect
from pecan import make_app, expose, request, response, redirect, ValidationException
from pecan.templating import _builtin_renderers as builtin_renderers
try:
@@ -95,7 +95,7 @@ class TestValidation(object):
@expose()
def errors(self, *args, **kwargs):
assert request.validation_errors is not None
assert len(request.validation_errors) > 0
return 'There was an error!'
@expose(schema=RegistrationSchema())
@@ -106,7 +106,7 @@ class TestValidation(object):
password,
password_confirm,
age):
assert request.validation_errors is not None
assert len(request.validation_errors) > 0
return 'Success!'
@expose(schema=RegistrationSchema(), error_handler='/errors')
@@ -117,17 +117,17 @@ class TestValidation(object):
password,
password_confirm,
age):
assert request.validation_errors is not None
assert len(request.validation_errors) > 0
return 'Success!'
@expose(json_schema=RegistrationSchema())
def json(self, data):
assert request.validation_errors is not None
assert len(request.validation_errors) > 0
return 'Success!'
@expose(json_schema=RegistrationSchema(), error_handler='/errors')
def json_with_handler(self, data):
assert request.validation_errors is not None
assert len(request.validation_errors) > 0
return 'Success!'
@@ -198,7 +198,7 @@ class TestValidation(object):
@expose(schema=ColorSchema(),
variable_decode=True)
def index(self, **kwargs):
if request.validation_errors is not None:
if request.validation_errors:
return ', '.join(request.validation_errors.keys())
else:
return 'Success!'
@@ -207,7 +207,7 @@ class TestValidation(object):
error_handler='/errors',
variable_decode=True)
def with_handler(self, **kwargs):
if request.validation_errors is not None:
if request.validation_errors:
return ', '.join(request.validation_errors.keys())
else:
return 'Success!'
@@ -215,7 +215,7 @@ class TestValidation(object):
@expose(json_schema=ColorSchema(),
variable_decode=True)
def json(self, data):
if request.validation_errors is not None:
if request.validation_errors:
return ', '.join(request.validation_errors.keys())
else:
return 'Success!'
@@ -224,7 +224,7 @@ class TestValidation(object):
error_handler='/errors',
variable_decode=True)
def json_with_handler(self, data):
if request.validation_errors is not None:
if request.validation_errors:
return ', '.join(request.validation_errors.keys())
else:
return 'Success!'
@@ -232,7 +232,7 @@ class TestValidation(object):
@expose(schema=ColorSchema(),
variable_decode=dict())
def custom(self, **kwargs):
if request.validation_errors is not None:
if request.validation_errors:
return ', '.join(request.validation_errors.keys())
else:
return 'Success!'
@@ -241,7 +241,7 @@ class TestValidation(object):
error_handler='/errors',
variable_decode=dict())
def custom_with_handler(self, **kwargs):
if request.validation_errors is not None:
if request.validation_errors:
return ', '.join(request.validation_errors.keys())
else:
return 'Success!'
@@ -249,7 +249,7 @@ class TestValidation(object):
@expose(json_schema=ColorSchema(),
variable_decode=dict())
def custom_json(self, data):
if request.validation_errors is not None:
if request.validation_errors:
return ', '.join(request.validation_errors.keys())
else:
return 'Success!'
@@ -258,7 +258,7 @@ class TestValidation(object):
error_handler='/errors',
variable_decode=dict())
def custom_json_with_handler(self, data):
if request.validation_errors is not None:
if request.validation_errors:
return ', '.join(request.validation_errors.keys())
else:
return 'Success!'
@@ -266,7 +266,7 @@ class TestValidation(object):
@expose(schema=ColorSchema(),
variable_decode=dict(dict_char='-', list_char='.'))
def alternate(self, **kwargs):
if request.validation_errors is not None:
if request.validation_errors:
return ', '.join(request.validation_errors.keys())
else:
return 'Success!'
@@ -275,7 +275,7 @@ class TestValidation(object):
error_handler='/errors',
variable_decode=dict(dict_char='-', list_char='.'))
def alternate_with_handler(self, **kwargs):
if request.validation_errors is not None:
if request.validation_errors:
return ', '.join(request.validation_errors.keys())
else:
return 'Success!'
@@ -283,7 +283,7 @@ class TestValidation(object):
@expose(json_schema=ColorSchema(),
variable_decode=dict(dict_char='-', list_char='.'))
def alternate_json(self, data):
if request.validation_errors is not None:
if request.validation_errors:
return ', '.join(request.validation_errors.keys())
else:
return 'Success!'
@@ -292,7 +292,7 @@ class TestValidation(object):
error_handler='/errors',
variable_decode=dict(dict_char='-', list_char='.'))
def alternate_json_with_handler(self, data):
if request.validation_errors is not None:
if request.validation_errors:
return ', '.join(request.validation_errors.keys())
else:
return 'Success!'
@@ -627,6 +627,9 @@ class TestValidation(object):
def test_error_for(self):
if 'mako' not in builtin_renderers:
return
class ColorSchema(Schema):
colors = ForEach(validators.String(not_empty=True))
@@ -662,6 +665,14 @@ class TestValidation(object):
# 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' : ''
@@ -669,7 +680,7 @@ class TestValidation(object):
assert r.status_int == 200
assert r.body == 'Please enter a value'
# test with error handler
# test failure with error handler
r = app.post('/with_handler', {
'colors-0' : 'blue',
'colors-1' : ''
@@ -677,7 +688,7 @@ class TestValidation(object):
assert r.status_int == 200
assert r.body == 'Please enter a value'
# test JSON without error handler
# test JSON failure without error handler
r = app.post('/json', dumps({
'colors-0' : 'blue',
'colors-1' : ''
@@ -685,7 +696,7 @@ class TestValidation(object):
assert r.status_int == 200
assert r.body == 'Please enter a value'
# test JSON with error handler
# test JSON failure with error handler
r = app.post('/json_with_handler', dumps({
'colors-0' : 'blue',
'colors-1' : ''
@@ -726,3 +737,48 @@ class TestValidation(object):
})
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')