On Wed, Oct 01, 2008 at 05:14:03PM +0200, Emanuele Olivetti wrote:
> Michael Hanke wrote:
> > On Wed, Oct 01, 2008 at 09:43:48AM -0400, Yaroslav Halchenko wrote:
> >> heh -- well we have workaround already I think -- I've done pure python
> >> implementation. We just need proper check for weave in externals I guess
> >
> > I don't think that is done via a test -- i have everything installed (I
> > think).
> >
> >
>
> It could be interesting to investigate this issue a bit more. Under
> ~/.python25_compiled/ you should have the automatically generated C++
> sources of the broken code (and some compiled shared objects as
> well). Usually the source code is a big wrapper plus few lines of
> useful C++ code. The source can be compiled and inspected offline.
>
> Can you send the source of the broken example to us? I can compare
> against my code.
Here is the code, and just the code, as it could never be compiled.
But again, why runtime compiling as opposed to proper extensions?
Michael
--
GPG key: 1024D/3144BE0F Michael Hanke
http://apsy.gse.uni-magdeburg.de/hanke
ICQ: 48230050
#ifdef __CPLUSPLUS__
extern "C" {
#endif
#ifndef __GNUC__
#pragma warning(disable: 4275)
#pragma warning(disable: 4101)
#endif
#include "Python.h"
#include "blitz/array.h"
#include "compile.h"
#include "frameobject.h"
#include <complex>
#include <math.h>
#include <string>
#include "scxx/object.h"
#include "scxx/list.h"
#include "scxx/tuple.h"
#include "scxx/dict.h"
#include <iostream>
#include <stdio.h>
#include "numpy/arrayobject.h"
// global None value for use in functions.
namespace py {
object None = object(Py_None);
}
char* find_type(PyObject* py_obj)
{
if(py_obj == NULL) return "C NULL value";
if(PyCallable_Check(py_obj)) return "callable";
if(PyString_Check(py_obj)) return "string";
if(PyInt_Check(py_obj)) return "int";
if(PyFloat_Check(py_obj)) return "float";
if(PyDict_Check(py_obj)) return "dict";
if(PyList_Check(py_obj)) return "list";
if(PyTuple_Check(py_obj)) return "tuple";
if(PyFile_Check(py_obj)) return "file";
if(PyModule_Check(py_obj)) return "module";
//should probably do more intergation (and thinking) on these.
if(PyCallable_Check(py_obj) && PyInstance_Check(py_obj)) return "callable";
if(PyInstance_Check(py_obj)) return "instance";
if(PyCallable_Check(py_obj)) return "callable";
return "unkown type";
}
void throw_error(PyObject* exc, const char* msg)
{
//printf("setting python error: %s\n",msg);
PyErr_SetString(exc, msg);
//printf("throwing error\n");
throw 1;
}
void handle_bad_type(PyObject* py_obj, const char* good_type, const char* var_name)
{
char msg[500];
sprintf(msg,"received '%s' type instead of '%s' for variable '%s'",
find_type(py_obj),good_type,var_name);
throw_error(PyExc_TypeError,msg);
}
void handle_conversion_error(PyObject* py_obj, const char* good_type, const char* var_name)
{
char msg[500];
sprintf(msg,"Conversion Error:, received '%s' type instead of '%s' for variable '%s'",
find_type(py_obj),good_type,var_name);
throw_error(PyExc_TypeError,msg);
}
class int_handler
{
public:
int convert_to_int(PyObject* py_obj, const char* name)
{
// Incref occurs even if conversion fails so that
// the decref in cleanup_code has a matching incref.
if (!py_obj || !PyInt_Check(py_obj))
handle_conversion_error(py_obj,"int", name);
return (int) PyInt_AsLong(py_obj);
}
int py_to_int(PyObject* py_obj, const char* name)
{
// !! Pretty sure INCREF should only be called on success since
// !! py_to_xxx is used by the user -- not the code generator.
if (!py_obj || !PyInt_Check(py_obj))
handle_bad_type(py_obj,"int", name);
return (int) PyInt_AsLong(py_obj);
}
};
int_handler x__int_handler = int_handler();
#define convert_to_int(py_obj,name) \
x__int_handler.convert_to_int(py_obj,name)
#define py_to_int(py_obj,name) \
x__int_handler.py_to_int(py_obj,name)
PyObject* int_to_py(PyObject* obj)
{
return (PyObject*) obj;
}
class float_handler
{
public:
double convert_to_float(PyObject* py_obj, const char* name)
{
// Incref occurs even if conversion fails so that
// the decref in cleanup_code has a matching incref.
if (!py_obj || !PyFloat_Check(py_obj))
handle_conversion_error(py_obj,"float", name);
return PyFloat_AsDouble(py_obj);
}
double py_to_float(PyObject* py_obj, const char* name)
{
// !! Pretty sure INCREF should only be called on success since
// !! py_to_xxx is used by the user -- not the code generator.
if (!py_obj || !PyFloat_Check(py_obj))
handle_bad_type(py_obj,"float", name);
return PyFloat_AsDouble(py_obj);
}
};
float_handler x__float_handler = float_handler();
#define convert_to_float(py_obj,name) \
x__float_handler.convert_to_float(py_obj,name)
#define py_to_float(py_obj,name) \
x__float_handler.py_to_float(py_obj,name)
PyObject* float_to_py(PyObject* obj)
{
return (PyObject*) obj;
}
class complex_handler
{
public:
std::complex<double> convert_to_complex(PyObject* py_obj, const char* name)
{
// Incref occurs even if conversion fails so that
// the decref in cleanup_code has a matching incref.
if (!py_obj || !PyComplex_Check(py_obj))
handle_conversion_error(py_obj,"complex", name);
return std::complex<double>(PyComplex_RealAsDouble(py_obj),PyComplex_ImagAsDouble(py_obj));
}
std::complex<double> py_to_complex(PyObject* py_obj, const char* name)
{
// !! Pretty sure INCREF should only be called on success since
// !! py_to_xxx is used by the user -- not the code generator.
if (!py_obj || !PyComplex_Check(py_obj))
handle_bad_type(py_obj,"complex", name);
return std::complex<double>(PyComplex_RealAsDouble(py_obj),PyComplex_ImagAsDouble(py_obj));
}
};
complex_handler x__complex_handler = complex_handler();
#define convert_to_complex(py_obj,name) \
x__complex_handler.convert_to_complex(py_obj,name)
#define py_to_complex(py_obj,name) \
x__complex_handler.py_to_complex(py_obj,name)
PyObject* complex_to_py(PyObject* obj)
{
return (PyObject*) obj;
}
class unicode_handler
{
public:
Py_UNICODE* convert_to_unicode(PyObject* py_obj, const char* name)
{
// Incref occurs even if conversion fails so that
// the decref in cleanup_code has a matching incref.
Py_XINCREF(py_obj);
if (!py_obj || !PyUnicode_Check(py_obj))
handle_conversion_error(py_obj,"unicode", name);
return PyUnicode_AS_UNICODE(py_obj);
}
Py_UNICODE* py_to_unicode(PyObject* py_obj, const char* name)
{
// !! Pretty sure INCREF should only be called on success since
// !! py_to_xxx is used by the user -- not the code generator.
if (!py_obj || !PyUnicode_Check(py_obj))
handle_bad_type(py_obj,"unicode", name);
Py_XINCREF(py_obj);
return PyUnicode_AS_UNICODE(py_obj);
}
};
unicode_handler x__unicode_handler = unicode_handler();
#define convert_to_unicode(py_obj,name) \
x__unicode_handler.convert_to_unicode(py_obj,name)
#define py_to_unicode(py_obj,name) \
x__unicode_handler.py_to_unicode(py_obj,name)
PyObject* unicode_to_py(PyObject* obj)
{
return (PyObject*) obj;
}
class string_handler
{
public:
std::string convert_to_string(PyObject* py_obj, const char* name)
{
// Incref occurs even if conversion fails so that
// the decref in cleanup_code has a matching incref.
Py_XINCREF(py_obj);
if (!py_obj || !PyString_Check(py_obj))
handle_conversion_error(py_obj,"string", name);
return std::string(PyString_AsString(py_obj));
}
std::string py_to_string(PyObject* py_obj, const char* name)
{
// !! Pretty sure INCREF should only be called on success since
// !! py_to_xxx is used by the user -- not the code generator.
if (!py_obj || !PyString_Check(py_obj))
handle_bad_type(py_obj,"string", name);
Py_XINCREF(py_obj);
return std::string(PyString_AsString(py_obj));
}
};
string_handler x__string_handler = string_handler();
#define convert_to_string(py_obj,name) \
x__string_handler.convert_to_string(py_obj,name)
#define py_to_string(py_obj,name) \
x__string_handler.py_to_string(py_obj,name)
PyObject* string_to_py(std::string s)
{
return PyString_FromString(s.c_str());
}
class list_handler
{
public:
py::list convert_to_list(PyObject* py_obj, const char* name)
{
// Incref occurs even if conversion fails so that
// the decref in cleanup_code has a matching incref.
if (!py_obj || !PyList_Check(py_obj))
handle_conversion_error(py_obj,"list", name);
return py::list(py_obj);
}
py::list py_to_list(PyObject* py_obj, const char* name)
{
// !! Pretty sure INCREF should only be called on success since
// !! py_to_xxx is used by the user -- not the code generator.
if (!py_obj || !PyList_Check(py_obj))
handle_bad_type(py_obj,"list", name);
return py::list(py_obj);
}
};
list_handler x__list_handler = list_handler();
#define convert_to_list(py_obj,name) \
x__list_handler.convert_to_list(py_obj,name)
#define py_to_list(py_obj,name) \
x__list_handler.py_to_list(py_obj,name)
PyObject* list_to_py(PyObject* obj)
{
return (PyObject*) obj;
}
class dict_handler
{
public:
py::dict convert_to_dict(PyObject* py_obj, const char* name)
{
// Incref occurs even if conversion fails so that
// the decref in cleanup_code has a matching incref.
if (!py_obj || !PyDict_Check(py_obj))
handle_conversion_error(py_obj,"dict", name);
return py::dict(py_obj);
}
py::dict py_to_dict(PyObject* py_obj, const char* name)
{
// !! Pretty sure INCREF should only be called on success since
// !! py_to_xxx is used by the user -- not the code generator.
if (!py_obj || !PyDict_Check(py_obj))
handle_bad_type(py_obj,"dict", name);
return py::dict(py_obj);
}
};
dict_handler x__dict_handler = dict_handler();
#define convert_to_dict(py_obj,name) \
x__dict_handler.convert_to_dict(py_obj,name)
#define py_to_dict(py_obj,name) \
x__dict_handler.py_to_dict(py_obj,name)
PyObject* dict_to_py(PyObject* obj)
{
return (PyObject*) obj;
}
class tuple_handler
{
public:
py::tuple convert_to_tuple(PyObject* py_obj, const char* name)
{
// Incref occurs even if conversion fails so that
// the decref in cleanup_code has a matching incref.
if (!py_obj || !PyTuple_Check(py_obj))
handle_conversion_error(py_obj,"tuple", name);
return py::tuple(py_obj);
}
py::tuple py_to_tuple(PyObject* py_obj, const char* name)
{
// !! Pretty sure INCREF should only be called on success since
// !! py_to_xxx is used by the user -- not the code generator.
if (!py_obj || !PyTuple_Check(py_obj))
handle_bad_type(py_obj,"tuple", name);
return py::tuple(py_obj);
}
};
tuple_handler x__tuple_handler = tuple_handler();
#define convert_to_tuple(py_obj,name) \
x__tuple_handler.convert_to_tuple(py_obj,name)
#define py_to_tuple(py_obj,name) \
x__tuple_handler.py_to_tuple(py_obj,name)
PyObject* tuple_to_py(PyObject* obj)
{
return (PyObject*) obj;
}
class file_handler
{
public:
FILE* convert_to_file(PyObject* py_obj, const char* name)
{
// Incref occurs even if conversion fails so that
// the decref in cleanup_code has a matching incref.
Py_XINCREF(py_obj);
if (!py_obj || !PyFile_Check(py_obj))
handle_conversion_error(py_obj,"file", name);
return PyFile_AsFile(py_obj);
}
FILE* py_to_file(PyObject* py_obj, const char* name)
{
// !! Pretty sure INCREF should only be called on success since
// !! py_to_xxx is used by the user -- not the code generator.
if (!py_obj || !PyFile_Check(py_obj))
handle_bad_type(py_obj,"file", name);
Py_XINCREF(py_obj);
return PyFile_AsFile(py_obj);
}
};
file_handler x__file_handler = file_handler();
#define convert_to_file(py_obj,name) \
x__file_handler.convert_to_file(py_obj,name)
#define py_to_file(py_obj,name) \
x__file_handler.py_to_file(py_obj,name)
PyObject* file_to_py(FILE* file, char* name, char* mode)
{
return (PyObject*) PyFile_FromFile(file, name, mode, fclose);
}
class instance_handler
{
public:
py::object convert_to_instance(PyObject* py_obj, const char* name)
{
// Incref occurs even if conversion fails so that
// the decref in cleanup_code has a matching incref.
if (!py_obj || !PyInstance_Check(py_obj))
handle_conversion_error(py_obj,"instance", name);
return py::object(py_obj);
}
py::object py_to_instance(PyObject* py_obj, const char* name)
{
// !! Pretty sure INCREF should only be called on success since
// !! py_to_xxx is used by the user -- not the code generator.
if (!py_obj || !PyInstance_Check(py_obj))
handle_bad_type(py_obj,"instance", name);
return py::object(py_obj);
}
};
instance_handler x__instance_handler = instance_handler();
#define convert_to_instance(py_obj,name) \
x__instance_handler.convert_to_instance(py_obj,name)
#define py_to_instance(py_obj,name) \
x__instance_handler.py_to_instance(py_obj,name)
PyObject* instance_to_py(PyObject* obj)
{
return (PyObject*) obj;
}
class numpy_size_handler
{
public:
void conversion_numpy_check_size(PyArrayObject* arr_obj, int Ndims,
const char* name)
{
if (arr_obj->nd != Ndims)
{
char msg[500];
sprintf(msg,"Conversion Error: received '%d' dimensional array instead of '%d' dimensional array for variable '%s'",
arr_obj->nd,Ndims,name);
throw_error(PyExc_TypeError,msg);
}
}
void numpy_check_size(PyArrayObject* arr_obj, int Ndims, const char* name)
{
if (arr_obj->nd != Ndims)
{
char msg[500];
sprintf(msg,"received '%d' dimensional array instead of '%d' dimensional array for variable '%s'",
arr_obj->nd,Ndims,name);
throw_error(PyExc_TypeError,msg);
}
}
};
numpy_size_handler x__numpy_size_handler = numpy_size_handler();
#define conversion_numpy_check_size x__numpy_size_handler.conversion_numpy_check_size
#define numpy_check_size x__numpy_size_handler.numpy_check_size
class numpy_type_handler
{
public:
void conversion_numpy_check_type(PyArrayObject* arr_obj, int numeric_type,
const char* name)
{
// Make sure input has correct numeric type.
int arr_type = arr_obj->descr->type_num;
if (PyTypeNum_ISEXTENDED(numeric_type))
{
char msg[80];
sprintf(msg, "Conversion Error: extended types not supported for variable '%s'",
name);
throw_error(PyExc_TypeError, msg);
}
if (!PyArray_EquivTypenums(arr_type, numeric_type))
{
char* type_names[23] = {"bool", "byte", "ubyte","short", "ushort",
"int", "uint", "long", "ulong", "longlong", "ulonglong",
"float", "double", "longdouble", "cfloat", "cdouble",
"clongdouble", "object", "string", "unicode", "void", "ntype",
"unknown"};
char msg[500];
sprintf(msg,"Conversion Error: received '%s' typed array instead of '%s' typed array for variable '%s'",
type_names[arr_type],type_names[numeric_type],name);
throw_error(PyExc_TypeError,msg);
}
}
void numpy_check_type(PyArrayObject* arr_obj, int numeric_type, const char* name)
{
// Make sure input has correct numeric type.
int arr_type = arr_obj->descr->type_num;
if (PyTypeNum_ISEXTENDED(numeric_type))
{
char msg[80];
sprintf(msg, "Conversion Error: extended types not supported for variable '%s'",
name);
throw_error(PyExc_TypeError, msg);
}
if (!PyArray_EquivTypenums(arr_type, numeric_type))
{
char* type_names[23] = {"bool", "byte", "ubyte","short", "ushort",
"int", "uint", "long", "ulong", "longlong", "ulonglong",
"float", "double", "longdouble", "cfloat", "cdouble",
"clongdouble", "object", "string", "unicode", "void", "ntype",
"unknown"};
char msg[500];
sprintf(msg,"received '%s' typed array instead of '%s' typed array for variable '%s'",
type_names[arr_type],type_names[numeric_type],name);
throw_error(PyExc_TypeError,msg);
}
}
};
numpy_type_handler x__numpy_type_handler = numpy_type_handler();
#define conversion_numpy_check_type x__numpy_type_handler.conversion_numpy_check_type
#define numpy_check_type x__numpy_type_handler.numpy_check_type
class numpy_handler
{
public:
PyArrayObject* convert_to_numpy(PyObject* py_obj, const char* name)
{
// Incref occurs even if conversion fails so that
// the decref in cleanup_code has a matching incref.
Py_XINCREF(py_obj);
if (!py_obj || !PyArray_Check(py_obj))
handle_conversion_error(py_obj,"numpy", name);
return (PyArrayObject*) py_obj;
}
PyArrayObject* py_to_numpy(PyObject* py_obj, const char* name)
{
// !! Pretty sure INCREF should only be called on success since
// !! py_to_xxx is used by the user -- not the code generator.
if (!py_obj || !PyArray_Check(py_obj))
handle_bad_type(py_obj,"numpy", name);
Py_XINCREF(py_obj);
return (PyArrayObject*) py_obj;
}
};
numpy_handler x__numpy_handler = numpy_handler();
#define convert_to_numpy(py_obj,name) \
x__numpy_handler.convert_to_numpy(py_obj,name)
#define py_to_numpy(py_obj,name) \
x__numpy_handler.py_to_numpy(py_obj,name)
PyObject* numpy_to_py(PyObject* obj)
{
return (PyObject*) obj;
}
class catchall_handler
{
public:
py::object convert_to_catchall(PyObject* py_obj, const char* name)
{
// Incref occurs even if conversion fails so that
// the decref in cleanup_code has a matching incref.
if (!py_obj || !(py_obj))
handle_conversion_error(py_obj,"catchall", name);
return py::object(py_obj);
}
py::object py_to_catchall(PyObject* py_obj, const char* name)
{
// !! Pretty sure INCREF should only be called on success since
// !! py_to_xxx is used by the user -- not the code generator.
if (!py_obj || !(py_obj))
handle_bad_type(py_obj,"catchall", name);
return py::object(py_obj);
}
};
catchall_handler x__catchall_handler = catchall_handler();
#define convert_to_catchall(py_obj,name) \
x__catchall_handler.convert_to_catchall(py_obj,name)
#define py_to_catchall(py_obj,name) \
x__catchall_handler.py_to_catchall(py_obj,name)
PyObject* catchall_to_py(PyObject* obj)
{
return (PyObject*) obj;
}
void handle_variable_not_found(char* var_name)
{
char msg[500];
sprintf(msg,"Conversion Error: variable '%s' not found in local or global scope.",var_name);
throw_error(PyExc_NameError,msg);
}
PyObject* get_variable(char* name,PyObject* locals, PyObject* globals)
{
// no checking done for error -- locals and globals should
// already be validated as dictionaries. If var is NULL, the
// function calling this should handle it.
PyObject* var = NULL;
var = PyDict_GetItemString(locals,name);
if (!var)
{
var = PyDict_GetItemString(globals,name);
}
if (!var)
handle_variable_not_found(name);
return var;
}
PyObject* py_to_raw_dict(PyObject* py_obj, char* name)
{
// simply check that the value is a valid dictionary pointer.
if(!py_obj || !PyDict_Check(py_obj))
handle_bad_type(py_obj, "dictionary", name);
return py_obj;
}
// This should be declared only if they are used by some function
// to keep from generating needless warnings. for now, we'll always
// declare them.
int _beg = blitz::fromStart;
int _end = blitz::toEnd;
blitz::Range _all = blitz::Range::all();
template<class T, int N>
static blitz::Array<T,N> convert_to_blitz(PyArrayObject* arr_obj,const char* name)
{
blitz::TinyVector<int,N> shape(0);
blitz::TinyVector<int,N> strides(0);
int stride_acc = 1;
//for (int i = N-1; i >=0; i--)
for (int i = 0; i < N; i++)
{
shape[i] = arr_obj->dimensions[i];
strides[i] = arr_obj->strides[i]/sizeof(T);
}
//return blitz::Array<T,N>((T*) arr_obj->data,shape,
return blitz::Array<T,N>((T*) arr_obj->data,shape,strides,
blitz::neverDeleteData);
}
template<class T, int N>
static blitz::Array<T,N> py_to_blitz(PyArrayObject* arr_obj,const char* name)
{
blitz::TinyVector<int,N> shape(0);
blitz::TinyVector<int,N> strides(0);
int stride_acc = 1;
//for (int i = N-1; i >=0; i--)
for (int i = 0; i < N; i++)
{
shape[i] = arr_obj->dimensions[i];
strides[i] = arr_obj->strides[i]/sizeof(T);
}
//return blitz::Array<T,N>((T*) arr_obj->data,shape,
return blitz::Array<T,N>((T*) arr_obj->data,shape,strides,
blitz::neverDeleteData);
}
static PyObject* compiled_func(PyObject*self, PyObject* args)
{
py::object return_val;
int exception_occured = 0;
PyObject *py__locals = NULL;
PyObject *py__globals = NULL;
PyObject *py_data1, *py_S1, *py_F, *py_weight, *py_d, *py_p;
py_data1 = py_S1 = py_F = py_weight = py_d = py_p = NULL;
if(!PyArg_ParseTuple(args,"OO:compiled_func",&py__locals,&py__globals))
return NULL;
try
{
PyObject* raw_locals = py_to_raw_dict(py__locals,"_locals");
PyObject* raw_globals = py_to_raw_dict(py__globals,"_globals");
/* argument conversion code */
py_data1 = get_variable("data1",raw_locals,raw_globals);
PyArrayObject* data1_array = convert_to_numpy(py_data1,"data1");
conversion_numpy_check_type(data1_array,PyArray_DOUBLE,"data1");
conversion_numpy_check_size(data1_array,2,"data1");
blitz::Array<double,2> data1 = convert_to_blitz<double,2>(data1_array,"data1");
blitz::TinyVector<int,2> Ndata1 = data1.shape();
py_S1 = get_variable("S1",raw_locals,raw_globals);
int S1 = convert_to_int(py_S1,"S1");
py_F = get_variable("F",raw_locals,raw_globals);
int F = convert_to_int(py_F,"F");
py_weight = get_variable("weight",raw_locals,raw_globals);
PyArrayObject* weight_array = convert_to_numpy(py_weight,"weight");
conversion_numpy_check_type(weight_array,PyArray_DOUBLE,"weight");
conversion_numpy_check_size(weight_array,1,"weight");
blitz::Array<double,1> weight = convert_to_blitz<double,1>(weight_array,"weight");
blitz::TinyVector<int,1> Nweight = weight.shape();
py_d = get_variable("d",raw_locals,raw_globals);
PyArrayObject* d_array = convert_to_numpy(py_d,"d");
conversion_numpy_check_type(d_array,PyArray_DOUBLE,"d");
conversion_numpy_check_size(d_array,2,"d");
blitz::Array<double,2> d = convert_to_blitz<double,2>(d_array,"d");
blitz::TinyVector<int,2> Nd = d.shape();
py_p = get_variable("p",raw_locals,raw_globals);
int p = convert_to_int(py_p,"p");
/* inline code */
/* NDARRAY API VERSION 1000009 */
int i,j,t;
double tmp, tmp2;
for (i=0; i<S1-1; i++) {
for (j=i+1; j<S1; j++) {
tmp = 0.0;
for(t=0; t<F; t++) {
tmp = tmp+weight(t)*fabs(data1(i,t)-data1(j,t));
}
d(i,j) = tmp;
}
}
return_val = 0;
/*I would like to fill in changed locals and globals here...*/
}
catch(...)
{
return_val = py::object();
exception_occured = 1;
}
/* cleanup code */
Py_XDECREF(py_data1);
Py_XDECREF(py_weight);
Py_XDECREF(py_d);
if(!(PyObject*)return_val && !exception_occured)
{
return_val = Py_None;
}
return return_val.disown();
}
static PyMethodDef compiled_methods[] =
{
{"compiled_func",(PyCFunction)compiled_func , METH_VARARGS},
{NULL, NULL} /* Sentinel */
};
PyMODINIT_FUNC initsc_d72e19998f429431bc88033f9d65db8a0(void)
{
Py_Initialize();
import_array();
PyImport_ImportModule("numpy");
(void) Py_InitModule("sc_d72e19998f429431bc88033f9d65db8a0", compiled_methods);
}
#ifdef __CPLUSCPLUS__
}
#endif
_______________________________________________
Pkg-ExpPsy-PyMVPA mailing list
[email protected]
http://lists.alioth.debian.org/mailman/listinfo/pkg-exppsy-pymvpa