How do I know all thrown exceptions of a function?

D-Man dsh8290 at rit.edu
Wed Jan 24 18:28:27 EST 2001


On Wed, Jan 24, 2001 at 03:04:58PM +0000, Remco Gerlich wrote:
| Paul Foley mailed me his comments, I'm assuming he meant to post to the
| group. I'll paste in some of them, since he disagreed interestingly :-)
| (his quotes marked with |)
| 
| I've left D-Man's comments in although I comment mainly on Paul's, but
| whatever :)
| 
| D-Man <dsh8290 at rit.edu> wrote in comp.lang.python:
| > On Tue, Jan 23, 2001 at 06:48:45PM +0000, Remco Gerlich wrote:
|  > | - All the exceptions your code explicitly throws should inherit
| > |   some base exception defined in your module, so that that can
| > |   be tested for.
| > 
| > I agree with this.  It makes handling all exceptions of a certain
| > classification easy.
| 
| (Paul)
| | No.  If your code gets, say, a bad value, it should raise ValueError,
| | not some new version of ValueError defined only in that module.
| 
| Ah, of course. If there's an obvious builtin exception for exactly this
| problem, use that. That should cover many cases.

Yes, if it is obvious that a builtin exception is more
suitable/natural use it.  Though maybe it is good to do something
like:

class MyValueError( ValueError , MyModuleExceptionRoot ) :
	pass

It is-a ValueError and it is-a exception from my module.  This allows
both types of except clauses to be used.  IMO you should do whatever
is clearest and provides the best handling in the given situation.
If, for example, you are creating your own MagicSequence class, then
it makes sense to simply use the builtin sequence exceptions.

| 
| My point is though, say you have some markup language parser that is looking
| for an end tag. Your string.index() call fails with a ValueError (end marker
| not found). Now it would be best to catch that and raise some sort of
| mymarkupparser.MissingEndTag exception, not to simply pass on the unhelpful
| ValueError that might change once you switch to regular expressions.
| 
| (Paul)
| | It's often useful to define a bunch of new exceptions for your module,
| | but probably equally often, you want the built-in exceptions [or,
| | occasionally, exceptions defined in third-party modules you imported.
| | E.g., a module that defines some new kind of network socket might want
| | to raise socket.error...though this is a bad example; socket.error is
| | rather under-specific...]
| 
| I don't like using exceptions from completely different modules you happen
| to use. That is where it becomes hard to find out for the user what
| exceptions your code might raise, and now they need to import that module to
| use its exceptions, and read its documentation, when the whole points is
| that they reach it through your module so they don't have to know about it.
| 

These ought to be "renamed" to an exception in your module.
This provides for a more consistent interface for your module and
eliminates the client's need for knowledge of your dependent modules.

| > | - Avoid throwing exceptions that have to do with your implementation
| > |   to the outside world. If your module function gets an argument that
| > |   is out of range, resulting in an IndexError, don't just pass that on
| > |   to the caller but catch it and raise a custom exception yourself,
| > |   that inherits from your module's standard exception. Hide your
| > |   implementation.
| > 
| > I agree with this as well.  I did this when modifying a library to
| > actually throw exceptions :-).  It had try{ ... } catch( Exception e ) {
| > return false ; } in it.  (Java lib someone else copied from a C lib).
| > It made the errors much more useful.
|  
| (Paul)
| | Au contraire; pass on that IndexError if it makes sense to do so
| | (i.e., if you can't handle it inside your code, and its not some
| | implementation detail that could go away with a different
| | implementation (unlikely, for IndexError)). 
| 
| But if it's caused by a bad input value, it should raise ValueError - so you
| catch it and raise the other exception. Otherwise you have to remember for
| each library function what the exception is that it throws when you give it
| wrong input (and there might be several possibilities).
| 
| (Paul)
| | Catching it only to raise
| | some custom exception is conceptually horrible, as well as being
| | generally impossible (think higher-level functions, or callbacks.  You
| | don't know what the user wants to do when exceptions happen in his own
| | code that's being called by yours, and if you alter his exceptions,
| | you'll break his handlers!  Utterly evil!)
| 

In the case of the library I tweaked to have better error reporting I
caught the thrown exceptions so that I could raise my own.  The lib's
purpose was to receive a string input and validate it.  There are
several ways it could be invalid, and I created simple exception types
that encapsulated these ideas.  When the lib threw all sorts of
errors (after my modifications), I translated it into an appropriate
exception from my module.  (For example, sometimes I would get an
IOException,  this isn't what I wanted to tell the client so I caught
it and threw InvalidData exception instead)  All the exceptions in my
module inhertied from a single exception type so that the client could
be general or specific depending on the needs.  Although, more
specifically, except in some cases, I had the lib throw my exception
type in the first place.

| Ok, functions you know nothing about that are passed in as an argument,
| those are an exception. If you know nothing about what it does, you
| shouldn't change it either...
| 
| (Paul)
| | Perhaps the best advice is "know what you're doing, and write code
| | that behaves sensibly", rather than trying to enforce some overly
| | strict rules.
| 
| Of course. But discussing what good rules of thumb would be makes it a
| lot easier to behave sensibly later :-).

Good points were made from both sides.  It is good to have some rules
of thumb to start with, but don't take it beyond realistic bounds.

In all cases, do what is sensible (as Paul said).

| 
| -- 
| Remco Gerlich
| -- 

-D





More information about the Python-list mailing list