Thanks for the snippet above, Ian.

> 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 ?

I think the validator must raise an exception in such a case.

I'm going to create a ticket in the formencode's tracker. Do you have
any additional suggestions that should be mentioned in it?


On Feb 11, 5:10 am, Ian Wilson <[email protected]> wrote:
> 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''
>
> -Ian
>
> On Thu, Feb 10, 2011 at 2:52 PM, Maxim Avanov <[email protected]>wrote:
>
> > Hi, Ian. Thanks for reply.
>
> > >If you want to be EXTRA strict then you could try ConfirmType and
> > UnicodeString combined in an All validator to catch this error. Or something
> > to that effect.
>
> > This solution will work, but I wouldn't like to use it for several
> > reasons. First of all, we already have a huge code base that
> > intensively uses UnicodeStrings.  Surely, we could define our own
> > UnicodeString validator like below,
>
> > UnicodeString =
> > formencode.All(formencode.ConfirmType(subclass=unicode),
> > formencode.UnicodeString())
>
> > but we trying to keep our design clean.  Moreover, "All" and
> > "ConfirmType" require extra validation steps (and hence more function
> > calls). I think it has to be solved in more generic and concise way
> > (i.e. in formencode's internal api level).
>
> > > Also note that someone could actually send ?username=[u'John', u'Mike']
> > in
> > > the query which would exhibit similar behavior.
>
> > Yes, and it is the place where the inconsistency of validators
> > behaviour comes. if we'd have an unified behaviour for all single-
> > value validators (Int, UnicodeString, Bool etc.) we could get
> > "[u'John', u'Mike']" result only for "/?username=[u'John', u'Mike']"
> > request. But now, we can get the same result by the two different
> > requests - by "/?username=[u'John', u'Mike']" and by "/?
> > username=John&username=Mike". This shouldn't be allowed. And it's not
> > allowed for all single-value validators except the UnicodeString.
>
> > > If we don't use mixed then how do we get the multiple values when we want
> > > them?
>
> > We might explicitly specify our expectations with ForEach() and Set()
> > validators.
> > formencode's FancyValidator could internally test currently running
> > validator by calling something like
>
> > isinstance(current_validator, ForEach)
>
> > and then perform appropriate actions for this case (i.e. call single-
> > value validator for each found item with the same key).
>
> > P.S. I hope Ian Bicking will see this topic and give his opinion all
> > about this, as I might miss something important here.
>
> > On Feb 9, 6:38 am, Ian Wilson <[email protected]> wrote:
> > > Hi,
>
> > > I think this behavior happens because mixed is used herehttps://
> > bitbucket.org/ianb/formencode/src/d95237b33f3c/formencode/api....
> > > If you don't want that to happen ever then I think you need to cast
> > params
> > > to a regular dictionary, with something like
> > dict(request.params.items()).
> > > This will silently ignore one of the names though which might be worse.
>
> > > If you want to be EXTRA strict then you could try ConfirmType and
> > > UnicodeString combined in an All validator to catch this error.  Or
> > > something to that effect.
>
> > > Also note that someone could actually send ?username=[u'John', u'Mike']
> > in
> > > the query which would exhibit similar behavior.  So as far as I can tell
> > if
> > > that is a problem you'd need to validate it either way.
>
> > > I agree that this might be misleading but its a difficult problem to
> > solve.
> > > If we don't use mixed then how do we get the multiple values when we want
> > > them?  I think formencode might just need better internal integration
> > with
> > > multiple value dictionaries so that different types don't show up
> > depending
> > > on the input.  It tries to be input agnostic though.
>
> > > -Ian
>
> > > On Tue, Feb 8, 2011 at 10:25 AM, Maxim Avanov <[email protected]
> > >wrote:
>
> > > > Here's an example.
>
> > > > # =====================
> > > > from formencode import Schema, Invalid
> > > > from formencode.validators import UnicodeString, Int
> > > > from webob import Request
>
> > > > class StrictSchema(Schema):
> > > >    allow_extra_fields = False
>
> > > > class IntegerTestSchema(StrictSchema):
> > > >    testfield = Int(not_empty=True)
>
> > > > class StringTestSchema(StrictSchema):
> > > >    testfield = UnicodeString(not_empty=True)
>
> > > > # Testing.
> > > > # =====================
> > > > req = Request.blank('/?testfield=111')
> > > > print IntegerTestSchema.to_python(req.params)
>
> > > > # This raises an exception
> > > > req = Request.blank('/?testfield=111&testfield=222')
> > > > try:
> > > >    IntegerTestSchema.to_python(req.params)
> > > > except Invalid as e:
> > > >    print "Caught Exception: {0}".format(e)
>
> > > > req = Request.blank('/?testfield=aaa')
> > > > print StringTestSchema.to_python(req.params)
>
> > > > # This will be passed successfully (!)
> > > > # The output will be {'testfield': u"[u'aaa', u'bbb']"}
> > > > req = Request.blank('/?testfield=aaa&testfield=bbb')
> > > > print StringTestSchema.to_python(req.params)
>
> > > > # ========================
>
> > > > Please note we do not use formencode.ForEach() or formencode.Set()
> > > > here. I think this is very unclear behaviour.
> > > > Imagine an UsernameValidator (or something related to "not-so-strict-
> > > > string-validator"). Instead of indicating an input error, we show the
> > > > service realization details to our users -- "{'username': u"[u'John',
> > > > u'Mike']"}" - "Ok. This is Python list inside the dict".
>
> > > > According to WebOb documentation (http://pythonpaste.org/webob/
> > > > #multidict), we probably should use request.GET.getone() instead of
> > > > request.GET.getall().
>
> > > > --
> > > > You received this message because you are subscribed to the Google
> > Groups
> > > > "pylons-discuss" group.
> > > > To post to this group, send email to [email protected].
> > > > 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.
>
> > --
> > You received this message because you are subscribed to the Google Groups
> > "pylons-discuss" group.
> > To post to this group, send email to [email protected].
> > 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.

-- 
You received this message because you are subscribed to the Google Groups 
"pylons-discuss" group.
To post to this group, send email to [email protected].
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