Identifying exceptions that can be raised

D

dkcpub

I'm very new to Python, but I couldn't find anything in the docs or faq
about this. And I fished around in the IDLE menus but didn't see anything.

Is there a tool that can determine all the exceptions that can be raised
in a Python function, or in any of the functions it calls, etc.?

/Dan
 
B

Brian van den Broek

dkcpub said unto the world upon 2004-11-18 22:38:
I'm very new to Python, but I couldn't find anything in the docs or faq
about this. And I fished around in the IDLE menus but didn't see anything.

Is there a tool that can determine all the exceptions that can be raised
in a Python function, or in any of the functions it calls, etc.?

/Dan

Hi Dan,

Do you mean all the exceptions that exist? If so, while I don't know
Python well enough to vouch for its completeness, check out
<http://www.python.org/doc/2.3.4/lib/module-exceptions.html>.

If you mean you want a list of exceptions that a given function could
raise, well, never mind :)

Best,

Brian vdB
 
D

dkcpub

Brian said:
If you mean you want a list of exceptions that a given function could
raise, well, never mind :)

Yeah, that is what I mean. I write foo(), which calls a half-dozen
library functions. What exceptions is a caller of foo() going to have
to handle? It there an automated way of discovering that?

/Dan
 
P

Peter Otten

dkcpub said:
Yeah, that is what I mean. I write foo(), which calls a half-dozen
library functions. What exceptions is a caller of foo() going to have
to handle? It there an automated way of discovering that?

/Dan

None that I know of. You just have to feed the function the typical data and
any corner cases that you can think of and handle all failures that appear
in the process. The unittest module can help you automate this.
Hoping to ever get a comprehensive set of exceptions a function can raise is
a vain effort in Python. A little example may illustrate this:
.... return a + b
....Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 2, in add
TypeError: unsupported operand type(s) for +: 'int' and 'str'

The above calls should cover the typical usage of our trivial function. Does
it make sense then, to document/report that add() may raise a TypeError? I
think that would be misleading:
.... def __add__(self, other):
.... return self/other
....Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 2, in add
File "<stdin>", line 3, in __add__
ZeroDivisionError: integer division or modulo by zero

This may seem contrived, but for any non-trivial function the number of
exceptions is open-ended, and trying to achieve reliability by handling a
fixed set of exceptions is essentially asking for type declarations for a
small portion of a function's signature - and a portion where its
usefulness is debated even for statically typed languages (I think Java has
it, but C sharp doesn't).
Put your time to a better use and write a good test suite.

Peter
 
P

Peter Hansen

dkcpub said:
Yeah, that is what I mean. I write foo(), which calls a half-dozen
library functions. What exceptions is a caller of foo() going to have
to handle? It there an automated way of discovering that?

Nope. That's that nasty ol' Java thinkin'. ;-)

Basically, given the dynamicism that is Python's hallmark,
you can't guarantee that any given function won't raise
an arbitrary exception. I could write a function that
could raise random exceptions, including ones it wasn't
even previously aware of (by crawling the tree of classes
starting at sys.modules and discovering new ones, perhaps).

The usual approach is to have a caller catch exceptions
*which it is capable of dealing with appropriately*, and
ignore others. In some cases it's necessary to have a
"generic" exception handler, such as at the top level of
a thread, to catch and log all exceptions, but that's
relatively rare.

In contrast to Java code, you aren't forced to catch
exceptions in a manner similar to the old-style approach
to handling error values returned by functions (that is,
by ignoring them). Instead you write useful code that
actually explicitly catches only things it understands
and can deal with. A breath of fresh air, really...

All that said, you do sometimes find yourself pondering
what exceptions a given function might raise and which
you *do* want to handle properly. It's not always clear,
and unfortunately short of examining the source or hoping
that the author wrote decent documentation, you're out
of luck.

-Peter
 
A

Andrew Dalke

Peter said:
Nope. That's that nasty ol' Java thinkin'. ;-)

Basically, given the dynamicism that is Python's hallmark,
you can't guarantee that any given function won't raise
an arbitrary exception.

One of my puzzlements about Java 10 years ago or so was
why it decided to go the "must declare every exception" route.

Consider this simple and naive numeric integrator

def integrate(f, start, end, n):
delta = (end-start)/float(n)
x = start + delta / 2
sum = 0.0
for i in range(n+1):
sum = sum + f(x)
x += delta
return sum / (n+1)

That function cannot define all the exceptions that can be
raised because f itself can raise an arbitrary exception. Eg,

def f1(x):
return 1/max(5-x, 0)) # Can raise a divide-by-zero error

integrate(f1, 0, 10, 5)

Java handles that case by saying you don't need to declare
system exceptions. Then consider

def f2(x):
fname = os.path.join("/cache/directory", str(x))
if os.path.exists(fname):
return float(open(fname, "r").read())
y = _f2(x)
outfile = open(fname, "w")
try:
outfile.write(str(y))
finally:
outfile.close()
return y

integrate(f2, 0, 10, 10)

If the file is not readable, or the directory not readable,
then this might raise an IOError.

How does the 'integrate' function declare that it can raise
any of the errors that the integrator function 'f' might raise?

Again, IOError might be considered a system-level error
such that it doesn't need declaring. Then change it to
polling some URL ("http://cache.server/" + str(x)) when the
network is down, or getting it from some SQL database when
the password is incorrect, or anything else that cannot be
determined until actually calling f().

It looks like the only thing to do is convert all such
unhandled exceptions and wrap them in a catch-all generic
exception. I think I've seen people do that. But if so,
what's the point of having typed exceptions?

Curiously-y'rs,

Andrew
(e-mail address removed)
 
D

Dan Sommers

One of my puzzlements about Java 10 years ago or so was
why it decided to go the "must declare every exception" route.
Consider this simple and naive numeric integrator
def integrate(f, start, end, n):
delta = (end-start)/float(n)
x = start + delta / 2
sum = 0.0
for i in range(n+1):
sum = sum + f(x)
x += delta
return sum / (n+1)
That function cannot define all the exceptions that can be
raised because f itself can raise an arbitrary exception. Eg,

[ cool example of f reading data from a file-system cache snipped ]
Again, IOError might be considered a system-level error
such that it doesn't need declaring. Then change it to
polling some URL ("http://cache.server/" + str(x)) when the
network is down, or getting it from some SQL database when
the password is incorrect, or anything else that cannot be
determined until actually calling f().

And what if f has its own run-time plug-in mechanism?
It looks like the only thing to do is convert all such
unhandled exceptions and wrap them in a catch-all generic
exception. I think I've seen people do that. But if so,
what's the point of having typed exceptions?

IMO (and maybe I'm just restating the obvious; it wouldn't be the first
time <g>), "the list of exceptions f is allowed to raise" shouldn't be
part of the interface of integrate, but rather "the list of exceptions
integrate will handle gracefully" should be. Resumably, the caller of
f, or some entity far enough up the call chain, anyway, knows something
about f that integrate does not. In some cases, that entity could be a
human sitting at an interactive console, and that human would like to
know if/when f raises exceptions not handled by integrate.

As to the original question, I agree: there's no way that integrate can
know every exception f might raise, and there's no reason it should,
either. f *must be content* with handling what it promises to handle
and letting everything else pass through it unchanged. Logically, f is
part of the *caller* of integrate rather than being among the functions
integrate *calls*.

Regards,
Dan
 
D

Dan

Peter said:
> Nope. That's that nasty ol' Java thinkin'. ;-)

Never used Java. Mostly just C. All in all, I like these exceptions
better than C's error codes, because I mostly just write trivial little
programs that would just print a message and exit if I detected an
error--and exceptions do that automatically with no active checking on
my part.

But the thought occured to me that if I _did_ want to handle exceptions,
I would have no idea what the possibilities even were.
> All that said, you do sometimes find yourself pondering
> what exceptions a given function might raise and which
> you *do* want to handle properly.

Exactly.

/Dan
 
P

Peter Hansen

Dan said:
the thought occured to me that if I _did_ want to handle exceptions,
I would have no idea what the possibilities even were.

Here's another area where good unit testing can help (apologies
to those with an irrational negative reaction to test-driven
development concepts). By writing tests which exercise the routines
you are calling in various ways, you will often find which
exceptions are of interest but not perhaps documented clearly.

For example, the other day I discovered that if you attempt
to read or write from/to a closed file, you don't get what
you might expect (an IOError or an OSError), but in fact
you get a ValueError. Writing unit tests was what led to
this discovery. (Perhaps it's actually documented... I don't
know and didn't bother looking.)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
ValueError: I/O operation on closed file


-Peter
 
R

Roy Smith

Peter Hansen said:
For example, the other day I discovered that if you attempt
to read or write from/to a closed file, you don't get what
you might expect (an IOError or an OSError), but in fact
you get a ValueError. Writing unit tests was what led to
this discovery. (Perhaps it's actually documented... I don't
know and didn't bother looking.)

What you are describing is essentially black-box testing. It may be a
valid procedure for QA purposes, but it's hardly a reasonable way to
write a program. Actually, it's worse than black-box testing.
Black-box testing says you should design your tests based only on the
documentation (functional spec, whatever) without looking at the source
code. You're saying you should write the code without even looking at
the documentation.

I'm a big fan of test-driven development, but not to the extent that I
feel I can ignore reading the documentation to see how something is
supposed to work. It took me about 15 seconds to find the page in the
library reference for file objects, where I immediately found:

---------
close()
Close the file. A closed file cannot be read or written any more. Any
operation which requires that the file be open will raise a ValueError
after the file has been closed. Calling close() more than once is
allowed.
---------

Computer Science is not an experimental science. In the old days of
biology, if I wanted to know what a certain gene did, I made my best
guess and designed an experiment to prove or disprove my theory. Repeat
as long as the funding holds out. These days, I pop the DNA into a
sequencing machine and read the source code. We may not fully
understand the language the program is written in, but it sure beats
poking at the thing with a stick and seeing what happens.
 
P

Peter Hansen

Roy said:
What you are describing is essentially black-box testing. It may be a
valid procedure for QA purposes, but it's hardly a reasonable way to
write a program.

You provide nothing to back up this claim.
> Actually, it's worse than black-box testing.

Nor this, of course.
Black-box testing says you should design your tests based only on the
documentation (functional spec, whatever) without looking at the source
code. You're saying you should write the code without even looking at
the documentation.

Did I say that somewhere? I really don't think you can
find anything in what I said that equates to me recommending
that one should write code this way in the general case.
---------
close()
Close the file. A closed file cannot be read or written any more. Any
operation which requires that the file be open will raise a ValueError
after the file has been closed. Calling close() more than once is
allowed.
---------

In other words, the documentation in this case happens to align
with the actual behaviour of file objects.

Now I ask you, how often does documentation either not mention
the fact at all (which was the topic of this thread until now),
or -- perhaps less common with standard library code, but widespread
with other code -- mention things that are inaccurate and wrong?

And how often does the code actually behave the way the code
behaves?

In other words, which should one trust more, the documentation
or the actual observed behaviour?
Computer Science is not an experimental science.

Again, you've said nothing that in any way justifies this statement.

I'm not saying CS _is_ an experimental science, but I think
I would say that your implied statement that one should *never*
do this is fundamentally flawed.

Ultimately, however, this is a silly argument, because neither
you nor I write code solely in the manner I described, nor
in the manner you appear to be recommending (i.e. going exclusively
based on the documentation), so I'm not even sure why you
wrote...

As a final note, I'll point out that I was writing code for
a mock file system, and if you think doing that solely based
on the documentation is a good idea, I heartily recommend you
give it a go and see how useful your results actually are...

-Peter
 
R

Roy Smith

Peter Hansen said:
Did I say that somewhere?

You said, "Perhaps it's actually documented... I don't know and didn't
bother looking." If I misinterpreted your statement, I apologize.
In other words, the documentation in this case happens to align
with the actual behaviour of file objects.

Now I ask you, how often does documentation either not mention
the fact at all (which was the topic of this thread until now),
or -- perhaps less common with standard library code, but widespread
with other code -- mention things that are inaccurate and wrong?

Of course there is bad documentation in the world. If the documented
and actual behavior of the code differ, there's clearly a bug somewhere.
It could be that the documentation is wrong, or it could be that the
code is wrong. Both happen. Both kinds of bugs should be fixed when
they are discovered.
In other words, which should one trust more, the documentation
or the actual observed behaviour?

Well, that's an interesting question, and I'm not sure there's a simple
answer to it. Certainly, if my testing determines that read() throws
ValueError under certain situations which are not documented, it would
be foolish for me to pretend that it didn't happen because the
documentation doesn't say so. But on the other hand, if I discovered
that math.pi had the value 3, I would be equally foolish to write code
which depended on that behavior.
Ultimately, however, this is a silly argument, because neither
you nor I write code solely in the manner I described, nor
in the manner you appear to be recommending (i.e. going exclusively
based on the documentation), so I'm not even sure why you
wrote...

I never recommended going exclusively from the docs. I started out by
saying:
I'm a big fan of test-driven development, but not to the extent that I
feel I can ignore reading the documentation to see how something is
supposed to work.

Anyway, it would look like both of us have unintentionally
misinterpreted what each other has said. I think in the end we both
agree that reading the docs is important, and testing is important too.
Both give us information which is unavailable from the other.
 
C

Cameron Laird

.
.
.
But the thought occured to me that if I _did_ want to handle exceptions,
I would have no idea what the possibilities even were.
.
.
.
I'm sympathetic. It bothers me no end when working
with C and Java that documenters are as relaxed as
I've found them to be in failing to document error
conditions.

Peter and the others correctly express the Python
approach, though.
 
J

Jim Hefferon

Peter Hansen said:
The usual approach is to have a caller catch exceptions
*which it is capable of dealing with appropriately*, and
ignore others. In some cases it's necessary to have a
"generic" exception handler, such as at the top level of
a thread, to catch and log all exceptions, but that's
relatively rare.

I wonder if perhaps you don't write different kinds of programs than I
do.

For instance, I have a cgi program. One routine will get an id from a
httpd parameter, use it to reach into a database and fetch some xml,
and then pull information out of the xml for display. That I can
tell, there are about 100 exceptions that could be raised (the xml
parser is vague about what it could raise, and although the dB is a
bit better, it is not always clear what an exception means or under
what condidtions it could be raised). I'm left with the feeling that
for any amount of testing that I do (and I've found cgi hard to
automatically test), there is always another exception lurking out
there. I have a great deal of difficulty achieving the feeling that I
am consistently returning a sensible error screen to the user.

I've tried Java, and found it a slog, but for some programs knowing
which exceptions could be raised would be a comfort.
All that said, you do sometimes find yourself pondering
what exceptions a given function might raise and which
you *do* want to handle properly. It's not always clear,
and unfortunately short of examining the source or hoping
that the author wrote decent documentation, you're out
of luck.

I second that.

Jim
 
D

Dan

Cameron said:
I'm sympathetic. It bothers me no end when working
with C and Java that documenters are as relaxed as
I've found them to be in failing to document error
conditions.

Then there was the DEC C library, in which free() returned an error code
on failure--and was so documented, but which was prototyped to return
void as required by the standard.

But I'll stop looking for the tool that finds all the exceptions that a
function can raise. :)

/Dan
 
P

Peter Hansen

Jim said:
I wonder if perhaps you don't write different kinds of programs than I
do.

I certainly do. I don't, for example, ever do CGI...
For instance, I have a cgi program. One routine will get an id from a
httpd parameter, use it to reach into a database and fetch some xml,
and then pull information out of the xml for display. That I can
tell, there are about 100 exceptions that could be raised ...

....but were I faced with this situation, I would follow my
above advice about "in some cases it's necessary...". This
is exactly such a situation. I would always wrap such a
program** at the top level with a generic exception handler
and a call to traceback.format_exception() (or whatever it's
called), turning any errors into visible results, or at
the very least logging them somewhere for analysis.

** I don't think of CGI calls as independent _programs_, mind
you, any more than I think of individual threads as programs,
but I'm not sure this is affecting my opinion here vis-a-vis
exception handling.

-Peter
 
S

Steve Holden

Peter said:
I certainly do. I don't, for example, ever do CGI...



....but were I faced with this situation, I would follow my
above advice about "in some cases it's necessary...". This
is exactly such a situation. I would always wrap such a
program** at the top level with a generic exception handler
and a call to traceback.format_exception() (or whatever it's
called), turning any errors into visible results, or at
the very least logging them somewhere for analysis.
Such as is provided by the line

import cgitb; cgitb.enable()

for example.
** I don't think of CGI calls as independent _programs_, mind
you, any more than I think of individual threads as programs,
but I'm not sure this is affecting my opinion here vis-a-vis
exception handling.

-Peter

I think some people just deal with uncertainty better than others. Java
is indeed a slog, and being forced to write exception handlers for
errors I never expect to occur and was quite happy to see my program
fail under was one of the least attractive things about it.

no-more-java-for-me-ly y'rs - steve
 
R

Roy Smith

Steve Holden said:
I think some people just deal with uncertainty better than others. Java
is indeed a slog, and being forced to write exception handlers for
errors I never expect to occur and was quite happy to see my program
fail under was one of the least attractive things about it.

Java doesn't actually force you to handle the errors. You can always
just declare your method to throw those exceptions you don't handle.
That's a pain in the butt too, it's just a slightly smaller pain than
catching them. I agree with you that exception handling is Java is one
of the (many) low points of the language.
 
U

Uche Ogbuji

Peter Hansen said:
Again, you've said nothing that in any way justifies this statement.

I'm not saying CS _is_ an experimental science, but I think
I would say that your implied statement that one should *never*
do this is fundamentally flawed.

Ultimately, however, this is a silly argument, because neither
you nor I write code solely in the manner I described, nor
in the manner you appear to be recommending (i.e. going exclusively
based on the documentation), so I'm not even sure why you
wrote...

Personally, I shared Mr. Smith's reaction to your posting. I've seen
a lot of claims of the magical fairy dust of test-first programming
(an idea whose basic soundness I agree with), but the idea that such
prophetic pre-testing is a sounder way of learning an API properly
than reading the documentation tops them all.

I believe now your claims that you didn't mean anything so radical,
but you can hardly blame Mr. Smith from reading what you wrote,
originally and coming to the natural conclusion from comprehension of
your prose. The reason why he wrote is to make it clear to anyone
else who respects you as an intelligent commentator on Python
programming (this was a thread started by a noob question, after all)
that in reality that reading the documentation should generally be the
first step in comprehending code. I think he achieved this aim by
pointing out that the very example you trumpeted proved the overriding
value of documentation.


--
Uche Ogbuji Fourthought, Inc.
http://uche.ogbuji.net http://4Suite.org http://fourthought.com
A hands-on introduction to ISO Schematron -
http://www-106.ibm.com/developerworks/edu/x-dw-xschematron-i.html
Schematron abstract patterns -
http://www.ibm.com/developerworks/xml/library/x-stron.html
Wrestling HTML (using Python) -
http://www.xml.com/pub/a/2004/09/08/pyxml.html
XML's growing pains - http://www.adtmag.com/article.asp?id=10196
XMLOpen and more XML Hacks -
http://www.ibm.com/developerworks/xml/library/x-think27.html
A survey of XML standards -
http://www-106.ibm.com/developerworks/xml/library/x-stand4/
 
N

Neil Benn

Hello,

I too find the lack of finding exceptions that can be raised a
problem (I'm a nasty old Java programmer as well!). Java checked
exceptions get a beating every so often but it's not as bad as always
made out, see comments below:
One of my puzzlements about Java 10 years ago or so was
why it decided to go the "must declare every exception" route.

Well sort of there are two basic types of exceptions 'normal' exception
and runtime exceptions - runtime exceptions do not need a try/catch
around them. These are your general case.
Consider this simple and naive numeric integrator

def integrate(f, start, end, n):
delta = (end-start)/float(n)
x = start + delta / 2
sum = 0.0
for i in range(n+1):
sum = sum + f(x)
x += delta
return sum / (n+1)

That function cannot define all the exceptions that can be
raised because f itself can raise an arbitrary exception. Eg,

def f1(x):
return 1/max(5-x, 0)) # Can raise a divide-by-zero error

integrate(f1, 0, 10, 5)

Java handles that case by saying you don't need to declare
system exceptions.

Not exactly true, you do have to check some systems exceptions - all
those that are not runtime. Divide by zero, type exceptions, null
pointer exceptions are all examples of run-time. For the others see later.
Then consider

def f2(x):
fname = os.path.join("/cache/directory", str(x))
if os.path.exists(fname):
return float(open(fname, "r").read())
y = _f2(x)
outfile = open(fname, "w")
try:
outfile.write(str(y))
finally:
outfile.close()
return y

integrate(f2, 0, 10, 10)

If the file is not readable, or the directory not readable,
then this might raise an IOError.

How does the 'integrate' function declare that it can raise
any of the errors that the integrator function 'f' might raise?

Again, IOError might be considered a system-level error
such that it doesn't need declaring.

IOError is a checked exception - if you want to do IO then you need to
wrap it in a try catch or throw it to your caller. This is because IO
is inherently fault prone and you should be thinking about exceptions
and unusual cases when doing IO. However in Java, this sometimes falls
over for example - ByteOutputStream, writes to a byte array - because it
inherits OutStream, the read and write functions declare IOException
which means you do sometimes have to write a meaningless try catch for
this (its memory copying, won't fail due to IO).
Then change it to
polling some URL ("http://cache.server/" + str(x)) when the
network is down, or getting it from some SQL database when
the password is incorrect, or anything else that cannot be
determined until actually calling f().

The first case uses OutputStream, checked exception - the second case
uses JDBC which also has checked exceptions.
It looks like the only thing to do is convert all such
unhandled exceptions and wrap them in a catch-all generic
exception. I think I've seen people do that. But if so,
what's the point of having typed exceptions?

Any java developer who does that should get pulled up at code review
time, the only time I could ever recommend that is in a top level call
when you want to catch all exceptions, log them and then apologise to
the user profusely that your program screwed up!!
Curiously-y'rs,

Andrew
(e-mail address removed)
On a general point, the python/adults thingy that is often said - if
followed correctly - removes the need for checked exceptions - if
everyone coded correctly then you wouldn't need it. However, I do find
it frustrating that in a lot of python docs - the exceptions that can be
thrown are not documented. I know there are obvious null pointers, key
errors and type exceptions but for example - what exceptions are thrown
if I call socket.recv(1024) when there are no characters for me to
receive?? The only way to determine this is to try it. I miss a level
of comfort that means that there may be a case which I haven't thought
of which could cause my code to go kablooeee. Eiffel's programming by
contract goes one step further...

Cheers,

Neil
 

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
474,212
Messages
2,571,102
Members
47,697
Latest member
looped_monk

Latest Threads

Top