[Zope-dev] uncatchable 'Bad Request' exceptions ?

Leonardo Rochael Almeida leo@hiper.com.br
Fri, 24 Aug 2001 15:22:53 -0300


In response to your subject, yes, they are uncatchable. In Python, no matter
what version, string exceptions (and everything else that you 'raise' that is not a
class) can only be catched by identity, not by equality.

So, the only way to catch a string exception is to have this string defined
in the toplevel of some module, raise it by the variable name, and catch it
by the variable name, such as

# module foo.py
BadRequest = 'Bad Request'

...
def badabing(REQUEST):
   ...
   if something:
      raise BadRequest, "this is a very naughty request"


# module bar.py
...
import foo
...
    try:
        foo.badabing(REQUEST)
    except foo.BadRequest, detail:
        # detail == "this is a very naughty request"

what that means is that

raise "something"

cannot be catched but with a generic 'except' and that

except "something":

will never catch anything

With class exceptions things are a bit different, "except" will catch
everything that is an instance of the exception or of one of its
subclasses. You can read more about it in python docs here:
http://python.org/doc/current/lib/module-exceptions.html

and here:
http://python.org/doc/current/tut/node10.html

Now the bummer is that the number of string exceptions in Zope is
staggering, and what is worse, most of them are raised without being
previously delcared. if you type:

# grep -rI "raise [\"']" .

at your zope instalation directory you will get 270 counts as of Zope
2.4.0 of such oddities as 'raise "huh 3?"' 'raise "DAMN!"' and 
'raise "Damn!(2)"', not to mention the various instances of
'Bad Request' "BadRequest" and variants. There are a few places that
actually have the trouble of defining BadRequest = "Bad Request" on
their modules but you try importing one of those from python scripts...

What all this means for us python scripters is that we must catch
everything with a generic 'except' and check string contents!

This sucks. There are lots of "Bad Request"s that we should be able to
catch from python scripts and we simply can't without catching
everything. Not even Python Products can catch those exceptions from
lack of a name to import!

I'd call for an ExceptionJihad but I'm lazy :-) So, instead, I'll just kick
some ideas around:

* String exceptions should be considered bugs in Zope. All exceptions
raised should be subclasses of Exception.

* String exceptions that are raised without being declared first
should not be considered bugs. They should be considered crimes! Their
perpetrators should be shot on sight! :-) The crime should be considered
heinous if the string is calculated on raise, (check
lib/python/ZODB/Connection.py on line 169 for an example).

* All exceptions should be accessible from python script and other
safeguarded code. Security assertions might be needed on top of the
exception classes in this case...

* There could be a predefined Zope exception hierarchy so that people
don't need to invent their own, and so that they know what to subclass. Some
sugestions come to mind, such as BadRequest and Unauthorized, which
should be subclasses of some SiteError or ZopeException, with security
assertions already in place, so that subclassers don't need to worry
about these details unless they want to.

What do you all think?

    Regards, Leo

On Thu, Aug 23, 2001 at 07:28:23PM +0000, Florent Guillaume wrote:
> I guess this is the better place to ask this.
> 
> Zope 2.3.3, python 1.5.2.
> 
> >From a python script I can't seem to catch a 'Bad Request' exception.
> 
> This doesn't work:
> # script1
> raise 'Bad Request', 'foo'
> 
> # script2
> try: context.script1()
> except 'Bad Request', x: return x
> return 'nothing'
> 
> I get a Zope error:
>  Error Type: Bad Request
>  Error Value: foo
> 
> 
> But the following one works...
> # script1
> raise 'bar', 'foo'
> 
> # script2
> try: context.script1()
> except 'bar', x: return x
> return 'nothing'
> 
> 
> And this one too...
> # script1
> raise 'Bad Request', 'foo'
> 
> # script2
> try: context.script1()
> except: return 'something'
> return 'nothing'
> 
> 
> Anyone has an idea ? The exception is raised by another product which I
> don't want to touch (CMF RegistrationTool), and I think I should be able
> to catch them !
> 
> 
> Florent Guillaume
> Nuxeo