Permalink
Browse files

Support validation dict using TW2 validators and make validation less…

… dependant from FormEncode
  • Loading branch information...
1 parent 6299183 commit 6e4db533d59cedbbec8268d4ef53674ad4d3e94d @amol- amol- committed May 25, 2012
Showing with 84 additions and 40 deletions.
  1. +12 −0 tests/test_validation.py
  2. +23 −32 tg/controllers/decoratedcontroller.py
  3. +0 −8 tg/util.py
  4. +49 −0 tg/validation.py
View
@@ -143,6 +143,11 @@ def tw2form_error_handler(self, **kwargs):
def send_tw2_to_error_handler(self, **kwargs):
return 'passed validation'
+ @expose()
+ @validate({'param':tw2c.IntValidator()})
+ def tw2_dict_validation(self, **kwargs):
+ return str(pylons.tmpl_context.form_errors)
+
@expose()
def set_lang(self, lang=None):
pylons.session['tg_lang'] = lang
@@ -262,6 +267,13 @@ def test_tw2form_validation(self):
assert "Must be an integer" in values['errors']['year'],\
'Error message not found: %r' % values['errors']
+ def test_tw2dict_validation(self):
+ resp = self.app.post('/tw2_dict_validation', {'param': "7"})
+ assert '{}' in resp.body
+
+ resp = self.app.post('/tw2_dict_validation', {'param': "hello"})
+ assert 'Must be an integer' in resp.body
+
def test_form_validation_translation(self):
"""Test translation of form validation error messages"""
form_values = {'title': 'Razer', 'year': "t007"}
@@ -29,29 +29,14 @@ def strip_string(s):
from tg.jsonify import JsonEncodeError
from tg.render import render as tg_render
from tg.controllers.util import pylons_formencode_gettext
-from tg.util import _navigate_tw2form_children
+from tg.validation import (_navigate_tw2form_children, _FormEncodeSchema,
+ _FormEncodeValidationError, _format_compound_error,
+ _Tw2ValidationError, validation_errors,
+ _FormEncodeValidator, TGValidationError)
# Load tw (ToscaWidets) only on demand
tw = None
-try:
- from tw2.core import ValidationError as Tw2ValidationError
-except ImportError:
- class Tw2ValidationError(Exception):
- """ToscaWidgets2 Validation Error"""
-
-try:
- from formencode.api import Invalid as FormEncodeValidationError
- from formencode import Schema as FormEncodeSchema
- from formencode.schema import format_compound_error
-except ImportError:
- class FormEncodeValidationError(Exception):
- """FormEncode Invalid"""
- class FormEncodeSchema(object):
- """FormEncode Schema"""
- def format_compound_error(*arg, **kw):
- """FormEncode format_compound_error"""
-
# @expose(content_type=CUSTOM_CONTENT_TYPE) won't
# override pylons.request.content_type
CUSTOM_CONTENT_TYPE = 'CUSTOM/LEAVE'
@@ -136,7 +121,7 @@ def _call(self, controller, params, remainder=None):
# call controller method
output = controller_callable(*remainder, **dict(params))
- except (FormEncodeValidationError, Tw2ValidationError) , inv:
+ except validation_errors, inv:
controller, output = self._handle_validation_errors(
controller, remainder, params, inv)
@@ -180,8 +165,7 @@ def _perform_validate(self, controller, params):
return params
# An object used by FormEncode to get translator function
- state = type('state', (),
- {'_': staticmethod(pylons_formencode_gettext)})
+ formencode_state = type('state', (), {'_': staticmethod(pylons_formencode_gettext)})
#Initialize new_params -- if it never gets updated just return params
new_params = {}
@@ -196,10 +180,13 @@ def _perform_validate(self, controller, params):
errors = {}
for field, validator in validation.validators.iteritems():
try:
- new_params[field] = validator.to_python(params.get(field),
- state)
+ if isinstance(validator, _FormEncodeValidator):
+ new_params[field] = validator.to_python(params.get(field),
+ formencode_state)
+ else:
+ new_params[field] = validator.to_python(params.get(field))
# catch individual validation errors into the errors dictionary
- except FormEncodeValidationError, inv:
+ except validation_errors, inv:
errors[field] = inv
# Parameters that don't have validators are returned verbatim
@@ -210,23 +197,24 @@ def _perform_validate(self, controller, params):
# If there are errors, create a compound validation error based on
# the errors dictionary, and raise it as an exception
if errors:
- raise FormEncodeValidationError(format_compound_error(errors),
- params, None, error_dict=errors)
+ raise TGValidationError(TGValidationError.make_compound_message(errors),
+ value=params,
+ error_dict=errors)
- elif isinstance(validation.validators, FormEncodeSchema):
+ elif isinstance(validation.validators, _FormEncodeSchema):
# A FormEncode Schema object - to_python converts the incoming
# parameters to sanitized Python values
- new_params = validation.validators.to_python(params, state)
+ new_params = validation.validators.to_python(params, formencode_state)
elif (hasattr(validation.validators, 'validate')
and getattr(validation, 'needs_controller', False)):
# An object with a "validate" method - call it with the parameters
new_params = validation.validators.validate(
- controller, params, state)
+ controller, params, formencode_state)
elif hasattr(validation.validators, 'validate'):
# An object with a "validate" method - call it with the parameters
- new_params = validation.validators.validate(params, state)
+ new_params = validation.validators.validate(params, formencode_state)
# Theoretically this should not happen...
# if new_params is None:
@@ -343,14 +331,17 @@ def _handle_validation_errors(self,
tmpl_context.validation_exception = exception
tmpl_context.form_errors = {}
- if isinstance(exception, Tw2ValidationError):
+ if isinstance(exception, _Tw2ValidationError):
#Fetch all the children and grandchildren of a widget
widget = exception.widget
widget_children = _navigate_tw2form_children(widget.child)
errors = [(child.id, child.error_msg) for child in widget_children]
tmpl_context.form_errors.update(errors)
tmpl_context.form_values = widget.child.value
+ elif isinstance(exception, TGValidationError):
+ tmpl_context.form_errors = exception.error_dict
+ tmpl_context.form_values = exception.value
else:
# Most Invalid objects come back with a list of errors in the format:
#"fieldname1: error\nfieldname2: error"
View
@@ -236,11 +236,3 @@ def _f(*args, **kwargs):
f(*args, **kwargs)
warnings.resetwarnings()
return wrap(_f, f)
-
-def _navigate_tw2form_children(w):
- if getattr(w, 'id', None):
- yield w
- else:
- for c in getattr(w, 'children', []):
- for cc in _navigate_tw2form_children(c):
- yield cc
View
@@ -0,0 +1,49 @@
+try:
+ from tw2.core import ValidationError as _Tw2ValidationError
+except ImportError:
+ class _Tw2ValidationError(Exception):
+ """ToscaWidgets2 Validation Error"""
+
+try:
+ from formencode.api import Invalid as _FormEncodeValidationError
+ from formencode.api import Validator as _FormEncodeValidator
+ from formencode import Schema as _FormEncodeSchema
+ from formencode.schema import format_compound_error as _format_compound_error
+except ImportError, e:
+ class _FormEncodeValidationError(Exception):
+ """FormEncode Invalid"""
+ class _FormEncodeValidator(object):
+ """FormEncode Validator"""
+ class _FormEncodeSchema(object):
+ """FormEncode Schema"""
+ def _format_compound_error(*arg, **kw):
+ """FormEncode format_compound_error"""
+
+def _navigate_tw2form_children(w):
+ if getattr(w, 'id', None):
+ yield w
+ else:
+ for c in getattr(w, 'children', []):
+ for cc in _navigate_tw2form_children(c):
+ yield cc
+
+class TGValidationError(Exception):
+ """Invalid data was encountered during validation.
+
+ The constructor can be passed a short message with
+ the reason of the failed validation.
+ """
+ def __init__(self, msg, value=None, error_dict=None):
+ super(TGValidationError, self).__init__(msg)
+ self.msg = msg
+ self.value = value
+ self.error_dict = error_dict
+
+ @classmethod
+ def make_compound_message(cls, error_dict):
+ return '\n'.join("%s: %s" % errorinfo for errorinfo in error_dict.items())
+
+ def __str__(self):
+ return self.msg
+
+validation_errors = (_Tw2ValidationError, _FormEncodeValidationError, TGValidationError)

0 comments on commit 6e4db53

Please sign in to comment.