> Hello,
>
> I wonder why this test fails:
>
> def test_options():
> w = MultipleSelectField(options="Group1 Group2 Group3".split())
> eq_(['Group3', 'Group1'], w.validate(['Group3', 'Group1']))
> print w.validate(['GroupX'])
> assert 0, "formencode.Invalid not raised"
>
> I was assuming that the select widget will only accept options that
> are in the options list. No?
This is a tricky case. For that test to pass a OneOf valiadator is
needed, however, that would break the callable support for the
"options" parameter since the validator is fixed at construction
time. I can think of 2 ways to solve it:
1) avoid using a callable for "options" and pass a OneOf validator
explicitly
2) Use a hidden field to store view state and make validators aware
of it to validate accordingly.
2 is probably the best option in the long-run but the hardest to
design/implement. It would also allow disabling fields dynamically
which is now not possible for required fields since validation would
fail.
Ideas?
Alberto
P.S: Cross-posting to toscawidgets-discuss
Alberto,
On 4/5/07, Alberto Valverde <alb...@toscat.net> wrote:
> def test_options():
> w = MultipleSelectField(options="Group1 Group2 Group3".split())
> eq_(['Group3', 'Group1'], w.validate(['Group3', 'Group1']))
> print w.validate(['GroupX'])
> assert 0, "formencode.Invalid not raised"
>
> I was assuming that the select widget will only accept options that
> are in the options list. No?
This is a tricky case. For that test to pass a OneOf valiadator is
needed, however, that would break the callable support for the
"options" parameter since the validator is fixed at construction
time. I can think of 2 ways to solve it:
1) avoid using a callable for "options" and pass a OneOf validator
explicitly
That's hardly an option (sorry for pun) -- callable are invaluable in certain situations.
2) Use a hidden field to store view state and make validators aware
of it to validate accordingly.
What's a "view state"?
By design, widgets are static: you can create one as a module global and keep using it for the program's lifetime.
OTOH, to validate with OneOf you need to know which options were actually used to render the form last time and this information has to be kept somewhere. You can pickle and sign this into a bundle and put as a hidden field on a form. Is it what you means?
It may be not very elegant but I don't see a better way. You can also save options temporarily in the the widget itself and passing some bucket-id as a hidden. This can also work as long as widgets does it in a thread safe way.
It may be not very elegant but I don't see a better way. You can also save options temporarily in the the widget itself and passing some bucket-id as a hidden. This can also work as long as widgets does it in a thread safe way.I've heard ASP does something similar. I don't thiink that saving options temporarily in the widget is a viable solution because they have to survive across requests. How could we handle that?
On 4/5/07, Alberto Valverde <alb...@toscat.net> wrote:
It may be not very elegant but I don't see a better way. You can also save options temporarily in the the widget itself and passing some bucket-id as a hidden. This can also work as long as widgets does it in a thread safe way.I've heard ASP does something similar. I don't thiink that saving options temporarily in the widget is a viable solution because they have to survive across requests. How could we handle that?
It is certainly doable and not too complicated.
To render a widget you need to convert all options to strings, right?
So you just concat all the strings together, take md5 hexdigest out of it and use it as a key to thread-safe hash to store the actual values.
Then you need to pass this digest down to the form so that it's get submitted and the options can be retrieved from the hashmap.
> It is certainly doable and not too complicated.
>
> To render a widget you need to convert all options to strings, right?
>
> So you just concat all the strings together, take md5 hexdigest out of it
> and use it as a key to thread-safe hash to store the actual values.
>
> Then you need to pass this digest down to the form so that it's get
> submitted and the options can be retrieved from the hashmap.
Where would you store this hashmap? What about applications without database
servers? Or heavy loaded database servers and very complex forms?
--
Jorge Godoy <jgo...@gmail.com>
> Saving this "view-state" is certainly not hard, what I'm not sure how
Do you think so? I'm thinking on a distributed server scenario, where one
request can go to server1 and the submit to server5... I'm also thinking on
how much memory would one need in a one server scenario with 300 or 400 users
using the system and having some complex forms to fill (usually a digital
version of a one or two paper pages forms...).
> hard it would be is to generalize this enough and integrate with
> formencode...
This is always a problem on some designs to me as well :-) Custom widgets
aren't always easy...
> This can be used to add another similar attribute, maybe,
> InputWidget.view_state which could be a dict where each widget that
> needs saving this state can place a key there which the form will
> finally picke and sign (in a similar manner SecureFormMixin does to
> prevent CSRF attacks) before rendering. The form would also take care
> of unsigning and de-pickling and passing the saved state to the Schema.
>
> However, I haven't thought of a way yet for the validators to make
> good use of this info in a general enough way...
Maybe you'll need some glue code to decode that and pass it to validators in a
more usual way...
> a simple md5 digest wouldn't be very secure I guess. Keep in mind
> this info will affect how validation will occur so it's esssential
> for it to be secure to prevent attacks. SecureFormMixin uses hmac
> plus a secret which I think it's safer.
And is also easy to compute.
--
Jorge Godoy <jgo...@gmail.com>
> To render a widget you need to convert all options to strings, right?
>
> So you just concat all the strings together, take md5 hexdigest out of it
> and use it as a key to thread-safe hash to store the actual values.
>
> Then you need to pass this digest down to the form so that it's get
> submitted and the options can be retrieved from the hashmap.
Where would you store this hashmap? What about applications without database
servers? Or heavy loaded database servers and very complex forms?
So you just concat all the strings together, take md5 hexdigest out of it and use it as a key to thread-safe hash to store the actual values.a simple md5 digest wouldn't be very secure I guess. Keep in mind this info will affect how validation will occur so it's esssential for it to be secure to prevent attacks. SecureFormMixin uses hmac plus a secret which I think it's safer.
Then you need to pass this digest down to the form so that it's get submitted and the options can be retrieved from the hashmap.
RequestLocalDescriptor (or a variant of it) can provide the mechanism for inter-widget communication in a thread-safe, request-local way.
On 4/5/07, Alberto Valverde <alb...@toscat.net> wrote:So you just concat all the strings together, take md5 hexdigest out of it and use it as a key to thread-safe hash to store the actual values.a simple md5 digest wouldn't be very secure I guess. Keep in mind this info will affect how validation will occur so it's esssential for it to be secure to prevent attacks. SecureFormMixin uses hmac plus a secret which I think it's safer.
Whatever, the concept is the same.
Then you need to pass this digest down to the form so that it's get submitted and the options can be retrieved from the hashmap.
RequestLocalDescriptor (or a variant of it) can provide the mechanism for inter-widget communication in a thread-safe, request-local way.
I don't know anything about request-local stuff but if there is a way to 'attach' this to request than great - use it and forget about the need for thread-safe global storage.
But there are two requests involved here: first to generate HTML form and another to actually send it (and validate). Does RequestLocalDescriptor handle this?