
Take a look at the attached extension module "testlite" which demonstrates the technique I evolved from this discussion. As we discussed, this usage pattern enables the construction of an extension which will take advantage of numarray if it is there, but will continue to work if the user has not installed numarray. Here's how it works: 1. I created a new API function, PyArray_isArray() which is safe to call in all contexts. I defined it as: #define PyArray_isArray(o) (PyArray_API && NA_isNumArray(o)) I added NA_isNumArray(o) to the numarray C-API because it was the easy way to do it. 2. Ordinary API functions are safe to call once an object has been identified to be a numarray because it implies (locally) that the PyArray_API pointer has been initialized. 3. I tried out the standard import_array() code and added some cleanup for the case where numarray is not installed. The only caveat I see at this point is that you are required to include numarray headers in order to use this. In numarray's case, this might necessitate header updates and/or function call modifications. The numarray C-API should stabilize pretty soon, but I don't think its quite there yet. The same approach should apply to Numeric. This stuff is in numarray CVS now and should be in the next numarray release. Todd /* This module demonstrates how to make a weak linkage between an extension module (which might consider numarray to be optional) and numarray. There are essentially two parts to the "weak linkage": 1. PyArray_isArray(o) identifies if an arbitrary Python object is a NumArray. Once it is known that an object is a numarray, assume that PyArray_API has been initialized and call API functions. PyArray_isArray(o) is unique in the sense that it will work correctly even if numarray is not installed. In that case, it always reports false. Because of this, PyArray_isArray() is useful as a guard around arbitrary API functions which should never be called when numarray is not present. Doing so results in a call to NULL and ensuing segfault. 2. At module init time, prior to calling and numarray API functions, call import_array(). Since, in the case where numarray has *not* been installed, the import_array() call will fail, check for and clear the Python error state. This will prevent the Python exception handling mechanisms from inadvertantly trapping the error later on. */ #include "Python.h" #include <stdio.h> #include <math.h> #include <signal.h> #include <ctype.h> #include "arrayobject.h" static PyObject *_Error; static PyObject * Py_testit(PyObject *obj, PyObject *args) { PyObject *it; if (!PyArg_ParseTuple(args, "O", &it)) return PyErr_Format(_Error, "testit: Invalid parameters."); if (PyArray_isArray(it)) { fprintf(stderr, "It's an array.\n"); /* It's safe to call API functions in here */ } else { fprintf(stderr, "It't not an array.\n"); /* But never call numarray API functions out here. */ } Py_INCREF(Py_None); return Py_None; } static PyMethodDef _Methods[] = { {"testit", Py_testit, METH_VARARGS, "testit(obj) prints a message identifying an object."}, {NULL, NULL} /* Sentinel */ }; /* platform independent*/ #ifdef MS_WIN32 __declspec(dllexport) #endif void inittestlite(void) { PyObject *m, *d; m = Py_InitModule("testlite", _Methods); d = PyModule_GetDict(m); _Error = PyErr_NewException("testlite.error", NULL, NULL); PyDict_SetItemString(d, "error", _Error); import_array(); if (PyErr_Occurred()) PyErr_Clear(); } /* * Local Variables: * mode: C * c-file-style: "python" * End: */