Question

Problem:

I have a form in TurboGears 2 that has a text field for a list of e-mails. Is there a simple way using ToscaWidgets or FormEncode to chain form validators for Set and Email or will I have to write my own validator for this?

Was it helpful?

Solution

I think it should be more like the below. It has the advantage of trying each email instead of just stopping at the first invalid. It will also add the errors to the state so you could tell which ones had failed.

from formencode import FancyValidator, Invalid
from formencode.validators import Email

class EmailList(FancyValidator):
    """ Takes a delimited (default is comma) string and returns a list of validated e-mails
        Set the delimiter by passing delimiter="A_DELIMITER" to the constructor.
        Also takes all arguments a FancyValidator does.  
        The e-mails will always be stripped of whitespace.
    """
    def _to_python(self, value, state):
        try:
            values = str(value).split(self.delimiter)
        except AttributeError:
            values = str(value).split(',')
        validator = formencode.ForEach(validators.Email())
        validator.to_python(values, state)
        return [value.strip() for value in values]

OTHER TIPS

from http://formencode.org/Validator.html

Another notable validator is formencode.compound.All – this is a compound validator – that is, it’s a validator that takes validators as input. Schemas are one example; in this case All takes a list of validators and applies each of them in turn. formencode.compound.Any is its compliment, that uses the first passing validator in its list.

What I wanted was a validator I could just stick into a field like the String and Int validators. I found there was no way to do this unless I created my own validator. I'm posting it here for completeness sake, and so others can benefit.

from formencode import FancyValidator, Invalid
from formencode.validators import Email

class EmailList(FancyValidator):
    """ Takes a delimited (default is comma) string and returns a list of validated e-mails
        Set the delimiter by passing delimiter="A_DELIMITER" to the constructor.
        Also takes all arguments a FancyValidator does.  
        The e-mails will always be stripped of whitespace.
    """
    def _to_python(self, value, state):
        try:
            values = str(value).split(self.delimiter)
        except AttributeError:
            values = str(value).split(',')
        returnValues = []
        emailValidator = Email()
        for value in values:
            returnValues.append( emailValidator._to_python(value.strip(), state) )
        return values

With FormEncode validators - Pipe and Wrapper, you could:

from formencode import validators, compound


compound.Pipe(validators.Wrapper(to_python=lambda v: v.split(',')),
              validators.Email())
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top