Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > How to except the unexpected?

Reply
Thread Tools

How to except the unexpected?

 
 
Rene Pijlman
Guest
Posts: n/a
 
      03-03-2006
One of the things I dislike about Java is the need to declare exceptions
as part of an interface or class definition. But perhaps Java got this
right...

I've writen an application that uses urllib2, urlparse, robotparser and
some other modules in the battery pack. One day my app failed with an
urllib2.HTTPError. So I catch that. But then I get a urllib2.URLError, so
I catch that too. The next day, it encounters a urllib2.HTTPError, then a
IOError, a socket.timeout, httplib.InvalidURL,...

How do you program robustly with these modules throwing all those
different (and sometimes undocumented) exceptions at you?

A catchall seems like a bad idea, since it also catches AttributeErrors
and other bugs in the program.

--
René Pijlman
 
Reply With Quote
 
 
 
 
James Stroud
Guest
Posts: n/a
 
      03-03-2006
Rene Pijlman wrote:
> One of the things I dislike about Java is the need to declare exceptions
> as part of an interface or class definition. But perhaps Java got this
> right...
>
> I've writen an application that uses urllib2, urlparse, robotparser and
> some other modules in the battery pack. One day my app failed with an
> urllib2.HTTPError. So I catch that. But then I get a urllib2.URLError, so
> I catch that too. The next day, it encounters a urllib2.HTTPError, then a
> IOError, a socket.timeout, httplib.InvalidURL,...
>
> How do you program robustly with these modules throwing all those
> different (and sometimes undocumented) exceptions at you?
>
> A catchall seems like a bad idea, since it also catches AttributeErrors
> and other bugs in the program.
>


The relevant lines of urllib2, for example, look as such:

class URLError(IOError):
class HTTPError(URLError, addinfourl):
class GopherError(URLError):

This suggests that catching URLError should have caught your HTTPError,
so you might have the chronology backwards above.

E.g.:

py> class BobError(Exception): pass
....
py> class CarolError(BobError): pass
....
py> try:
.... raise CarolError
.... except BobError:
.... print 'got it'
....
got it


Now,

% cat httplib.py | grep -e '^\s*class'

produces the following at one point in its output:

class HTTPException(Exception):
class NotConnected(HTTPException):
class InvalidURL(HTTPException):
class UnknownProtocol(HTTPException):
class UnknownTransferEncoding(HTTPException):
class UnimplementedFileMode(HTTPException):
class IncompleteRead(HTTPException):
class ImproperConnectionState(HTTPException):
class CannotSendRequest(ImproperConnectionState):
class CannotSendHeader(ImproperConnectionState):
class ResponseNotReady(ImproperConnectionState):
class BadStatusLine(HTTPException):

Which suggests that "try: except HTTPException:" will be specific enough
as a catchall for this module.

The following, then, should catch everything you mentioned except the
socket timeout:

try:
whatever()
except URLError, HTTPException:
alternative()

But it seems to me that working with the internet as you are doing is
fraught with peril anyway.

James
 
Reply With Quote
 
 
 
 
Ben Caradoc-Davies
Guest
Posts: n/a
 
      03-04-2006
James Stroud wrote:
> except URLError, HTTPException:


Aieee! This catches only URLError and binds the name HTTPException to
the detail of that error. You must write

except (URLError, HTTPException):

to catch both.

--
Ben Caradoc-Davies <>
http://wintersun.org/
"Those who deny freedom to others deserve it not for themselves."
- Abraham Lincoln
 
Reply With Quote
 
James Stroud
Guest
Posts: n/a
 
      03-04-2006
Ben Caradoc-Davies wrote:
> James Stroud wrote:
>
>> except URLError, HTTPException:

>
>
> Aieee! This catches only URLError and binds the name HTTPException to
> the detail of that error. You must write
>
> except (URLError, HTTPException):
>
> to catch both.
>


Oops.
 
Reply With Quote
 
Roy Smith
Guest
Posts: n/a
 
      03-04-2006
In article <4408db38$0$21898$>,
Ben Caradoc-Davies <> wrote:

> James Stroud wrote:
> > except URLError, HTTPException:

>
> Aieee! This catches only URLError and binds the name HTTPException to
> the detail of that error. You must write
>
> except (URLError, HTTPException):
>
> to catch both.


This exact issue came up just within the past week or so. I think that
qualifies it as a wart, but I think it's a double wart.

It's certainly a wart that the try statement syntax allows for such
ambiguity. But, I think it's also a wart in how the exceptions were
defined. I like to create a top-level exception class to encompass all the
possible errors in a given module, then subclass that. This way, if you
want to catch anything to goes wrong in a call, you can catch the top-level
exception class without having to enumerate them all.
 
Reply With Quote
 
Peter Hansen
Guest
Posts: n/a
 
      03-04-2006
Rene Pijlman wrote:
> One of the things I dislike about Java is the need to declare exceptions
> as part of an interface or class definition. But perhaps Java got this
> right...
>
> I've writen an application that uses urllib2, urlparse, robotparser and
> some other modules in the battery pack. One day my app failed with an
> urllib2.HTTPError. So I catch that. But then I get a urllib2.URLError, so
> I catch that too. The next day, it encounters a urllib2.HTTPError, then a
> IOError, a socket.timeout, httplib.InvalidURL,...
>
> How do you program robustly with these modules throwing all those
> different (and sometimes undocumented) exceptions at you?


I do it by not micromanaging things. Presumably if you plan to catch an
exception, you have a specific procedure in mind for handling the
problem. Maybe a retry, maybe an alternate way of attempting the same
thing? Look to the code that you are putting in those except:
statements (or that you think you want to put in them) to decide what to
do about this situation. If each type of exception will be handled in a
different manner, then you definitely want to identify each type by
looking at the source or the docs, or doing it empirically.

Most of the time there isn't a whole lot of real "handling" going on in
an exception handler, but merely something like logging and/or reporting
it onscreen in a cleaner fashion than a traceback, then failing anyway.
This is one reason Java does get it wrong: 95% of exceptions don't
need and shouldn't have special handling anyway.

Good code should probably have a very small set of real exception
handling cases, and one or two catchalls at a higher level to avoid
barfing a traceback at the user.

> A catchall seems like a bad idea, since it also catches AttributeErrors
> and other bugs in the program.


Generally speaking this won't be a problem if you have your catchalls at
a fairly high level and have proper unit tests for the lower level code
which is getting called. You are doing unit testing, aren't you?

-Peter

 
Reply With Quote
 
Steven D'Aprano
Guest
Posts: n/a
 
      03-04-2006
On Sat, 04 Mar 2006 00:10:17 +0100, Rene Pijlman wrote:

> I've writen an application that uses urllib2, urlparse, robotparser and
> some other modules in the battery pack. One day my app failed with an
> urllib2.HTTPError. So I catch that. But then I get a urllib2.URLError, so
> I catch that too. The next day, it encounters a urllib2.HTTPError, then a
> IOError, a socket.timeout, httplib.InvalidURL,...
>
> How do you program robustly with these modules throwing all those
> different (and sometimes undocumented) exceptions at you?


How robust do you want to be? Do you want to take a leaf out of Firefox
and Windows XP by generating an error report and transmitting it back to
the program maintainer?

> A catchall seems like a bad idea, since it also catches AttributeErrors
> and other bugs in the program.


ExpectedErrors = (URLError, IOError)
ErrorsThatCantHappen = (LookupError, ArithmeticError, AssertionError)

try:
process_things()
except ExpectedErrors:
recover_from_error_gracefully()
except ErrorsThatCantHappen:
print "Congratulations! You have found a program bug!"
print "For a $327.68 reward, please send the following " \
"traceback to Professor Donald Knuth."
raise
except:
print "An unexpected error occurred."
print "This probably means the Internet is broken."
print "If the bug still occurs after fixing the Internet, " \
"it may be a program bug."
log_error()
sys.exit()



--
Steven.

 
Reply With Quote
 
Paul Rubin
Guest
Posts: n/a
 
      03-04-2006
Steven D'Aprano <> writes:
> try:
> process_things()
> except ExpectedErrors:
> recover_from_error_gracefully()
> except ErrorsThatCantHappen:
> print "Congratulations! You have found a program bug!"
> print "For a $327.68 reward, please send the following " \
> "traceback to Professor Donald Knuth."
> raise
> except:
> print "An unexpected error occurred."
> print "This probably means the Internet is broken."


But this isn't good, it catches asynchronous exceptions like the user
hitting ctrl-C, which you might want to handle elsewhere. What you
want is a way to catch only actual exceptions raised from inside the
try block.
 
Reply With Quote
 
Steven D'Aprano
Guest
Posts: n/a
 
      03-04-2006
On Fri, 03 Mar 2006 21:10:22 -0800, Paul Rubin wrote:

> Steven D'Aprano <> writes:
>> try:
>> process_things()
>> except ExpectedErrors:
>> recover_from_error_gracefully()
>> except ErrorsThatCantHappen:
>> print "Congratulations! You have found a program bug!"
>> print "For a $327.68 reward, please send the following " \
>> "traceback to Professor Donald Knuth."
>> raise
>> except:
>> print "An unexpected error occurred."
>> print "This probably means the Internet is broken."

>
> But this isn't good, it catches asynchronous exceptions like the user
> hitting ctrl-C, which you might want to handle elsewhere. What you
> want is a way to catch only actual exceptions raised from inside the
> try block.



It will only catch the KeyboardInterrupt exception if the user actually
hits ctrl-C during the time the code running inside the try block is
executing. It certainly won't catch random ctrl-Cs happening at other
times.

The way to deal with it is to add another except clause to deal with the
KeyboardInterrupt, or to have recover_from_error_gracefully() deal with
it. The design pattern still works. I don't know if it has a fancy name,
but it is easy to describe:-

catch specific known errors that you can recover from, and recover from
them whatever way you like (including, possibly, re-raising the exception
and letting higher-level code deal with it);

then catch errors that cannot possibly happen unless there is a bug,
and treat them as a bug;

and lastly catch unexpected errors that you don't know how to handle and
die gracefully.

My code wasn't meant as production level code, nor was ExpectedErrors
meant as an exhaustive list. I thought that was too obvious to need
commenting on.

Oh, in case this also wasn't obvious, Donald Knuth won't really pay
$327.68 for bugs in your Python code. He only pays for bugs in his own
code. *wink*



--
Steven.

 
Reply With Quote
 
Paul Rubin
Guest
Posts: n/a
 
      03-04-2006
Steven D'Aprano <> writes:
> The way to deal with it is to add another except clause to deal with the
> KeyboardInterrupt, or to have recover_from_error_gracefully() deal with
> it.


I think adding another except clause for KeyboardInterrupt isn't good
because maybe in Python 2.6 or 2.6 or whatever there will be some
additional exceptions like that and your code will break. For example,
proposals have floated for years of adding ways for threads to raise
exceptions in other threads.

I put up a proposal for adding an AsynchronousException class to
contain all of these types of exceptions, so you can check for that.

> Oh, in case this also wasn't obvious, Donald Knuth won't really pay
> $327.68 for bugs in your Python code. He only pays for bugs in his own
> code. *wink*


The solution to that one is obvious. We have to get Knuth using Python.
Anyone want to write a PEP?
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Re: How include a large array? Edward A. Falk C Programming 1 04-04-2013 08:07 PM
What is the difference between 'except IOError as e:' and 'except Peng Yu Python 1 11-18-2009 02:38 AM
try -> except -> else -> except? David House Python 2 07-06-2009 05:48 PM
who is simpler? try/except/else or try/except Fabio Z Tessitore Python 5 08-13-2007 12:52 AM
converting a nested try/except statement into try/except/else John Salerno Python 20 08-11-2006 02:48 PM



Advertisments