[Python-Dev] [capi-sig] Exceptions with additional instance variables

Guilherme Polo ggpolo at gmail.com
Mon Dec 22 13:45:36 CET 2008


On Mon, Dec 22, 2008 at 10:06 AM,  <chojrak11 at gmail.com> wrote:
> On Mon, Dec 22, 2008 at 03:29, Guilherme Polo <ggpolo at gmail.com> wrote:
>> On Sun, Dec 21, 2008 at 11:02 PM,  <chojrak11 at gmail.com> wrote:
>>> Hello,
>>>
>>> I'm trying to implement custom exception that have to carry some
>>> useful info by means of instance members, to be used like:
>>>
>>> try:
>>>    // some code
>>> except MyException, data:
>>>    // use data.errorcode, data.errorcategory, data.errorlevel,
>>> data.errormessage and some others
>>>
>>> The question is - how to implement the instance variables with
>>> PyErr_NewException?
>>
>> Using PyErr_NewException is fine. You must understand that an
>> exception is a class, and thus PyErr_NewException creates one for you
>> and returns it.
>> Just like you would do with a class that has __dict__, set some
>> attributes to what you want. That is, use PyObject_SetAttrString or
>> something more appropriated for you.
>
> Ok so I did the following. In init function (forget refcounting and
> error checking for a moment ;-)
>
> PyObject *dict = PyDict_New();
> PyDict_SetItemString(dict, "errorcode", PyInt_FromLong(0));
> static PyObject *myexception =
> PyErr_NewException("module.MyException", NULL, dict);

You do not really have to create a dict here, one will be created for
you if you pass a NULL there.

> PyModule_AddObject(module, "MyException", myexception);
>
> It worked more or less as expected, the help shown:
>
>  |  ----------------------------------------------------------------------
>  |  Data and other attributes defined here:
>  |
>  |  errorcode = 0
>  |
>  |  ----------------------------------------------------------------------
>
> Then I did the following when raising the exception:
>
> PyObject_SetAttrString(myexception, "errorcode", PyInt_FromLong(111));
> PyErr_SetString(myexception, "Bad thing happened");
> return NULL;
>
> and the test code was:
> try:
>    do_bad_thing();
> except MyException, data:
>
> and you surely already guessed it -- data.errorcode was 0.... Not only
> that, module.MyException.errorcode was also 0...
>
> What I'm doing wrong? I certainly don't get the idea of exceptions in
> Python, especially what is being raised - a class or an instance?

There are two forms raise can take, both will end up involving a class
and a intsance.

> If
> the latter - how's the class instantiated?

You can call a class to instantiate it.

> If not - what about values
> in different threads? The docs are so vague about that...
>
>
> Thanks again in advance,
> Chojrak
>

Again, an exception is a class, so you could create a new type in C,
and do anything you wanted. But you probably don't want to create a
new type to achieve this, so there are two simple ways I'm going to
paste below:

#include "Python.h"

static PyObject *MyErr;

static PyMethodDef module_methods[] = {
	{"raise_test", (PyCFunction)raise_test, METH_NOARGS, NULL},
	{NULL},
};

PyMODINIT_FUNC
initfancy_exc(void)
{
	PyObject *m;

	m = Py_InitModule("fancy_exc", module_methods);
	if (m == NULL)
		return;

	MyErr = PyErr_NewException("fancy_exc.err", NULL, NULL);

	Py_INCREF(MyErr);
	if (PyModule_AddObject(m, "err", MyErr) < 0)
		return;
}

the raise_test function is missing, pick one of these:

static PyObject *
raise_test(PyObject *self)
{
	PyObject_SetAttrString(MyErr, "code", PyInt_FromLong(42));
	PyObject_SetAttrString(MyErr, "category", PyString_FromString("nice one"));
	PyErr_SetString(MyErr, "All is good, I hope");
        return NULL;
}

or

static PyObject *
raise_test(PyObject *self)
{
	
	PyObject *t = PyTuple_New(3);
	PyTuple_SetItem(t, 0, PyString_FromString("error message"));
	PyTuple_SetItem(t, 1, PyInt_FromLong(10));
	PyTuple_SetItem(t, 2, PyString_FromString("category name here"));
	PyErr_SetObject(MyErr, t);
	Py_DECREF(t);
	return NULL;
}

In this second form you check for the args attribute of the exception.

-- 
-- Guilherme H. Polo Goncalves


More information about the Python-Dev mailing list