How to set up your module exceptions to be useful

June 4, 2010

Suppose that you are writing a Python module that has exceptions as part of its interface, and you want them to actually be useful to people. From the perspective of a sometimes grumpy user of module exceptions, here is my opinions on what you should do:

  • all exceptions that you expect people to actually catch should descend from a common ancestor class, so that people can just do 'except YourException, e:' and be done with it.

    If you have an exception you raise for internal errors and other impossible situations, do not make it part of this hierarchy; otherwise people will catch it when you don't want them to.

  • people will mostly use your error exceptions by turning them into strings (and printing them out). Make sure that this gives useful information.

  • you need to document what fields your exceptions have. If you do not, people will just str() your exceptions and ignore any information that this misses.
  • if you have multiple exception classes, try to have as many common fields in them as possible. As a pragmatic thing, expect people to mostly ignore unique fields unless they have important information that people need to act on.

  • do not ever reuse or subclass standard exceptions, especially IOError and OSError.

    (If you are ever tempted to break this rule, make absolutely sure that your versions of these exceptions are exactly identical to the real ones.)

  • if you call code from other modules, you should capture and wrap up their exceptions, turning them into exceptions of your own. This is much easier for your callers to deal with, since they don't have to know what other modules you use (or care if you change what modules you use).

In general, I would say that you should avoid the temptation to get too complex in error handling. Put yourself in the shoes of the typical person using your module; are you going to care about anything beyond the fact that some sort of an error happened? Generally not. Then you just need a single exception class with a useful string error message, and you're done.

(I admit that I don't always stick to this simple model for my own code; I sometimes have an irrepressible urge to subclass my overall module error class so that I can distinguish this sort of error from that sort of error and so on. Then I never use any of these features.)

Comments on this page:

From at 2010-06-05 09:56:43:

I'm curious as to way you think that I should not subclass Exception when implementing my module's base exception?

Also, generally try to have as few exceptions as possible for my modules. But when it comes to unit testing I often get the urge to subclass (and sometimes do so) to signal different types of errors that I want to test for. I haven't made up my mind on how I feel about this yet. :-)

By cks at 2010-06-05 14:33:26:

Oops; I was unclear. Subclassing Exception itself is fine (and I should have put in something about doing it, in fact). When I wrote 'standard exceptions', I was thinking about all of the concrete standard exceptions that Python uses. Basically, if existing code raises it and people catch it, you shouldn't try to use it yourself.

From at 2010-06-08 11:25:21:

Great post! Poor exception throwing is a real pet peeve of mine. I remember running into a lack of 'rethrow with your own exception issue' that made an app I was working on that called xml-rpc functions particularly hard to stream line error catching as in addition to it's own there was a whole host of socket exceptions that had to be caught (which weren't documented).

Looking over that code now, I had to know to catch: IOError, xmlrpclib.Fault, xmlrpclib.ResponseError, socket.gaierror, socket.error, xmlrpclib.ProtocolError, and xmlrpclib.Error. And then I had to raise a new exception to give meaningful output as their conversions to strings were not meaningful to users.


Written on 04 June 2010.
« How disk write caches can corrupt filesystem metadata
The quiet death of postmaster@anywhere »

Page tools: View Source, View Normal, Add Comment.
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Fri Jun 4 23:19:10 2010
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.