[Numpy-svn] r3236 - in trunk/numpy/f2py/lib: . src
numpy-svn at scipy.org
numpy-svn at scipy.org
Sat Sep 30 17:03:13 EDT 2006
Author: pearu
Date: 2006-09-30 16:02:52 -0500 (Sat, 30 Sep 2006)
New Revision: 3236
Added:
trunk/numpy/f2py/lib/generate_pyobj_tofrom_funcs.py
trunk/numpy/f2py/lib/wrapper_base.py
Modified:
trunk/numpy/f2py/lib/block_statements.py
trunk/numpy/f2py/lib/python_wrapper.py
trunk/numpy/f2py/lib/src/pyobj_to_Py_complex.c
trunk/numpy/f2py/lib/src/pyobj_to_long.c
trunk/numpy/f2py/lib/src/pyobj_to_npy_longlong.c
trunk/numpy/f2py/lib/src/pyobj_to_string_len.c
trunk/numpy/f2py/lib/typedecl_statements.py
Log:
F2PY G3: wrapping nested derived types.
Modified: trunk/numpy/f2py/lib/block_statements.py
===================================================================
--- trunk/numpy/f2py/lib/block_statements.py 2006-09-29 18:02:25 UTC (rev 3235)
+++ trunk/numpy/f2py/lib/block_statements.py 2006-09-30 21:02:52 UTC (rev 3236)
@@ -1007,6 +1007,37 @@
s += tab + 'END TYPE ' + self.name + '\n'
return s
+ # Wrapper methods:
+
+ def get_bit_size(self, _cache={}):
+ try:
+ return _cache[id(self)]
+ except KeyError:
+ s = 0
+ for name,var in self.a.components.items():
+ s += var.get_bit_size()
+ _cache[id(self)] = s
+ return s
+
+ def get_f_type(self):
+ return 'TYPE(%s)' % (self.name)
+
+ def get_c_type(self):
+ return 'f2py_type_%s_%s' % (self.name, self.get_bit_size())
+
+ def get_c_name(self):
+ return 'f2py_type_%s' % (self.name)
+
+ def get_c_struct_name(self):
+ return self.get_c_name() + '_struct'
+
+ def get_c_struct(self):
+ l = []
+ for name, var in self.a.components.items():
+ t = var.get_typedecl()
+ l.append(' %s %s;' % (t.get_c_type(), name))
+ return 'typedef struct {\n%s\n} %s;' % ('\n'.join(l), self.get_c_struct_name())
+
TypeDecl = Type
# Enum
Added: trunk/numpy/f2py/lib/generate_pyobj_tofrom_funcs.py
===================================================================
--- trunk/numpy/f2py/lib/generate_pyobj_tofrom_funcs.py 2006-09-29 18:02:25 UTC (rev 3235)
+++ trunk/numpy/f2py/lib/generate_pyobj_tofrom_funcs.py 2006-09-30 21:02:52 UTC (rev 3236)
@@ -0,0 +1,129 @@
+"""
+Generate
+ int pyobj_to_<ctype>(PyObject* obj, <ctype>* value)
+ PyObject* pyobj_from_<stype>(<ctype>* value)
+functions.
+"""
+__all__ = ['pyobj_to_npy_scalar','pyobj_to_f2py_string','pyobj_from_npy_scalar']
+
+from utils import CHAR_BIT
+
+def pyobj_from_npy_int(ctype):
+ ctype_bits = int(ctype[7:])
+ itemsize = ctype_bits/CHAR_BIT
+ dtype = ctype.upper()
+ return '''\
+static PyObject* pyobj_from_%(ctype)s(%(ctype)s* value) {
+ return PyArray_Return(PyArray_SimpleNewFromData(0, NULL, %(dtype)s, (char*)value));
+}
+''' % (locals())
+
+def pyobj_from_f2py_type(ctype):
+ ctype_bits = int(ctype[10:])
+ raise NotImplementedError,`ctype`
+ return '''\
+static PyObject* pyobj_from_%(ctype)s(%(ctype)s* value) {
+ fprintf(stderr,"In pyobj_from_%(ctype)s (%%p)\\n", value);
+}
+'''
+
+def pyobj_to_npy_int(ctype):
+ ctype_bits = int(ctype[7:])
+ return '''
+/* depends: pyobj_to_long.c, pyobj_to_npy_longlong.c */
+#if NPY_BITSOF_LONG == %(ctype_bits)s
+#define pyobj_to_%(ctype)s pyobj_to_long
+#else
+#if NPY_BITSOF_LONG > %(ctype_bits)s
+static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) {
+ long tmp;
+ if (pyobj_to_long(obj,&tmp)) {
+ *value = (%(ctype)s)tmp;
+ return 1;
+ }
+ return 0;
+}
+#else
+static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) {
+ npy_longlong tmp;
+ if (pyobj_to_npy_longlong(obj,&tmp)) {
+ *value = (%(ctype)s)tmp;
+ return 1;
+ }
+ return 0;
+}
+#endif
+#endif
+''' % (locals())
+
+def pyobj_to_npy_float(ctype):
+ ctype_bits = int(ctype[9:])
+ return '''
+/* depends: pyobj_to_double.c */
+#if NPY_BITSOF_DOUBLE == %(ctype_bits)s
+#define pyobj_to_%(ctype)s pyobj_to_double
+#else
+#if NPY_BITSOF_DOUBLE > %(ctype_bits)s
+static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) {
+ double tmp;
+ if (pyobj_to_double(obj,&tmp)) {
+ *value = (%(ctype)s)tmp;
+ return 1;
+ }
+ return 0;
+}
+#else
+#error, "NOTIMPLEMENTED pyobj_to_%(ctype)s"
+#endif
+#endif
+''' % (locals())
+
+def pyobj_to_npy_complex(ctype):
+ ctype_bits = int(ctype[11:])
+ cfloat_bits = ctype_bits/2
+ return '''
+/* depends: pyobj_to_Py_complex.c */
+#if NPY_BITSOF_DOUBLE >= %(cfloat_bits)s
+static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) {
+ Py_complex c;
+ if (pyobj_to_Py_complex(obj,&c)) {
+ (*value).real = (npy_float%(cfloat_bits)s)c.real;
+ (*value).imag = (npy_float%(cfloat_bits)s)c.imag;
+ return 1;
+ }
+ return 0;
+}
+#else
+#error, "NOTIMPLEMENTED pyobj_to_%(ctype)s"
+#endif
+''' % (locals())
+
+def pyobj_to_npy_scalar(ctype):
+ if ctype.startswith('npy_int'):
+ return dict(c_code=pyobj_to_npy_int(ctype))
+ elif ctype.startswith('npy_float'):
+ return dict(c_code=pyobj_to_npy_float(ctype))
+ elif ctype.startswith('npy_complex'):
+ return dict(c_code=pyobj_to_npy_complex(ctype))
+ raise NotImplementedError,`ctype`
+
+def pyobj_to_f2py_string(ctype):
+ ctype_bits = int(ctype[11:])
+ ctype_bytes = ctype_bits / CHAR_BIT
+ return dict(
+ c_code = '''
+/* depends: pyobj_to_string_len.c */
+static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) {
+ return pyobj_to_string_len(obj, (f2py_string*)value, %(ctype_bytes)s);
+}
+''' % (locals()),
+ typedef = ['typedef char * f2py_string;',
+ 'typedef struct { char data[%(ctype_bytes)s]; } %(ctype); ' % (locals())],
+ header = ['#include <string.h>'],
+ )
+
+def pyobj_from_npy_scalar(ctype):
+ if ctype.startswith('npy_int'):
+ return dict(c_code=pyobj_from_npy_int(ctype))
+ raise NotImplementedError,`ctype`
+
Modified: trunk/numpy/f2py/lib/python_wrapper.py
===================================================================
--- trunk/numpy/f2py/lib/python_wrapper.py 2006-09-29 18:02:25 UTC (rev 3235)
+++ trunk/numpy/f2py/lib/python_wrapper.py 2006-09-30 21:02:52 UTC (rev 3236)
@@ -9,87 +9,8 @@
#from typedecl_statements import intrinsic_type_spec, Character
from utils import CHAR_BIT
-class WrapperBase:
+from wrapper_base import *
-
- def __init__(self):
- self.srcdir = os.path.join(os.path.dirname(__file__),'src')
- return
- def warning(self, message):
- print >> sys.stderr, message
- def info(self, message):
- print >> sys.stderr, message
-
- def get_resource_content(self, name, ext):
- if name.startswith('pyobj_to_'):
- body = self.generate_pyobj_to_ctype_c(name[9:])
- if body is not None: return body
- generator_mth_name = 'generate_' + name + ext.replace('.','_')
- generator_mth = getattr(self, generator_mth_name, lambda : None)
- body = generator_mth()
- if body is not None:
- return body
- fn = os.path.join(self.srcdir,name+ext)
- if os.path.isfile(fn):
- f = open(fn,'r')
- body = f.read()
- f.close()
- return body
- self.warning('No such file: %r' % (fn))
- return
-
- def get_dependencies(self, code):
- l = []
- for uses in re.findall(r'(?<=depends:)([,\w\s.]+)', code, re.I):
- for use in uses.split(','):
- use = use.strip()
- if not use: continue
- l.append(use)
- return l
-
- def apply_attributes(self, template):
- """
- Apply instance attributes to template string.
-
- Replace rules for attributes:
- _list - will be joined with newline
- _clist - _list will be joined with comma
- _elist - _list will be joined
- ..+.. - attributes will be added
- [..] - will be evaluated
- """
- replace_names = set(re.findall(r'[ ]*%\(.*?\)s', template))
- d = {}
- for name in replace_names:
- tab = ' ' * (len(name)-len(name.lstrip()))
- name = name.lstrip()[2:-2]
- names = name.split('+')
- joinsymbol = '\n'
- attrs = None
- for n in names:
- realname = n.strip()
- if n.endswith('_clist'):
- joinsymbol = ', '
- realname = realname[:-6] + '_list'
- elif n.endswith('_elist'):
- joinsymbol = ''
- realname = realname[:-6] + '_list'
- if hasattr(self, realname):
- attr = getattr(self, realname)
- elif realname.startswith('['):
- attr = eval(realname)
- else:
- self.warning('Undefined %r attribute: %r' % (self.__class__.__name__, realname))
- continue
- if attrs is None:
- attrs = attr
- else:
- attrs += attr
- if isinstance(attrs, list):
- attrs = joinsymbol.join(attrs)
- d[name] = str(attrs).replace('\n','\n'+tab)
- return template % d
-
class PythonWrapperModule(WrapperBase):
main_template = '''\
@@ -101,21 +22,29 @@
#define PY_ARRAY_UNIQUE_SYMBOL PyArray_API
#include "numpy/arrayobject.h"
-%(include_list)s
-%(cppmacro_list)s
+%(header_list)s
+
%(typedef_list)s
+
+%(extern_list)s
+
+%(c_code_list)s
+
+%(capi_code_list)s
+
%(objdecl_list)s
-%(extern_list)s
-%(c_function_list)s
-%(capi_function_list)s
+
static PyObject *f2py_module;
+
static PyMethodDef f2py_module_methods[] = {
%(module_method_list)s
{NULL,NULL,0,NULL}
};
+
PyMODINIT_FUNC init%(modulename)s(void) {
f2py_module = Py_InitModule("%(modulename)s", f2py_module_methods);
- %(initialize_interface_list)s
+ import_array();
+ %(module_init_list)s
if (PyErr_Occurred()) {
PyErr_SetString(PyExc_ImportError, "can\'t initialize module %(modulename)s");
return;
@@ -133,31 +62,49 @@
def __init__(self, modulename):
WrapperBase.__init__(self)
self.modulename = modulename
- self.include_list = []
+ #self.include_list = []
+ #self.cppmacro_list = []
+
+ self.header_list = []
self.typedef_list = []
- self.cppmacro_list = []
+ self.extern_list = []
self.objdecl_list = []
- self.c_function_list = []
- self.extern_list = []
- self.capi_function_list = []
+ self.c_code_list = []
+ self.capi_code_list = []
+
self.module_method_list = []
- self.initialize_interface_list = []
+ self.module_init_list = []
+
self.fortran_code_list = []
- self.defined_types = []
- self.defined_macros = []
- self.defined_c_functions = []
- self.defined_typedefs = []
+ #self.defined_types = []
+ #self.defined_macros = []
+ #self.defined_c_functions = []
+ #self.defined_typedefs = []
+
+ self.list_names = ['header', 'typedef', 'extern', 'objdecl',
+ 'c_code','capi_code','module_method','module_init',
+ 'fortran_code']
+
return
def add(self, block):
if isinstance(block, BeginSource):
- for name, subblock in block.a.external_subprogram.items():
- self.add(subblock)
+ for name, moduleblock in block.a.module.items():
+ self.add(moduleblock)
+ #for name, subblock in block.a.external_subprogram.items():
+ # self.add(subblock)
elif isinstance(block, (Subroutine, Function)):
self.info('Generating interface for %s' % (block.name))
f = PythonCAPIFunction(self, block)
- f.fill()
+ f.fill()
+ elif isinstance(block, Module):
+ for name,declblock in block.a.type_decls.items():
+ self.add(declblock)
+ elif isinstance(block, TypeDecl):
+ PythonCAPIDerivedType(self, block)
+ elif isinstance(block, tuple(declaration_type_spec)):
+ PythonCAPIIntrinsicType(self, block)
else:
raise NotImplementedError,`block.__class__.__name__`
return
@@ -167,155 +114,306 @@
def fortran_code(self):
return self.apply_attributes(self.main_fortran_template)
- def add_c_function(self, name):
- if name not in self.defined_c_functions:
- body = self.get_resource_content(name,'.c')
- if body is None:
- self.warning('Failed to get C function %r content.' % (name))
- return
- for d in self.get_dependencies(body):
- if d.endswith('.cpp'):
- self.add_cppmacro(d[:-4])
- elif d.endswith('.c'):
- self.add_c_function(d[:-2])
- else:
- self.warning('Unknown dependence: %r.' % (d))
- self.defined_c_functions.append(name)
- self.c_function_list.append(body)
+ def add_subroutine(self, block):
+ raise
+ f = PythonCAPIFunction(self, block)
+ f.fill()
return
- def add_cppmacro(self, name):
- if name not in self.defined_macros:
- body = self.get_resource_content(name,'.cpp')
- if body is None:
- self.warning('Failed to get CPP macro %r content.' % (name))
- return
- for d in self.get_dependencies(body):
- if d.endswith('.cpp'):
- self.add_cppmacro(d[:-4])
- elif d.endswith('.c'):
- self.add_c_function(d[:-2])
- else:
- self.warning('Unknown dependence: %r.' % (d))
- self.defined_macros.append(name)
- self.cppmacro_list.append(body)
- return
- def add_type(self, typedecl):
- typewrap = TypeDecl(self, typedecl)
- typename = typewrap.typename
- if typename not in self.defined_types:
- self.defined_types.append(typename)
- typewrap.fill()
- return typename
- def add_typedef(self, name, code):
- if name not in self.defined_typedefs:
- self.typedef_list.append(code)
- self.defined_types.append(name)
- return
+
+class PythonCAPIIntrinsicType(WrapperBase):
+ """
+ Fortran intrinsic type hooks.
+ """
+ _defined_types = []
+ def __init__(self, parent, typedecl):
+ WrapperBase.__init__(self)
+ self.name = name = typedecl.name
+ if name in self._defined_types:
+ return
+ self._defined_types.append(name)
- def add_include(self, include):
- if include not in self.include_list:
- self.include_list.append(include)
- return
+ self.ctype = ctype = typedecl.get_c_type()
- def add_subroutine(self, block):
- f = PythonCAPIFunction(self, block)
- f.fill()
+ if ctype.startswith('npy_'):
+ from generate_pyobj_tofrom_funcs import pyobj_to_npy_scalar
+ d = pyobj_to_npy_scalar(ctype)
+ for v in d.values():
+ self.resolve_dependencies(parent, v)
+ for k,v in d.items():
+ l = getattr(parent, k+'_list')
+ l.append(v)
+ return
+
+ if not ctype.startswith('f2py_type_'):
+ raise NotImplementedError,`name,ctype`
+
+ for n in parent.list_names:
+ l = getattr(parent,n + '_list')
+ l.append(self.apply_attributes(getattr(self, n+'_template','')))
+
return
- def generate_pyobj_to_ctype_c(self, ctype):
- if ctype.startswith('npy_int'):
- ctype_bits = int(ctype[7:])
- return '''
-/* depends: pyobj_to_long.c, pyobj_to_npy_longlong.c */
-#if NPY_BITSOF_LONG == %(ctype_bits)s
-#define pyobj_to_%(ctype)s pyobj_to_long
-#else
-#if NPY_BITSOF_LONG > %(ctype_bits)s
-static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) {
- long tmp;
- if (pyobj_to_long(obj,&tmp)) {
- *value = (%(ctype)s)tmp;
- return 1;
- }
- return 0;
+class PythonCAPIDerivedType(WrapperBase):
+ """
+ Fortran 90 derived type hooks.
+ """
+
+ header_template = '''\
+#define %(oname)sObject_Check(obj) \\
+ PyObject_TypeCheck((PyObject*)obj, &%(oname)sType)
+#define %(init_func)s_f \\
+ F_FUNC(%(init_func)s,%(INIT_FUNC)s)
+'''
+
+ typedef_template = '''\
+typedef void * %(ctype)s;
+typedef struct {
+ PyObject_HEAD
+ %(ptrstruct_list)s
+ %(ctype)s data;
+} %(oname)sObject;
+'''
+
+ extern_template = '''\
+static PyTypeObject %(oname)sType;
+'''
+
+ objdecl_template = '''\
+static PyMethodDef %(oname)s_methods[] = {
+ %(type_method_list)s
+ {NULL} /* Sentinel */
+};
+
+static PyGetSetDef %(oname)s_getseters[] = {
+ %(type_getseters_list)s
+ {NULL} /* Sentinel */
+};
+
+static PyTypeObject %(oname)sType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "%(name)s", /*tp_name*/
+ sizeof(%(oname)sObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)%(oname)s_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ %(oname)s_repr, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ "Fortran derived type %(name)s objects", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ %(oname)s_methods, /* tp_methods */
+ 0 /*%(oname)s_members*/, /* tp_members */
+ %(oname)s_getseters, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)%(oname)s_init, /* tp_init */
+ 0, /* tp_alloc */
+ %(oname)s_new, /* tp_new */
+};
+'''
+
+ module_init_template = '''\
+if (PyType_Ready(&%(oname)sType) < 0)
+ return;
+PyModule_AddObject(f2py_module, "%(name)s",
+ (PyObject *)&%(oname)sType);
+'''
+
+ c_code_template = '''\
+static void %(init_func)s_c(
+ %(init_func_c_arg_clist)s) {
+ %(init_func_c_body_list)s
}
-#else
-static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) {
- npy_longlong tmp;
- if (pyobj_to_npy_longlong(obj,&tmp)) {
- *value = (%(ctype)s)tmp;
- return 1;
- }
- return 0;
+'''
+
+ capi_code_template = '''\
+static void %(oname)s_dealloc(%(oname)sObject* self) {
+ PyMem_Free(self->data);
+ self->ob_type->tp_free((PyObject*)self);
}
-#endif
-#endif
-''' % (locals())
- elif ctype.startswith('npy_float'):
- ctype_bits = int(ctype[9:])
- return '''
-/* depends: pyobj_to_double.c */
-#if NPY_BITSOF_DOUBLE == %(ctype_bits)s
-#define pyobj_to_%(ctype)s pyobj_to_double
-#else
-#if NPY_BITSOF_DOUBLE > %(ctype_bits)s
-static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) {
- double tmp;
- if (pyobj_to_double(obj,&tmp)) {
- *value = (%(ctype)s)tmp;
+
+static int pyobj_to_%(ctype)s(PyObject *obj,
+ %(ctype)s* value_ptr) {
+ if (%(oname)sObject_Check(obj)) {
+ if (!memcpy(value_ptr,((%(oname)sObject *)obj)->data, %(byte_size)s)) {
+ PyErr_SetString(PyExc_MemoryError,
+ "failed to copy %(name)s instance memory to %(ctype)s object.");
+ }
return 1;
}
return 0;
}
-#else
-#error, "NOTIMPLEMENTED pyobj_to_%(ctype)s"
-#endif
-#endif
-''' % (locals())
- elif ctype.startswith('npy_complex'):
- ctype_bits = int(ctype[11:])
- cfloat_bits = ctype_bits/2
- return '''
-/* depends: pyobj_to_Py_complex.c */
-#if NPY_BITSOF_DOUBLE >= %(cfloat_bits)s
-static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) {
- Py_complex c;
- if (pyobj_to_Py_complex(obj,&c)) {
- (*value).real = (npy_float%(cfloat_bits)s)c.real;
- (*value).imag = (npy_float%(cfloat_bits)s)c.imag;
- return 1;
+
+static PyObject* pyobj_from_%(ctype)s(%(ctype)s* value_ptr) {
+ %(oname)sObject* obj = (%(oname)sObject*)(%(oname)sType.tp_alloc(&%(oname)sType, 0));
+ if (obj == NULL)
+ return NULL;
+ obj->data = PyMem_Malloc(%(byte_size)s);
+ if (obj->data == NULL) {
+ Py_DECREF(obj);
+ return PyErr_NoMemory();
}
- return 0;
+ if (value_ptr) {
+ if (!memcpy(obj->data, value_ptr, %(byte_size)s)) {
+ PyErr_SetString(PyExc_MemoryError,
+ "failed to copy %(ctype)s object memory to %(name)s instance.");
+ }
+ }
+ %(init_func)s_f(%(init_func)s_c, obj, obj->data);
+ return (PyObject*)obj;
}
-#else
-#error, "NOTIMPLEMENTED pyobj_to_%(ctype)s"
-#endif
-''' % (locals())
- elif ctype.startswith('f2py_string'):
- ctype_bits = int(ctype[11:])
- ctype_bytes = ctype_bits / CHAR_BIT
- self.add_typedef('f2py_string','typedef char * f2py_string;')
- self.add_typedef(ctype,'typedef struct { char data[%s]; } %s;' % (ctype_bytes,ctype))
- self.add_include('#include <string.h>')
- return '''
-/* depends: pyobj_to_string_len.c */
-static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) {
- return pyobj_to_string_len(obj, (f2py_string*)value, %(ctype_bytes)s);
+
+static PyObject * %(oname)s_new(PyTypeObject *type,
+ PyObject *args, PyObject *kwds)
+{
+ return pyobj_from_%(ctype)s(NULL);
}
-''' % (locals())
- elif ctype.startswith('f2py_type_'):
- ctype_bits = int(ctype.split('_')[-1])
- ctype_bytes = ctype_bits / CHAR_BIT
- self.add_typedef(ctype,'typedef struct { char data[%s]; } %s;' % (ctype_bytes,ctype))
- return '''
-static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) {
- return pyobj_to_string_len(obj, (f2py_string*)value, %(ctype_bytes)s);
+
+static int %(oname)s_init(%(oname)sObject *self,
+ PyObject *capi_args, PyObject *capi_kwds)
+{
+ return !PyArg_ParseTuple(capi_args,"%(attr_format_elist)s"
+ %(attr_init_clist)s);
}
-''' % (locals())
-
+
+static PyObject * %(oname)s_as_tuple(%(oname)sObject * self) {
+ return Py_BuildValue("%(as_tuple_format_elist)s"
+ %(as_tuple_arg_clist)s);
+}
+
+static PyObject * %(oname)s_repr(PyObject * self) {
+ PyObject* r = PyString_FromString("%(name)s(");
+ PyString_ConcatAndDel(&r, PyObject_Repr(%(oname)s_as_tuple((%(oname)sObject*)self)));
+ PyString_ConcatAndDel(&r, PyString_FromString(")"));
+ return r;
+}
+
+%(getset_func_list)s
+'''
+
+ fortran_code_template = '''\
+ subroutine %(init_func)s(init_func_c, self, obj)
+ %(use_stmt_list)s
+ external init_func_c
+! self is %(oname)sObject
+ external self
+ %(ftype)s obj
+ call init_func_c(%(init_func_f_arg_clist)s)
+ end
+'''
+
+ #module_method_template = ''''''
+
+ _defined_types = []
+ def __init__(self, parent, typedecl):
+ WrapperBase.__init__(self)
+ name = typedecl.name
+ if name in self._defined_types:
+ return
+ self._defined_types.append(name)
+
+ self.name = name
+ self.oname = oname = 'f2py_' + name
+ self.ctype = typedecl.get_c_type()
+ self.ctype_ptrs = self.ctype + '_ptrs'
+ self.ftype = typedecl.get_f_type()
+ self.byte_size = byte_size = typedecl.get_bit_size() / CHAR_BIT
+ WrapperCPPMacro(parent, 'F_FUNC')
+
+ self.init_func_f_arg_list = ['self']
+ self.init_func_c_arg_list = ['%sObject *self' % (self.oname)]
+ self.init_func_c_body_list = []
+ self.ptrstruct_list = []
+ self.attr_decl_list = []
+ self.attr_format_list = []
+ self.attr_init_list = []
+ self.as_tuple_format_list = []
+ self.as_tuple_arg_list = []
+ self.getset_func_list = []
+ self.type_getseters_list = []
+ for n in typedecl.a.component_names:
+ v = typedecl.a.components[n]
+ t = v.get_typedecl()
+ ct = t.get_c_type()
+ on = 'f2py_' + t.name
+ parent.add(t)
+ self.ptrstruct_list.append('%s* %s_ptr;' % (ct, n))
+ self.init_func_f_arg_list.append('obj %% %s' % (n))
+ self.init_func_c_arg_list.append('\n%s * %s_ptr' % (ct, n))
+ self.init_func_c_body_list.append('''\
+if (!((void*)%(n)s_ptr >= self->data
+ && (void*)%(n)s_ptr < self->data + %(byte_size)s ))
+ fprintf(stderr,"INCONSISTENCY IN %(name)s WRAPPER: "
+ "self->data=%%p <= %(n)s_ptr=%%p < self->data+%(byte_size)s=%%p\\n",
+ self->data, %(n)s_ptr, self->data + %(byte_size)s);
+self->%(n)s_ptr = %(n)s_ptr;
+''' % (locals()))
+ self.attr_format_list.append('O&')
+ WrapperCCode(parent, 'pyobj_to_%s' % (ct))
+ self.attr_init_list.append('\npyobj_to_%s, self->%s_ptr' % (ct,n))
+ WrapperCCode(parent, 'pyobj_from_%s' % (ct))
+ self.as_tuple_format_list.append('O&')
+ self.as_tuple_arg_list.append('\npyobj_from_%s, self->%s_ptr' % (ct, n))
+ self.getset_func_list.append('''\
+static PyObject * %(oname)s_get_%(n)s(%(oname)sObject *self,
+ void *closure) {
+ return pyobj_from_%(ct)s(self->%(n)s_ptr);
+}
+static int %(oname)s_set_%(n)s(%(oname)sObject *self,
+ PyObject *value, void *closure)
+{
+ if (value == NULL) {
+ PyErr_SetString(PyExc_TypeError,
+ "Cannot delete %(name)s attribute %(n)s");
+ return -1;
+ }
+ if (pyobj_to_%(ct)s(value, self->%(n)s_ptr))
+ return 0;
+ return -1;
+}
+''' % (locals()))
+ self.type_getseters_list.append('{"%(n)s",(getter)%(oname)s_get_%(n)s, (setter)%(oname)s_set_%(n)s,\n "component %(n)s",NULL},' % (locals()))
+ if self.attr_init_list: self.attr_init_list.insert(0,'')
+ if self.as_tuple_arg_list: self.as_tuple_arg_list.insert(0,'')
+ self.init_func = self.ctype + '_init'
+ self.INIT_FUNC = self.init_func.upper()
+
+ self.type_method_list = []
+ self.type_method_list.append('{"as_tuple",(PyCFunction)%(oname)s_as_tuple,METH_NOARGS,\n "Return %(name)s components as tuple."},' % (self.__dict__))
+ self.cname = typedecl.get_c_name()
+
+ self.use_stmt_list = []
+ if isinstance(typedecl.parent, Module):
+ self.use_stmt_list.append('use %s' % (typedecl.parent.name))
+
+ for n in parent.list_names:
+ l = getattr(parent,n + '_list')
+ l.append(self.apply_attributes(getattr(self, n+'_template','')))
+ return
+
class PythonCAPIFunction(WrapperBase):
capi_function_template = '''
static char f2py_doc_%(function_name)s[] = "%(function_doc)s";
@@ -412,15 +510,15 @@
self.parent.pyarg_format_list.append('O&')
self.parent.keyword_list.append('"%s"' % (self.name))
- self.grand_parent.add_c_function('pyobj_to_%s' % (self.ctype))
return
-class TypeDecl(WrapperBase):
+
+class TypeDecl2(WrapperBase):
cppmacro_template = '''\
#define initialize_%(typename)s_interface F_FUNC(initialize_%(typename)s_interface_f,INITIALIZE_%(TYPENAME)s_INTERFACE_F)\
'''
typedef_template = '''\
-typedef struct { char data[%(byte_size)s] } %(ctype)s;
+typedef struct { char data[%(byte_size)s]; } %(ctype)s;
typedef %(ctype)s (*create_%(typename)s_functype)(void);
typedef void (*initialize_%(typename)s_interface_functype)(create_%(typename)s_functype);\
'''
@@ -449,6 +547,14 @@
call init_c(create_%(typename)s_object_f)
end
'''
+ pyobj_to_type_template = '''
+ static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) {
+ if (PyTuple_Check(obj)) {
+ return 0;
+ }
+ return 0;
+ }
+'''
def __init__(self, parent, typedecl):
WrapperBase.__init__(self)
@@ -464,12 +570,17 @@
def fill(self):
ctype =self.typedecl.get_c_type()
- if ctype.startswith('npy_'):
- pass
- elif ctype.startswith('f2py_string'):
- pass
- elif ctype.startswith('f2py_type'):
- pass
+ if ctype.startswith('npy_') or ctype.startswith('f2py_string'):
+ # wrappers are defined via pyobj_to_* functions
+ self.parent.add_c_function('pyobj_to_%s' % (self.ctype))
+ return
+ if ctype.startswith('f2py_type'):
+ return
+ self.parent.add_typedef(ctype,
+ self.apply_attributes('typedef struct { char data[%(byte_size)s]; } %(ctype)s;'))
+ self.parent.add_c_function(self.apply_attributes('pyobj_to_%(ctype)s'),
+ self.apply_attributes(self.pyobj_to_type_template)
+ )
else:
self.parent.typedef_list.append(self.apply_attributes(self.typedef_template))
self.parent.objdecl_list.append(self.apply_attributes(self.objdecl_template))
@@ -490,9 +601,13 @@
stmt = str2stmt("""
module rat
integer :: i
+ type info
+ integer flag
+ end type info
type rational
integer n
- integer*8 d
+ integer d
+ type(info) i
end type rational
end module rat
subroutine foo(a)
@@ -508,16 +623,20 @@
foo_code = """! -*- f90 -*-
module rat
+ type info
+ integer flag
+ end type info
type rational
- integer d,n
+ integer n,d
+ type(info) i
end type rational
end module rat
- subroutine foo(a,b,c)
+ subroutine foo(a,b)
use rat
integer a
- character*5 b
- type(rational) c
- print*,'a=',a,b,c
+ !character*5 b
+ type(rational) b
+ print*,'a=',a,b
end
"""
@@ -556,8 +675,31 @@
setup(configuration=configuration)
''')
f.close()
- print get_char_bit()
+ #print get_char_bit()
os.system('python foo_setup.py config_fc --fcompiler=gnu95 build build_ext --inplace')
import foo
- print dir(foo)
- foo.foo(2,"abcdefg")
+ #print foo.__doc__
+ #print dir(foo)
+ #print foo.info.__doc__
+ #print foo.rational.__doc__
+ #print dir(foo.rational)
+ i = foo.info(7)
+ #print i #,i.as_tuple()
+ #print 'i.flag=',i.flag
+ r = foo.rational(2,3,i)
+ print r
+ j = r.i
+ print 'r.i.flag=',(r.i).flag
+ print 'j.flag=',j.flag
+ #print 'r=',r
+ sys.exit()
+ n,d,ii = r.as_tuple()
+ n += 1
+ print n,d
+ print r
+ #foo.foo(2,r)
+ print r.n, r.d
+ r.n = 5
+ print r
+ r.n -= 1
+ print r
Modified: trunk/numpy/f2py/lib/src/pyobj_to_Py_complex.c
===================================================================
--- trunk/numpy/f2py/lib/src/pyobj_to_Py_complex.c 2006-09-29 18:02:25 UTC (rev 3235)
+++ trunk/numpy/f2py/lib/src/pyobj_to_Py_complex.c 2006-09-30 21:02:52 UTC (rev 3236)
@@ -33,7 +33,8 @@
}
}
if (!PyErr_Occurred()) {
- PyErr_SetString(PyExc_TypeError, "Failed to convert python object to C Py_complex.");
+ PyErr_SetString(PyExc_TypeError,
+ "Failed to convert python object to C Py_complex.");
}
return 0;
}
Modified: trunk/numpy/f2py/lib/src/pyobj_to_long.c
===================================================================
--- trunk/numpy/f2py/lib/src/pyobj_to_long.c 2006-09-29 18:02:25 UTC (rev 3235)
+++ trunk/numpy/f2py/lib/src/pyobj_to_long.c 2006-09-30 21:02:52 UTC (rev 3236)
@@ -25,7 +25,8 @@
Py_DECREF(tmp);
}
if (!PyErr_Occurred()) {
- PyErr_SetString(PyExc_TypeError, "Failed to convert python object to C long.");
+ PyErr_SetString(PyExc_TypeError,
+ "Failed to convert python object to C long.");
}
return 0;
}
Modified: trunk/numpy/f2py/lib/src/pyobj_to_npy_longlong.c
===================================================================
--- trunk/numpy/f2py/lib/src/pyobj_to_npy_longlong.c 2006-09-29 18:02:25 UTC (rev 3235)
+++ trunk/numpy/f2py/lib/src/pyobj_to_npy_longlong.c 2006-09-30 21:02:52 UTC (rev 3236)
@@ -29,7 +29,8 @@
Py_DECREF(tmp);
}
if (!PyErr_Occurred()) {
- PyErr_SetString(PyExc_TypeError, "Failed to convert python object to C npy_longlong.");
+ PyErr_SetString(PyExc_TypeError,
+ "Failed to convert python object to C npy_longlong.");
}
return 0;
}
Modified: trunk/numpy/f2py/lib/src/pyobj_to_string_len.c
===================================================================
--- trunk/numpy/f2py/lib/src/pyobj_to_string_len.c 2006-09-29 18:02:25 UTC (rev 3235)
+++ trunk/numpy/f2py/lib/src/pyobj_to_string_len.c 2006-09-30 21:02:52 UTC (rev 3236)
@@ -4,7 +4,8 @@
return 1;
}
if (!PyErr_Occurred()) {
- PyErr_SetString(PyExc_TypeError, "Failed to convert python object to C f2py_string.");
+ PyErr_SetString(PyExc_TypeError,
+ "Failed to convert python object to C f2py_string.");
}
return 0;
}
Modified: trunk/numpy/f2py/lib/typedecl_statements.py
===================================================================
--- trunk/numpy/f2py/lib/typedecl_statements.py 2006-09-29 18:02:25 UTC (rev 3235)
+++ trunk/numpy/f2py/lib/typedecl_statements.py 2006-09-30 21:02:52 UTC (rev 3236)
@@ -470,14 +470,10 @@
raise NotImplementedError,`self.__class__.__name__`
def get_bit_size(self):
- type_decl = self.get_type_decl(self.name)
- s = 0
- for name,var in type_decl.a.components.items():
- s += var.get_bit_size()
- return s
+ return self.get_type_decl(self.name).get_bit_size()
def get_c_type(self):
- return 'f2py_type_%s_%s' % (self.name, self.get_bit_size())
+ return self.get_type_decl(self.name).get_c_type()
TypeStmt = Type
Added: trunk/numpy/f2py/lib/wrapper_base.py
===================================================================
--- trunk/numpy/f2py/lib/wrapper_base.py 2006-09-29 18:02:25 UTC (rev 3235)
+++ trunk/numpy/f2py/lib/wrapper_base.py 2006-09-30 21:02:52 UTC (rev 3236)
@@ -0,0 +1,162 @@
+
+import os
+import sys
+import re
+__all__ = ['WrapperBase','WrapperCPPMacro','WrapperCCode']
+
+class WrapperBase:
+
+ def __init__(self):
+ self.srcdir = os.path.join(os.path.dirname(__file__),'src')
+ return
+ def warning(self, message):
+ print >> sys.stderr, message
+ def info(self, message):
+ print >> sys.stderr, message
+
+ def get_resource_content(self, name, ext):
+ if name.startswith('pyobj_to_'):
+ try:
+ return self.generate_pyobj_to_ctype_c(name[9:])
+ except NotImplementedError:
+ pass
+ elif name.startswith('pyobj_from_'):
+ try:
+ return self.generate_pyobj_from_ctype_c(name[11:])
+ except NotImplementedError:
+ pass
+ generator_mth_name = 'generate_' + name + ext.replace('.','_')
+ generator_mth = getattr(self, generator_mth_name, lambda : None)
+ body = generator_mth()
+ if body is not None:
+ return body
+ fn = os.path.join(self.srcdir,name+ext)
+ if os.path.isfile(fn):
+ f = open(fn,'r')
+ body = f.read()
+ f.close()
+ return body
+ self.warning('No such file: %r' % (fn))
+ return
+
+ def get_dependencies(self, code):
+ l = []
+ for uses in re.findall(r'(?<=depends:)([,\w\s.]+)', code, re.I):
+ for use in uses.split(','):
+ use = use.strip()
+ if not use: continue
+ l.append(use)
+ return l
+
+ def resolve_dependencies(self, parent, body):
+ assert isinstance(body, str),type(body)
+ for d in self.get_dependencies(body):
+ if d.endswith('.cpp'):
+ WrapperCPPMacro(parent, d[:-4])
+ elif d.endswith('.c'):
+ WrapperCCode(parent, d[:-2])
+ else:
+ self.warning('Unknown dependence: %r.' % (d))
+ return
+
+ def apply_attributes(self, template):
+ """
+ Apply instance attributes to template string.
+
+ Replace rules for attributes:
+ _list - will be joined with newline
+ _clist - _list will be joined with comma
+ _elist - _list will be joined
+ ..+.. - attributes will be added
+ [..] - will be evaluated
+ """
+ replace_names = set(re.findall(r'[ ]*%\(.*?\)s', template))
+ d = {}
+ for name in replace_names:
+ tab = ' ' * (len(name)-len(name.lstrip()))
+ name = name.lstrip()[2:-2]
+ names = name.split('+')
+ joinsymbol = '\n'
+ attrs = None
+ for n in names:
+ realname = n.strip()
+ if n.endswith('_clist'):
+ joinsymbol = ', '
+ realname = realname[:-6] + '_list'
+ elif n.endswith('_elist'):
+ joinsymbol = ''
+ realname = realname[:-6] + '_list'
+ if hasattr(self, realname):
+ attr = getattr(self, realname)
+ elif realname.startswith('['):
+ attr = eval(realname)
+ else:
+ self.warning('Undefined %r attribute: %r' % (self.__class__.__name__, realname))
+ continue
+ if attrs is None:
+ attrs = attr
+ else:
+ attrs += attr
+ if isinstance(attrs, list):
+ attrs = joinsymbol.join(attrs)
+ d[name] = str(attrs).replace('\n','\n'+tab)
+ return template % d
+
+class WrapperCPPMacro(WrapperBase):
+ """
+ CPP macros
+ """
+ _defined_macros = []
+ def __init__(self, parent, name):
+ WrapperBase.__init__(self)
+ if name in self._defined_macros:
+ return
+ self._defined_macros.append(name)
+
+ body = self.get_resource_content(name,'.cpp')
+ if body is None:
+ self.warning('Failed to get CPP macro %r content.' % (name))
+ return
+ self.resolve_dependencies(parent, body)
+ parent.header_list.append(body)
+ return
+
+class WrapperCCode(WrapperBase):
+ """
+ C code
+ """
+ _defined_codes = []
+ def __init__(self, parent, name):
+ WrapperBase.__init__(self)
+ if name in self._defined_codes:
+ return
+ self._defined_codes.append(name)
+
+ body = self.get_resource_content(name,'.c')
+ if body is None:
+ self.warning('Failed to get C code %r content.' % (name))
+ return
+ if isinstance(body, dict):
+ for k,v in body.items():
+ self.resolve_dependencies(parent, v)
+ for k,v in body.items():
+ l = getattr(parent,k+'_list')
+ l.append(v)
+ else:
+ self.resolve_dependencies(parent, body)
+ parent.c_code_list.append(body)
+ return
+
+ def generate_pyobj_to_ctype_c(self, ctype):
+ from generate_pyobj_tofrom_funcs import pyobj_to_npy_scalar, pyobj_to_f2py_string
+ if ctype.startswith('npy_'):
+ return pyobj_to_npy_scalar(ctype)
+ elif ctype.startswith('f2py_string'):
+ return pyobj_to_f2py_string(ctype)
+ raise NotImplementedError,`ctype`
+
+ def generate_pyobj_from_ctype_c(self, ctype):
+ from generate_pyobj_tofrom_funcs import pyobj_from_npy_scalar
+ if ctype.startswith('npy_'):
+ return pyobj_from_npy_scalar(ctype)
+ raise NotImplementedError,`ctype`
More information about the Numpy-svn
mailing list