An important convention throughout the Python interpreter is the
following: when a function fails, it should set an exception condition
and return an error value (usually a NULL
pointer). Exceptions
are stored in a static global variable inside the interpreter; if this
variable is NULL
no exception has occurred. A second global
variable stores the ``associated value'' of the exception (the second
argument to raise
). A third variable contains the stack
traceback in case the error originated in Python code. These three
variables are the C equivalents of the Python variables
sys.exc_type
, sys.exc_value
and sys.exc_traceback
(see the section on module sys
in the Library Reference
Manual). It is important to know about them to understand how errors
are passed around.
The Python API defines a number of functions to set various types of exceptions.
The most common one is PyErr_SetString()
. Its arguments are an
exception object and a C string. The exception object is usually a
predefined object like PyExc_ZeroDivisionError
. The C string
indicates the cause of the error and is converted to a Python string
object and stored as the ``associated value'' of the exception.
Another useful function is PyErr_SetFromErrno()
, which only
takes an exception argument and constructs the associated value by
inspection of the (Unix) global variable errno
. The most
general function is PyErr_SetObject()
, which takes two object
arguments, the exception and its associated value. You don't need to
Py_INCREF()
the objects passed to any of these functions.
You can test non-destructively whether an exception has been set with
PyErr_Occurred()
. This returns the current exception object,
or NULL
if no exception has occurred. You normally don't need
to call PyErr_Occurred()
to see whether an error occurred in a
function call, since you should be able to tell from the return value.
When a function f that calls another function varg detects
that the latter fails, f should itself return an error value
(e.g. NULL
or -1
). It should not call one of the
PyErr_*()
functions --- one has already been called by g.
f's caller is then supposed to also return an error indication
to its caller, again without calling PyErr_*()
,
and so on --- the most detailed cause of the error was already
reported by the function that first detected it. Once the error
reaches the Python interpreter's main loop, this aborts the currently
executing Python code and tries to find an exception handler specified
by the Python programmer.
(There are situations where a module can actually give a more detailed
error message by calling another PyErr_*()
function, and in
such cases it is fine to do so. As a general rule, however, this is
not necessary, and can cause information about the cause of the error
to be lost: most operations can fail for a variety of reasons.)
To ignore an exception set by a function call that failed, the exception
condition must be cleared explicitly by calling PyErr_Clear()
.
The only time C code should call PyErr_Clear()
is if it doesn't
want to pass the error on to the interpreter but wants to handle it
completely by itself (e.g. by trying something else or pretending
nothing happened).
Note that a failing malloc()
call must be turned into an
exception --- the direct caller of malloc()
(or
realloc()
) must call PyErr_NoMemory()
and return a
failure indicator itself. All the object-creating functions
(PyInt_FromLong()
etc.) already do this, so only if you call
malloc()
directly this note is of importance.
Also note that, with the important exception of
PyArg_ParseTuple()
and friends, functions that return an
integer status usually return a positive value or zero for success and
-1
for failure, like Unix system calls.
Finally, be careful to clean up garbage (by making Py_XDECREF()
or Py_DECREF()
calls for objects you have already created) when
you return an error indicator!
The choice of which exception to raise is entirely yours. There are
predeclared C objects corresponding to all built-in Python exceptions,
e.g. PyExc_ZeroDevisionError
which you can use directly. Of
course, you should choose exceptions wisely --- don't use
PyExc_TypeError
to mean that a file couldn't be opened (that
should probably be PyExc_IOError
). If something's wrong with
the argument list, the PyArg_ParseTuple()
function usually
raises PyExc_TypeError
. If you have an argument whose value
which must be in a particular range or must satisfy other conditions,
PyExc_ValueError
is appropriate.
You can also define a new exception that is unique to your module. For this, you usually declare a static object variable at the beginning of your file, e.g.
static PyObject *SpamError;
and initialize it in your module's initialization function
(initspam()
) with a string object, e.g. (leaving out the error
checking for now):
void initspam() { PyObject *m, *d; m = Py_InitModule("spam", SpamMethods); d = PyModule_GetDict(m); SpamError = PyString_FromString("spam.error"); PyDict_SetItemString(d, "error", SpamError); }
Note that the Python name for the exception object is
spam.error
. It is conventional for module and exception names
to be spelled in lower case. It is also conventional that the
value of the exception object is the same as its name, e.g.\
the string "spam.error"
.