
On Fri, Mar 23, 2007 at 12:12:56PM +0000, Richard W.M. Jones wrote:
I'm really confused about how the Python bindings are supposed to handle errors. Can someone explain how this is supposed to work?
Case in point: currently virt-manager fails because conn.listNetworks () returns None, whereas virt-manager is expecting it to return a list of network objects. The code returns None because the underlying calls (either virConnectNumOfNetworks or virConnectListNetworks) is failing.
The functions in question are:
class virConnect: # libvirtclass.py # ... def listNetworks(self): """list the networks, stores the pointers to the names in @names """ ret = libvirtmod.virConnectListNetworks(self._o) return ret
(the above code is automatically generated by generator.py), and:
static PyObject * // libvir.c libvirt_virConnectListNetworks(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { PyObject *py_retval; char **names = NULL; int c_retval, i; virConnectPtr conn; PyObject *pyobj_conn;
// ...
c_retval = virConnectNumOfNetworks(conn); if (c_retval < 0) { Py_INCREF(Py_None); return (Py_None); }
// ...
py_retval = PyList_New(c_retval);
if (names) { for (i = 0;i < c_retval;i++) { PyList_SetItem(py_retval, i, libvirt_constcharPtrWrap(names[i])); free(names[i]); } free(names); }
return(py_retval); }
(I've omitted some code to make the general idea clearer).
The upshot is that if the underlying functions fail, at no point is an exception thrown.
Yes, returning None here is totally bogus - it should be raising a libvirtError object.
This is not always the case. For other functions which return C structure pointers (eg. libvirt.open which wraps virConnectOpen), the bindings automatically catch the invalid return and throw an exception. For example:
def open(name): # libvirtclass.py """This function should be called first to get a connection to the Hypervisor and xen store """ ret = libvirtmod.virConnectOpen(name) if ret is None:raise libvirtError('virConnectOpen() failed') return virConnect(_obj=ret)
It is my view that all errors in C code should turn into Python exceptions.
Indeed they should - all the generated C code bindings do - its just a few of these hand written bindings that are wrong.
One way to do that would be to have a Python virterror handler which just directly throws the exception. I don't know if this is safe because the exception would unwind through C code, and in some languages that is safe, in others it is not.
I can't see that being remotely safe to do in python.
Another way would be to have a Python virterror handler which remembers that an exception happened, and after each auto-generated function call we check this and raise the exception. Since I'm just starting out in Python, I don't know if there are thread or other issues with this.
That shouldn't be neccessary - the libvirtError() constructor calls the virGetLastError or virConnectGetLastError functions to retrieve the full error report details. So simply raise libvirtError("blah", conn) should do the trick. Dan. -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|