I took a stab today at splitting @validate in two

the code is pretty darn awful, but I'm hoping some people who are more
familiar with pylons can help whip this up:

a drop-in replacement for @validate is below , as is a new function
validation_error

the functionality is this:

@validate
   has a new auto_error keyword, by default it is true.  this
preserves compatibility
   now sets c.form_errors to {} on every request - successful or not.
   caches for validation_error
        pylons.c.form_validated flag= True
        pylons.c.form_params= params
        pylons.c.form_is_unicode_params= is_unicode_params


def validation_error
   this is the existing functionality of @validate.  nothing new here,
just split...

what do we gain?

now we can spew an error, anywhere:

        c.form_errors['password_new']= "oh no you don't"
        return validation_error( self, form= '_password_change_print',
post_only= True )

this is a first rough stab... some things are working a little weird.
hoping some people more familiar with pylons core / formencode /
htmlfill can chime in







----


def validate(schema=None, validators=None, form=None,
variable_decode=False,
             dict_char='.', list_char='-', post_only=True, state=None,
             on_get=False, auto_error= True, **htmlfill_kwargs):
    """Validate input either for a FormEncode schema, or individual
validators

    Given a form schema or dict of validators, validate will attempt
to
    validate the schema or validator list.

    If validation was successful, the valid result dict will be saved
    as ``self.form_result``. Otherwise, the action will be re-run as
if it was
    a GET, and the output will be filled by FormEncode's htmlfill to
fill in
    the form field errors.

    ``schema``
        Refers to a FormEncode Schema object to use during validation.
    ``form``
        Method used to display the form, which will be used to get
the
        HTML representation of the form for error filling.
    ``variable_decode``
        Boolean to indicate whether FormEncode's variable decode
function
        should be run on the form input before validation.
    ``dict_char``
        Passed through to FormEncode. Toggles the form field naming
        scheme used to determine what is used to represent a dict.
This
        option is only applicable when used with variable_decode=True.
    ``list_char``
        Passed through to FormEncode. Toggles the form field naming
        scheme used to determine what is used to represent a list.
This
        option is only applicable when used with variable_decode=True.
    ``post_only``
        Boolean that indicates whether or not GET (query) variables
should
        be included during validation.

        .. warning::
            ``post_only`` applies to *where* the arguments to be
            validated come from. It does *not* restrict the form to
only
            working with post, merely only checking POST vars.
    ``state``
        Passed through to FormEncode for use in validators that
utilize
        a state object.
    ``on_get``
        Whether to validate on GET requests. By default only POST
requests
        are validated.
    ``auto_error``
        Whether to immediately call the error form. On by default
        You may call validation_error separately
    Example:

    .. code-block:: Python

        class SomeController(BaseController):

            def create(self, id):
                return render('/myform.mako')

            @validate(schema=model.forms.myshema(), form='create')
            def update(self, id):
                # Do something with self.form_result
                pass
    """
    def wrapper(func, self, *args, **kwargs):
        """Decorator Wrapper function"""
        request = pylons.request._current_obj()
        pylons.c.form_errors= {}
        errors = pylons.c.form_errors

        # Skip the validation if on_get is False and its a GET
        if not on_get and request.environ['REQUEST_METHOD'] == 'GET':
            return func(self, *args, **kwargs)

        # If they want post args only, use just the post args
        if post_only:
            params = request.POST
        else:
            params = request.params

        is_unicode_params = isinstance(params, UnicodeMultiDict)
        params = params.mixed()
        if variable_decode:
            log.debug("Running variable_decode on params")
            decoded = variabledecode.variable_decode(params,
dict_char,
                                                     list_char)
        else:
            decoded = params

        if schema:
            log.debug("Validating against a schema")
            try:
                self.form_result = schema.to_python(decoded, state)
            except formencode.Invalid, e:
                errors = e.unpack_errors(variable_decode, dict_char,
list_char)
        if validators:
            log.debug("Validating against provided validators")
            if isinstance(validators, dict):
                if not hasattr(self, 'form_result'):
                    self.form_result = {}
                for field, validator in validators.iteritems():
                    try:
                        self.form_result[field] = \
                            validator.to_python(decoded.get(field),
state)
                    except formencode.Invalid, error:
                        errors[field] = error

        pylons.c.form_validated= True
        pylons.c.form_params= params
        pylons.c.form_is_unicode_params= is_unicode_params


        if errors:
            log.debug("Errors found in validation, parsing form with
htmlfill "
                      "for errors")
            request.environ['REQUEST_METHOD'] = 'GET'
            pylons.c.form_errors = errors

            if auto_error:
                return validation_error( self, form= form,
post_only=post_only, params= params, *args, **kwargs)
            else:
                return func(self, *args, **kwargs)
        return func(self, *args, **kwargs)
    return decorator(wrapper)

def validation_error( self, form=None, post_only=True, params=None,
*args, **htmlfill_kwargs):
    """
        Calls the validation error
    """
    # If there's no form supplied, just continue with the current
    # function call.
    if not form:
        raise ValueError( 'form is required' )

    if not pylons.c.form_validated:
        raise ValueError( 'form has not been validated' )

    request = pylons.request._current_obj()
    errors= pylons.c.form_errors

    request.environ['pylons.routes_dict']['action'] = form
    response = self._dispatch_call()
    # XXX: Legacy WSGIResponse support
    legacy_response = False
    if hasattr(response, 'wsgi_response'):
        form_content = ''.join(response.content)
        legacy_response = True
    else:
        form_content = response
        response = pylons.response._current_obj()

    # Ensure htmlfill can safely combine the form_content, params and
    # errors variables (that they're all of the same string type)
    if not pylons.c.form_is_unicode_params:
        log.debug("Raw string form params: ensuring the '%s' form and
"
                  "FormEncode errors are converted to raw strings for
"
                  "htmlfill", form)
        encoding = determine_response_charset(response)

        # WSGIResponse's content may (unlikely) be unicode
        if isinstance(form_content, unicode):
            form_content = form_content.encode(encoding,
                                               response.errors)

        # FormEncode>=0.7 errors are unicode (due to being localized
        # via ugettext). Convert any of the possible formencode
        # unpack_errors formats to contain raw strings
        errors = encode_formencode_errors(errors, encoding,
                                          response.errors)
    elif not isinstance(form_content, unicode):
        log.debug("Unicode form params: ensuring the '%s' form is "
                  "converted to unicode for htmlfill", form)
        encoding = determine_response_charset(response)
        form_content = form_content.decode(encoding)

    defaults= pylons.c.form_params.copy()
    for item in errors.keys():
        if item in defaults:
           del defaults[item]

    form_content = htmlfill.render(form_content, defaults=defaults,
                                   errors=errors, **htmlfill_kwargs)
    if legacy_response:
        # Let the Controller merge the legacy response
        response.content = form_content
        return response
    else:
        return form_content

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"pylons-discuss" group.
To post to this group, send email to pylons-discuss@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/pylons-discuss?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to