I'm working on a C-extension for Python which implements a method that converts a list of numpy elements (numpy.uint64
in this case) to the unsigned long long
C-type (using the PyLong_AsUnsignedLongLong
function). The elements of the list are then summed up and the resulting sum is returned to the Python layer.
To create the module I wrote this code in testmodule.c
:
#include <Python.h>
static PyObject *method_sum_list_u64(PyObject *self, PyObject *args);
static PyMethodDef testmoduleMethods[] = {
{"sum_list_u64", method_sum_list_u64, METH_VARARGS, "docs"},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef testmodule = {
PyModuleDef_HEAD_INIT,
"testmodule",
"docs",
-1,
testmoduleMethods
};
PyMODINIT_FUNC PyInit_testmodule(void) {
return PyModule_Create(&testmodule);
}
And here is my method:
static PyObject *method_print_list_u64(PyObject *self, PyObject *args) {
uint64_t sum = 0;
PyObject *input_list;
if (!PyArg_ParseTuple(args, "O!", &PyList_Type, &input_list))
{
return NULL;
}
Py_ssize_t data_points = PyList_Size(input_list);
for (Py_ssize_t i = 0; i < data_points; i++)
{
PyObject *item = PyList_GetItem(input_list, i);
sum += PyLong_AsUnsignedLongLong(item);
}
return PyLong_FromUnsignedLongLong(sum);
}
My setup.py
file:
from setuptools import setup, Extension
def main():
setup(name="testmodule",
version="1.0.1",
description="Python interface for the testmodule C library function",
ext_modules=[Extension("testmodule", ["testmodule.c"])])
if __name__ == "__main__":
main()
And a simple test script called mytest.py
:
import numpy as np
import testmodule
input_list = [np.uint64(1000)]
print(testmodule.sum_list_u64(input_list))
To reproduce the error I run:
$ python setup.py install
$ python mytest.py
TypeError: an integer is required
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "mytest.py", line 5, in <module>
print(testmodule.sum_list_u64(input_list))
SystemError: <built-in function sum_list_u64> returned a result with an error set
Now, if I replace PyLong_AsUnsignedLongLong
with PyLong_AsLongLong
everything works fine. Why does PyLong_AsUnsignedLongLong
fail and PyLong_AsLongLong
doesn't?