Stumped about handling this particular exception...
I asked this question in a different form before but got only silence from the list. I'll give it another try... I'm using ZServer and a snapshot of the Zope CVS directory. When a user of the web site fails to input a required form element, ZServer spits out Server Error: exceptions.ValueError, No input for required field<p>: file: /home/dolphin/skip/src/Zope/lib/python/ZPublisher/Converters.py line: 114 on the controlling terminal and the user sees Error response Error code 500. Message: Internal Server Error. instead of a useful message that will help the user figure out what they did wrong. This makes them think my web site is broken, when it's actually their input that's broken... I've tried tracing the control flow back from Converters.py. I manually figured out the following call chain: HTTPRequest.py, line 246 Publish.py, line 252 The three levels of try statement nesting in Publish.py made it unlikely that I would figure out precisely what happens from the failed Request(). I tried adding a little traceback printing to the field2required function: def field2required(v): if hasattr(v,'read'): v=v.read() else: v=str(v) if strip(v): return v try: raise ValueError, 'No input for required field<p>' except: import sys, traceback ty, va, tb = sys.exc_info() f = open("/tmp/traceback", "a") f.write("\n\n---- %s, %s ----\n" % (ty, va)) traceback.print_tb(tb, None, f) f.write("\n") f.close() raise but all it dumps in /tmp/traceback is information for a single line: ---- exceptions.ValueError, No input for required field performers<p> ---- File "/home/killer-whale/skip/src/Zope/lib/python/ZPublisher/Converters.py", line 115, in field2required raise ValueError, 'No input for required field %s<p>' % k Any reason why it won't show me more of the execution stack? I'm really flummoxed. Any feedback on this problem would be much appreciated. Skip Montanaro | Mojam: "Uniting the World of Music" http://www.mojam.com/ skip@mojam.com | Musi-Cal: http://www.musi-cal.com/ 518-372-5583
At 10:19 PM 4/27/99 -0400, Skip Montanaro wrote:
I asked this question in a different form before but got only silence from the list. I'll give it another try...
I'm sure you're aware of the high volume of the Zope lists. It's more like a tidal wave of other questions rather than silence ;-)
I'm using ZServer and a snapshot of the Zope CVS directory. When a user of the web site fails to input a required form element, ZServer spits out
Server Error: exceptions.ValueError, No input for required field<p>: file: /home/dolphin/skip/src/Zope/lib/python/ZPublisher/Converters.py line: 114
on the controlling terminal and the user sees
Error response
Error code 500.
Message: Internal Server Error.
instead of a useful message that will help the user figure out what they did wrong. This makes them think my web site is broken, when it's actually their input that's broken...
Yes. ZPublisher's type converters are quite primitive. They don't offer much control over how value are coerced and frustratingly they don't allow control over how errors are handled. Finally, there is no interface for extending the converters, i.e. it's hard to figure out how to add your own converters. It may be that ZPublisher doesn't have much business validating form input. When I complain to Jim Fulton that the converters are pretty lame he usually tells me that they are not for form validation, but for argument marshalling. Improving the ZPublisher converters is a worthwhile problem, IMO. In addition, making ZPublisher's error reporting more flexible is also a worthwhile project. In the short term I can recommend these avenues to solve your problem. * Don't use type converters and do all the form validation in your published object. This way you have total control. In fact you can continue to use the type converters if you wish, a la. import ZPublisher.Converters def published_method(spam,eggs): "Convert spam and eggs myself" try: spam=Zpublisher.Converters.field2tokens(spam) except: warn_user() ... * Write your own type converters which do not raise exceptions. Here's an example which would be relevant in your case. import ZPublisher.Converters def my_required(v): "A converter which overrides the standard required converter" try: return ZPublisher.Converters.field2required(v) except: return None ZPublisher.Converters.type_converters['required']=my_required * Subclass HTTPResponse and change the error handling. HTTPResponse now has a _error_html method which can be overridden to provide some control over errors. This option is probably the most work but there are some interesting possibilities here. For example, maybe ZPublisher could be extended by some protocol which allows it to fall back to publishing certain objects/methods when an error is raised trying to publish a given object. Of course, this needs much more thought. Maybe this should be done on the object level, rather than the ZPublisher level. For example, Zope's DTML Documents and Methods call the (acquired) 'standard_error_message' object if an exception is raised while rendering... I'd be happy to hear opinions about how to improve type converters and/or error handling. Hope this helps. -Amos
Amos Latteier wrote:
(snip)
It may be that ZPublisher doesn't have much business validating form input.
I agree. ;)
When I complain to Jim Fulton that the converters are pretty lame he usually tells me that they are not for form validation, but for argument marshalling.
Exactly. Input validation, error reporting, and other UI activities should be done at a much higher level. ZPublisher is a very low-level tool meant for basic communication. Obviously, we made the mistake early on of introducting "required", which really is an input validation feature. This was before we realized that we couldn't hope to do a good job of validation at such a low level.
Improving the ZPublisher converters is a worthwhile problem, IMO.
I agree, It would be nice to do more sophisticated marshalling. ;)
In addition, making ZPublisher's error reporting more flexible is also a worthwhile project.
Well, It would be worthwhile to make ZPublisher provide better hooks to let application handle errors detected by ZPublisher. This is definately on the to do list. I also think that a default value mechanism of some kind would make sense. This would help in other situations too. Jim -- Jim Fulton mailto:jim@digicool.com Technical Director (540) 371-6909 Python Powered! Digital Creations http://www.digicool.com http://www.python.org Under US Code Title 47, Sec.227(b)(1)(C), Sec.227(a)(2)(B) This email address may not be added to any commercial mail list with out my permission. Violation of my privacy with advertising or SPAM will result in a suit for a MINIMUM of $500 damages/incident, $1500 for repeats.
Amos Latteier wrote:
At 10:19 PM 4/27/99 -0400, Skip Montanaro wrote:
instead of a useful message that will help the user figure out what they did wrong. This makes them think my web site is broken, when it's actually their input that's broken...
Yes. ZPublisher's type converters are quite primitive. They don't offer much control over how value are coerced and frustratingly they don't allow control over how errors are handled. Finally, there is no interface for extending the converters, i.e. it's hard to figure out how to add your own converters.
...
In the short term I can recommend these avenues to solve your problem.
* Don't use type converters and do all the form validation in your published object. This way you have total control.
I've also tried to use the type converters were for input validation. Today I usually use a external method for complex forms or dtml for the simple ones. Although it doesn't serve for input validation, I like to: 1. Use :list to guarantee that a multiple selection input (checkbox or multiple select) is returned as a list even if just one is selected 2. :int for the cases where you specify the form value. It is very common to use it with :list to have a list of integers. 3. :text in a textarea field to have a lot of newlines become just one and to have consistent newlines in the text. I've also already used :lines. The problem of these converters is that they aren't good even for marshaling. If you use :int or :float in a text input form you have the chance to get the ugly error screen. Since you don't have any way to control the output screen, it can crash the usability of your site. It's better to use them in very specific situations or in prototypes. Another approach is to use javascript to validate it before submitting it. A js library for this was posted sometime ago in the zope list. It just guarantee that an invalid field won't be submitted if ALL your users have javascript turned on. regards, -- Paulo Eduardo Neves mailto:neves@inf.puc-rio.br PUC-Rio de Janeiro
What if ZPublisher's REQUEST object were to do the following: 1. Perform type conversion dynamically upon being requested for an attribute, instead of statically during creation. 2. Look up and call a method 'marshal_type_x' from the published object when doing said dynamic type conversion, falling back to the built-in type converters if the marshalling function doesn't exist. 3. For performance's sake, cache the result of type conversion once the publishing traversal has completely finished. Now it would be possible, by adding External methods to a Folder, or adding type conversion methods to a class, or any of the other ways to add these marshal_type_x methods, to have specialized validation or marshalling on a local basis, without futzing up too much of ZPublisher's logic. Or... here's another alternative, one which I've implemented in certain of my own ZPublished systems... let DTML methods (SQL methods, External Methods, really any methods) do this 'marshal_type_x' lookup on their own parameters using types specified in their argument specifiers. I.e., if method foo has an arg string "bar:int baz:wumpus spam:cabbage", then forms submitting to method foo would leave off the type specifiers, and foo itself would call marshal_type_int, marshal_type_wumpus, and marshal_type_cabbage before proceeding to the body of the method. This bypasses ZPublisher's marshalling altogether except for :list, :tuple, and :method, which still get used in forms. All other form field names remain untyped at the ZPublisher level and get handled by the published object instead.
participants (5)
-
Amos Latteier -
Jim Fulton -
Paulo Eduardo Neves -
Phillip J. Eby -
skip@mojam.com