After thinking about this more it would probably be better if UnicodeString just had a parameter that turned coercion of everything but instances of basestring and None off. Or maybe another validator was created that did that. It makes more sense for the validator that is assigned that key to respond to both lists and non-lists.
What outcome do you actually want? Only the first or last thing from the list to get validated? Or an error if there is more than one thing ?
Here is a validator I hacked together from the String and UnicodeString validators that only accepts None and basestrings. None and non-unicode strings are both converted to unicode.
class StrictUnicodeString(FancyValidator):
""""""
min = None
max = None
not_empty = None
convert_none = True
encoding = 'utf-8'
messages = {
'notString': "Please enter a string",
'tooLong': "Enter a value less than %(max)i characters long",
'tooShort': "Enter a value %(min)i characters long or more",
'badEncoding' : "Invalid data or incorrect encoding",
}
def __initargs__(self, new_attrs):
if self.not_empty is None and self.min:
self.not_empty = True
def __init__(self, input_encoding=None, output_encoding=None,
convert_none=True, **kw):
FancyValidator.__init__(self, **kw)
self.input_encoding = input_encoding or self.encoding
self.output_encoding = output_encoding or self.encoding
self.convert_none = convert_none
def _to_python(self, value, state):
""" Converts to unicode. """
if self.convert_none and value is None:
value = u''
if not isinstance(value, basestring):
raise Invalid(self.message('notString', state), value, state)
if not isinstance(value, unicode):
try:
value = unicode(value, self.input_encoding)
except UnicodeDecodeError:
raise Invalid(self.message('badEncoding', state), value, state)
return value
def _from_python(self, value, state):
""" Converts to a bytestring. """
if not isinstance(value, unicode):
if hasattr(value, '__unicode__'):
value = unicode(value)
else:
value = str(value)
if isinstance(value, unicode):
value = value.encode(self.output_encoding)
return value
def validate_other(self, value, state):
if (self.max is not None and value is not None
and len(value) > self.max):
raise Invalid(self.message('tooLong', state,
max=self.max),
value, state)
if (self.min is not None
and (not value or len(value) < self.min)):
raise Invalid(self.message('tooShort', state,
min=self.min),
value, state)
def empty_value(self, value):
return u''