Python modules should not reinvent OSError

August 20, 2009

In light of yesterday's entry, here is one of my new rules for Python modules, especially extension modules written in C:

If you're going to raise an exception because a system call failed, don't make up a new exception for it. Raise either IOError or OSError themselves.

Every deviation from this causes annoyances for Python programmers. This is especially visible in the situation with signals and EINTR , where I really do not want to be rewriting the same code over and over again with different exception classes (or worse, writing different code because you decided to hide errno somewhere new in your exception).

A corollary to this is that if for some reason you absolutely have to raise a new exception, you should make it duck typing compatible with OSError (see here for what that requires). But really, you don't have to, especially because Python code can raise real OSError exceptions.

(Please do not get creative with the error message for OSError instances that you create yourself in Python code. If it is not exactly the strerror() of the errno, you are doing it wrong.)

Extension modules written in C have no excuse, because the Python C API makes it very easy to do the right thing (and reusing OSError saves you from having to create your own C level exception object). Alas, the standard Python exception modules are just overflowing with bad examples, where people make up a new exception instead of reusing OSError or IOError.

(This is sort of the reverse corollary of not using IOError for things that aren't system call errors.)

Sidebar: to wrap or not to wrap

I'm aware that this looks inconsistent with my views on not wrapping exceptions. The difference to me is if you are essentially wrapping a system call and directly exposing errno, you should be using the standard way of doing that, which is an EnvironmentError exception (or should be). If the system call's failure is just an internal implementation detail, you should wrap the problem up in your own exception to expose the high level issue.

(This is the difference between 'cannot resolve hostname, nameserver not available' and 'sendto() failed'. A DNS module that returned the latter would be technically correct but not useful.)

Written on 20 August 2009.
« Link: Using colour well in data visualization
The danger of powerful generality, illustrated »

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

Last modified: Thu Aug 20 00:04:01 2009
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.