[capi-sig] Getting Numbers in C

Campbell Barton cbarton at metavr.com
Fri Jul 20 23:30:16 CEST 2007


Campbell Barton wrote:
> Hrvoje Niksic wrote:
>>> double PyNumber_AsDouble(PyObject * value)
>>> {
>>> 	if (PyFloat_Check(value) || PyInt_Check(value)) {
>>> 		return PyFloat_AsDouble(value);
>>> 	} else {
>>> 		PyObject *pyfloat;
>>> 		double d;
>>>
>>> 		pyfloat = PyNumber_Float(value);
>>> 		d = PyNumber_AsDouble(pyfloat);
>> I assume this should be PyFloat_AsDouble?
>>
>>> 		Py_XDECREF(pyfloat);
>>> 		return d;
>>> 	}
>>> }
>> What happens if PyNumber_Float raises an exception?  As far as I can
>> tell, PyNumber_AsDouble will result in a "bad argument" exception
>> being raised and will return -1, losing track of the original
>> exception in the process.
>>
>> Come to think of it, error checking problems could very well be the
>> reason why the API doesn't provide a PyNumber_AsDouble.
> 
> It is a problem but I dont think thats a good enough reason not to have 
> some way to do this since its such a common operation.
> 
> PyFloat_AsDouble cant return an error value, so enforcing that the 
> pyobject is checked with PyNumber_Check seems reasonable to me.

To follow up on this issue, Iv added the function below to a branch of 
the Blender/Py API so Numbers that aren't pythons Ints of Floats work.

-----------------------------------------------------

double EXPP_PyNumber_AsDouble(PyObject * value)
{
	if (PyFloat_Check(value) || PyInt_Check(value)) {
		return PyFloat_AS_DOUBLE(value);
	} else  {
		PyObject *pyfloat;
		double d;

		pyfloat = PyNumber_Float(value);
		d = PyFloat_AsDouble(pyfloat);
		Py_XDECREF(pyfloat);
		return d; /* will be -1 and set an error if its PyNumber_Float failed */
	}
}
-----------------------------------------------------

from looking at pythons source there are 2 ways to make sure this 
function succeeds.

I was under the impression the only way to do error checking for this 
was to do....

float f;
if (!PyFloat_Check(pyob)) {
     PyErr_SetString(PyExc_TypeError, "float argument required");
     return -1;
}
f = PyFloat_AS_DOUBLE(pyob)



But another way to do it is.... (used in python 2.5.1's stringobject.c:4150)



float f = PyFloat_Check(pyob);
if (f == -1.0 && PyErr_Occurred()) {
     PyErr_SetString(PyExc_TypeError, "float argument required");
     return -1;
}


Which would work with EXPP_PyNumber_AsDouble to do error checking as 
well. so I think error checking is ok with that function. (and would 
like to see PyNumber_AsDouble in the C/Python API hint, hint)

However Im wondering if this is advisable,
with PyErr_Occurred() its possible that some other part of the API (even 
a totaly separate API) sets the error string but dosnt return an error 
value. - Any suggestions?



More information about the capi-sig mailing list