[Libvir] Python bindings, errors & exceptions

Daniel P. Berrange berrange at redhat.com
Fri Mar 23 12:58:04 UTC 2007


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




More information about the libvir-list mailing list