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