numpy 1.7, python 3.+, and compressionmodule.c

268 views
Skip to first unread message

Alex Conley

unread,
Dec 7, 2012, 4:29:03 PM12/7/12
to astro...@googlegroups.com
I'm not sure if it's better to report this here or to pyfits, but there is a return type
bug that affects installing the developer build of astropy with numpy 1.7b2
and python 3.3.

Digging around, __multiarray_api.h (in numpy/core/include/numpy)
defines import_array (a macro) to return an actual value in numpy 1.7
for python 3.+, while for earlier versions it just does a return (that is,
it's void).  That means that anything that calls import_array can't be a void function for bleeding edge
numpy/python builds.  And compression_module_init in astropy/astropy/io/fits/src/compressionmodule.c
fails exactly that test.

To be a little more explicit, the numpy API has:
#if PY_VERSION_HEX >= 0x03000000
#define NUMPY_IMPORT_ARRAY_RETVAL NULL
#else
#define NUMPY_IMPORT_ARRAY_RETVAL
#endif

#define import_array() {if (_import_array() < 0) {PyErr_Print(); PyErr_SetString(PyExc_ImportError, "numpy.core.multiarray failed to import"); return NUMPY_IMPORT_ARRAY_RETVAL; } }

and compression_module_init is of type void, and calls this macro.  
The compiler doesn't much care for that.

I made a quick fix for my purposes by just making compression_module_init
return int*, but that would break things for numpy < 1.7 or python < 3.
This probably means something like

#if PY_VERSION_HEX >= 0x03000000
int* compression_module_init(PyObject* module) {
#else
void compression_module_init(PyObject* module) {
#endif

which is pretty hideous.

Alex
 

Erik Bray

unread,
Dec 7, 2012, 5:40:38 PM12/7/12
to astro...@googlegroups.com
Thanks for pointing this out. I see the problem--I didn't realize
import_array() was a macro or that it included a 'return' statement.
I think this was working fine for me in Python 2.7, but I have not
tested this with the dev version of Numpy under Python 3.

Given that the import_array() macro is meant to be used at the end of
the module init function, I can see why they made this change. In
Python < 3 the PyMODINIT_FUNC returns void, whereas in Python 3 it's
meant to return a PyObject*. But in compressionmodule.c
import_array() actually gets called from within the
compression_module_init() function.

Rather that put some ugly preprocessor stuff around the
compression_module_init function it should work for me to just move
the import_array() call back into the actual module init functions.

Erik Bray

unread,
Dec 7, 2012, 5:52:38 PM12/7/12
to astro...@googlegroups.com
Fixed at the PyFITS end here:
https://github.com/iguananaut/PyFITS/commit/6dd5bc4c4a24e2aeb07db88c2152c743b05704ce

I'll merge this downstream to Astropy in a bit.

Erik
Reply all
Reply to author
Forward
0 new messages