Colander: unflatten invalid.asdict() error

103 views
Skip to first unread message

anh le

unread,
May 8, 2012, 9:52:04 PM5/8/12
to pylons-...@googlegroups.com
Hi all,

I'm using colander to validate json input for my api. To report the
invalid input to user
I try to unflatten the invalid.asdict()

However if the invalid input located in the place other than the first
place in a
sequence the unflatten fails.

Here is the snipets: (as https://gist.github.com/2641011 )

import colander

class Phone(colander.MappingSchema):
location = colander.SchemaNode(colander.String(),
validator=colander.OneOf(['home', 'work']))
number = colander.SchemaNode(colander.String())

class Phones(colander.SequenceSchema):
phone = Phone()

class User(colander.MappingSchema):
name = colander.SchemaNode(colander.Str())
phones = Phones()

user = User()

d1 = {'name': 'jim',
'phones': [{'location': 'office', 'number': '12343'},
{'location': 'home', 'number': '33131'}]
}

try:
user.deserialize(d1)
except colander.Invalid as invalid:
print user.unflatten(invalid.asdict())

# result:
# {'phones': [{'location': u'"office" is not one of home, work'}]}

# place invalid location as second position
d2 = {'name': 'bob',
'phones': [{'location': 'home', 'number': '1234'},
{'location': 'office', 'number': '33131'}]
}

try:
user.deserialize(d2)
except colander.Invalid as invalid:
print user.unflatten(invalid.asdict())

# result:
# ...
# /opt/env/lib/python2.7/site-packages/colander/__init__.py", line
816, in unflatten
# return [mapstruct[str(index)] for index in xrange(len(mapstruct))]
# KeyError: '0'
#

How to handle this error or is there a better way to show the error in
a api (json) validation?

thanks,

Robert Forkel

unread,
May 9, 2012, 12:54:34 AM5/9/12
to pylons-...@googlegroups.com
you may want to have a look at cornice [1]. Among other things it
helps with validating json input via colander and handling resulting
errors.
regards,
robert

[1] http://cornice.readthedocs.org/en/latest/index.html
> --
> You received this message because you are subscribed to the Google Groups "pylons-discuss" group.
> To post to this group, send email to pylons-...@googlegroups.com.
> To unsubscribe from this group, send email to pylons-discus...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/pylons-discuss?hl=en.
>

anh le

unread,
May 10, 2012, 9:35:23 PM5/10/12
to pylons-...@googlegroups.com
On Wed, May 9, 2012 at 11:54 AM, Robert Forkel <xrot...@googlemail.com> wrote:
> you may want to have a look at cornice [1]. Among other things it
> helps with validating json input via colander and handling resulting
> errors.
> regards,
> robert
>
> [1] http://cornice.readthedocs.org/en/latest/index.html

Thank you for cornice suggest, I'm building the json api using Flask,
so I'll look at the cornice's validation part.

regards,

Максим Коринец

unread,
May 14, 2012, 2:19:08 AM5/14/12
to pylons-...@googlegroups.com
I guess you can only flatten/unflatten a valid appstruct (that has been successfully deserialized). Invalid.asdict() returns a flat dictionary with error info, but I wouldn't rely on unflattening it with SchemaNode.unflatten().

The reason I'm interested in this question is that I needed a similar functionality from Invalid.asdict(). I needed error messages translated in it, and since they were not, I had to step through the asdict() code and write my own version of it. Consider this:

...
        try:
            appstruct = some_schema.deserialize(cstruct)
        except Invalid, e:
            for path in e.paths():
...

Now paths() has all the 'raw' error (fields and messages) data to manipulate and construct your own validation error handling mechanism.

anh le

unread,
May 14, 2012, 10:44:41 PM5/14/12
to pylons-...@googlegroups.com
Hello Максим,
I think you're right about unflatten and Invalid.asdict(). Based on
your suggestion,
I try to use the asdict to merge the error msg from asdict() to the
cstruct to show
the errors in-placed as the following:

# cstruct that missing 'name', and 'wrong' location
c ={ 'phones': [{'location': 'home', 'number': '1234'},
{'location': 'office', 'number': '33131'}]
}

try:
user.deserialize(c)
except colander.Invalid as invalid:
for k,msg in invalid.asdict().iteritems():
try:
value = user.get_value(c,k)
except KeyError:
value = None
user.set_value(c, k, "'%s' <-- ERROR %s" % (str(value), msg))
print c

# Result:
{{'phones': [{'location': 'home', 'number': '1234'}, {'location':
u'\'office\' <-- ERROR: "office" is not one of home, work', 'number':
'33131'}],
'name': u"'None' <-- ERROR: Required"}


Regards,
Reply all
Reply to author
Forward
0 new messages