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

Guilherme Polo ggpolo at gmail.com
Mon Dec 22 13:48:46 CET 2008


On Mon, Dec 22, 2008 at 10:45 AM, Guilherme Polo <ggpolo at gmail.com> wrote:
> 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

By creating a type I mean one that involves defining a tp_init, and
everything else your type needs, not about the simple one created by
PyErr_NewException.

> , 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
>



-- 
-- Guilherme H. Polo Goncalves


More information about the Python-Dev mailing list