Python style: exceptions vs. sys.exit()

D

Drake

I have a general question of Python style, or perhaps just good
programming practice.

My group is developing a medium-sized library of general-purpose
Python functions, some of which do I/O. Therefore it is possible for
many of the library functions to raise IOError Exceptions. The
question is: should the library function be able to just dump to
sys.exit() with a message about the error (like "couldn't open this
file"), or should the exception propagate to the calling program which
handles the issue?

Thanks in advance for anyone who can either answer my question or
point me to where this question has already been answered.
 
L

Larry Bates

Drake said:
I have a general question of Python style, or perhaps just good
programming practice.

My group is developing a medium-sized library of general-purpose
Python functions, some of which do I/O. Therefore it is possible for
many of the library functions to raise IOError Exceptions. The
question is: should the library function be able to just dump to
sys.exit() with a message about the error (like "couldn't open this
file"), or should the exception propagate to the calling program which
handles the issue?

Thanks in advance for anyone who can either answer my question or
point me to where this question has already been answered.

IMHO libraries should always just let the exception propagate up to the caller.
That allows the caller the option of taking the appropriate action.

-Larry
 
C

Craig Allen

The
question is: should the library function be able to just dump to
sys.exit() with a message about the error (like "couldn't open this
file"), or should the exception propagate to the calling program which
handles the issue?

my view is that the exceptions are there precisely to tell the calling
program about the error and give the programmer a chance to do
something smart about it. A library, properly, doesn't even know the
context in which it is running, and sys.exit() is pretty heavy handed
for a library to call and shows assumptions beyond what a library
should assume about its running environment.

imho
 
T

Terry Reedy

Drake said:
I have a general question of Python style, or perhaps just good
programming practice.

My group is developing a medium-sized library of general-purpose
Python functions, some of which do I/O. Therefore it is possible for
many of the library functions to raise IOError Exceptions. The
question is: should the library function be able to just dump to
sys.exit() with a message about the error (like "couldn't open this
file"),
No

> or should the exception propagate to the calling program which
handles the issue?

Yes -- with an informative error message.

If the caller ignores the exception, the program will exit with a full
stack trace anyway.
 
S

Steven D'Aprano

I have a general question of Python style, or perhaps just good
programming practice.

My group is developing a medium-sized library of general-purpose Python
functions, some of which do I/O. Therefore it is possible for many of
the library functions to raise IOError Exceptions. The question is:
should the library function be able to just dump to sys.exit() with a
message about the error (like "couldn't open this file"), or should the
exception propagate to the calling program which handles the issue?

Thanks in advance for anyone who can either answer my question or point
me to where this question has already been answered.


Presumably somebody has suggested that calling sys.exit() was a good
option. I'm curious to what possible reason they could give for such a
poor choice.

Hint: if a library function can't open a file, the application should be
given the opportunity to open a different file. Or do something
completely different instead. Whatever. That's not up to the library to
decide, not even if the library is in such a broken state that it can't
continue. Why not? Because the application might deal with that by
unloading the library and continuing regardless.
 
A

Asun Friere

Side note:

sys.exit() is just another way to write raise SystemExit. The function
is defined as:

As can be seen if you were ever silly enough to call sys.exit() in
IDLE. ;)
 
B

Bruno Desthuilliers

Drake a écrit :
I have a general question of Python style, or perhaps just good
programming practice.

My group is developing a medium-sized library of general-purpose
Python functions, some of which do I/O. Therefore it is possible for
many of the library functions to raise IOError Exceptions. The
question is: should the library function be able to just dump to
sys.exit() with a message about the error (like "couldn't open this
file"),

Arrghll ! NO, DONT !
or should the exception propagate to the calling program which
handles the issue?

Yes, by all means and for God's sake.
Thanks in advance for anyone who can either answer my question or
point me to where this question has already been answered.

There have been numerous threads about this here.
 
C

Carl Banks

The
question is: should the library function be able to just dump to
sys.exit() with a message about the error (like "couldn't open this
file"),

I'm kind of curious what your library is for. Is it something where
exiting the app be the only appropriate action for an IO error?

Even if it is, I will echo other people's advice: a library should
never call exit, at least not by default. For your imagined use it
might make sense to exit upon any failure, but other people using the
library might not want to do that.

For that matter, a library should never print error or status
messages. Messages should either be sent to the caller somehow, or
handled using the logging facility.


Carl Banks
 
T

Tim Rowe

2008/9/24 Bruno Desthuilliers said:
Drake a écrit :

Arrghll ! NO, DONT !

Can I put in a vote *for* the questioner's library dumping to
sys.exit() on any abnormal condition? It would reduce employment
competition for the rest of us.

Why, yes, I am wearing my BOFH hat. How could you tell?
 
R

Ross Ridge

Steven D'Aprano said:
Presumably somebody has suggested that calling sys.exit() was a good
option. I'm curious to what possible reason they could give for such a
poor choice.

Grant Edwards said:
Same here. It's like an automotive engine controls designer
asking if a failed O2 sensor should turn on the check engine
light or blow up the car.

No, it's more like asking if the failed sensor should turn on a strange
and mysterious light on the dashboard and then blow up the car if the
driver doesn't immediately stop and check the engine. The owners manual
would only vaguely hint at the fact that this could happen.

Ross Ridge
 
B

Bruno Desthuilliers

Ross Ridge a écrit :
(snip)
Well, my point was that exceptions in Python are a bit like a car's
check engine light. Few drivers know what this mysterious light means,
and aren't prepared to do anything about it when it goes on.

You're kidding, aren't you ?
 
R

Ross Ridge

Steven D'Aprano said:
Presumably somebody has suggested that calling sys.exit() was a good
option. I'm curious to what possible reason they could give for such a
poor choice.

Grant Edwards said:
Same here. It's like an automotive engine controls designer
asking if a failed O2 sensor should turn on the check engine
light or blow up the car.

Ross Ridge said:
No, it's more like asking if the failed sensor should turn on
a strange and mysterious light on the dashboard

Grant Edwards said:
You're right. I had forgotten that sys.exit() is actually
raising the system exit exception, and that the application
calling the library could handle that exception.

Well, my point was that exceptions in Python are a bit like a car's
check engine light. Few drivers know what this mysterious light means,
and aren't prepared to do anything about it when it goes on.

Ross Ridge
 
R

Ross Ridge

Grant Edwards said:
Same here. It's like an automotive engine controls designer
asking if a failed O2 sensor should turn on the check engine
light or blow up the car.

Ross Ridge said:
No, it's more like asking if the failed sensor should turn on
a strange and mysterious light on the dashboard

Grant Edwards said:
You're right. I had forgotten that sys.exit() is actually
raising the system exit exception, and that the application
calling the library could handle that exception.

Ross Ridge a écrit :
Well, my point was that exceptions in Python are a bit like a car's
check engine light. Few drivers know what this mysterious light means,
and aren't prepared to do anything about it when it goes on.

Bruno Desthuilliers said:
You're kidding, aren't you ?

Of course not. Plenty of people were quick to say that the exception
should be passed through to the caller. No one said this behaviour
should be documented. There may be little practical difference bewteen
calling sys.exit() after printing an error and progating an exception
if no one using the library knows that it could generate that exception
in those circumstances.

Ross Ridge
 
S

Steven D'Aprano

You're right. I had forgotten that sys.exit() is actually raising the
system exit exception, and that the application calling the library
could handle that exception.

Could but shouldn't.

The exception hierarchy was re-designed in Python 2.5 specifically so
that SystemExit and KeyboardInterrupt no longer inherit from Exception.
That means this will do the right thing:

try:
process(record)
if changed:
update(record)
except Exception:
# don't write the record if any error occurs
pass


Neither SystemExit nor KeyboardInterrupt are errors, and they should not
be treated as errors. I quote from the Fine Manual:

[SystemExit] inherits from BaseException instead of StandardError or
Exception so that it is not accidentally caught by code that catches
Exception. This allows the exception to properly propagate up and cause
the interpreter to exit.

http://docs.python.org/lib/module-exceptions.html

SystemExit is not an error. KeyboardInterrupt is not an error. Libraries
should not use SystemExit to signal an error any more than they should
use MemoryError to signal a missing attribute.

Whether or not an application exits is up to the application to decide,
not the library it wraps. Libraries should report errors by raising an
Exception (note the capital E), and the application should decide whether
or not it is recoverable, and if not, exit (perhaps by simply not
catching the exception).
 
S

Steven D'Aprano

Plenty of people were quick to say that the exception should be passed
through to the caller. No one said this behaviour should be documented.
There may be little practical difference bewteen calling sys.exit()
after printing an error and progating an exception if no one using the
library knows that it could generate that exception in those
circumstances.

That's true, I didn't explicitly say that the library should be
documented. Nor did I say that it shouldn't be riddled with bugs. There's
little practical difference between a buggy library and one that raises
unexpected (i.e. undocumented) exceptions either.
 
B

Bruno Desthuilliers

Steven D'Aprano a écrit :
That's true, I didn't explicitly say that the library should be
documented. Nor did I say that it shouldn't be riddled with bugs. There's
little practical difference between a buggy library and one that raises
unexpected (i.e. undocumented) exceptions either.

Also note that there are quite a couples cases where the library authors
themselves cannot predict which exception types may be raised - as soon
as the library functions expect callback functions, file-like or
dict-like or whatever-like objects etc, it's the caller's responsability
to handle the exceptions that may be raised by what *he* passes to the
library...
 
R

Ross Ridge

Ross said:
Plenty of people were quick to say that the exception should be passed
through to the caller. No one said this behaviour should be documented.
There may be little practical difference bewteen calling sys.exit()
after printing an error and progating an exception if no one using the
library knows that it could generate that exception in those
circumstances.

Steven D'Aprano said:
That's true, I didn't explicitly say that the library should be
documented. Nor did I say that it shouldn't be riddled with bugs. There's
little practical difference between a buggy library and one that raises
unexpected (i.e. undocumented) exceptions either.

The problem is that few Python libraries properly document where and
when they might generate exceptions. They'll document the fact that
they have an "error" exception, but only vaguely say which functions or
methods could generate it and why. You need either use trial and error
to find out, or look at the source.

Ross Ridge
 
R

Ross Ridge

Bruno Desthuilliers said:
Also note that there are quite a couples cases where the library authors
themselves cannot predict which exception types may be raised - as soon
as the library functions expect callback functions, file-like or
dict-like or whatever-like objects etc, it's the caller's responsability
to handle the exceptions that may be raised by what *he* passes to the
library...

Ug... that's another documentation pet-peeve of mine. Libraries that
say they take file-like (or whatever-like) object, but don't say exactly
how file-like it needs.

Ross Ridge
 
B

Bruno Desthuilliers

Ross Ridge a écrit :
Ug... that's another documentation pet-peeve of mine. Libraries that
say they take file-like (or whatever-like) object, but don't say exactly
how file-like it needs.

Seems not to be such a problem in practice...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top