diff options
author | Pearu Peterson <pearu.peterson@gmail.com> | 2006-10-02 20:21:11 +0000 |
---|---|---|
committer | Pearu Peterson <pearu.peterson@gmail.com> | 2006-10-02 20:21:11 +0000 |
commit | 022b06b4d628d991c8a8a294db92c0d4f93f4c90 (patch) | |
tree | 3f869cec4f43e988dc634aa199a2f3eb7a218d27 /numpy/f2py | |
parent | 58c43785202a4fb52c79b8658afa0682ef59c54a (diff) | |
download | numpy-022b06b4d628d991c8a8a294db92c0d4f93f4c90.tar.gz |
F2PY G3: exposing G3 to f2py script, fixed bugs, wrote source docs.
Diffstat (limited to 'numpy/f2py')
-rwxr-xr-x | numpy/f2py/f2py2e.py | 6 | ||||
-rw-r--r-- | numpy/f2py/lib/__init__.py | 14 | ||||
-rw-r--r-- | numpy/f2py/lib/api.py | 14 | ||||
-rw-r--r-- | numpy/f2py/lib/generate_pyobj_tofrom_funcs.py | 13 | ||||
-rw-r--r-- | numpy/f2py/lib/main.py | 143 | ||||
-rw-r--r-- | numpy/f2py/lib/parser/api.py | 5 | ||||
-rw-r--r-- | numpy/f2py/lib/parser/base_classes.py | 2 | ||||
-rw-r--r-- | numpy/f2py/lib/parser/block_statements.py | 43 | ||||
-rw-r--r-- | numpy/f2py/lib/parser/statements.py | 3 | ||||
-rw-r--r-- | numpy/f2py/lib/python_wrapper.py | 35 | ||||
-rw-r--r-- | numpy/f2py/lib/setup.py | 12 | ||||
-rw-r--r-- | numpy/f2py/lib/src/pyobj_to_Py_complex.c | 28 | ||||
-rwxr-xr-x | numpy/f2py/setup.py | 28 |
13 files changed, 306 insertions, 40 deletions
diff --git a/numpy/f2py/f2py2e.py b/numpy/f2py/f2py2e.py index 85102e281..54514dca8 100755 --- a/numpy/f2py/f2py2e.py +++ b/numpy/f2py/f2py2e.py @@ -64,6 +64,12 @@ Description: This program generates a Python C/API file (<modulename>module.c) Options: + --3g-numpy Use numpy.f2py.lib tool, the 3rd generation of F2PY, + with NumPy support. + --2d-numpy Use numpy.f2py tool with NumPy support. [DEFAULT] + --2d-numeric Use f2py2e tool with Numeric support. + --2d-numarray Use f2py2e tool with Numarray support. + -h <filename> Write signatures of the fortran routines to file <filename> and exit. You can then edit <filename> and use it instead of <fortran files>. If <filename>==stdout then the diff --git a/numpy/f2py/lib/__init__.py b/numpy/f2py/lib/__init__.py index e69de29bb..c3b40cb76 100644 --- a/numpy/f2py/lib/__init__.py +++ b/numpy/f2py/lib/__init__.py @@ -0,0 +1,14 @@ +""" +F2PY G3 --- The third generation of Fortran to Python Interface Generator. + +Use api module for importing public symbols. + +----- +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. See http://scipy.org. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +Author: Pearu Peterson <pearu@cens.ioc.ee> +Created: Oct 2006 +----- +""" diff --git a/numpy/f2py/lib/api.py b/numpy/f2py/lib/api.py new file mode 100644 index 000000000..0d21da28c --- /dev/null +++ b/numpy/f2py/lib/api.py @@ -0,0 +1,14 @@ +""" +Public API for F2PY G3. + +----- +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. See http://scipy.org. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +Author: Pearu Peterson <pearu@cens.ioc.ee> +Created: Oct 2006 +----- +""" + +from main import main diff --git a/numpy/f2py/lib/generate_pyobj_tofrom_funcs.py b/numpy/f2py/lib/generate_pyobj_tofrom_funcs.py index 188c35d34..f9dedb276 100644 --- a/numpy/f2py/lib/generate_pyobj_tofrom_funcs.py +++ b/numpy/f2py/lib/generate_pyobj_tofrom_funcs.py @@ -114,13 +114,20 @@ def pyobj_to_npy_complex(ctype): /* depends: pyobj_to_Py_complex.c */ #if NPY_BITSOF_DOUBLE >= %(cfloat_bits)s static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) { + int return_value = 0; Py_complex c; +#if defined(F2PY_DEBUG_PYOBJ_TOFROM) + fprintf(stderr,"pyobj_to_%(ctype)s(type=%%s)\\n",PyString_AS_STRING(PyObject_Repr(PyObject_Type(obj)))); +#endif 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; + (*value).imag = (npy_float%(cfloat_bits)s)c.imag; + return_value = 1; } - return 0; +#if defined(F2PY_DEBUG_PYOBJ_TOFROM) + fprintf(stderr,"pyobj_to_%(ctype)s: return_value=%%d, PyErr_Occurred()=%%p\\n", return_value, PyErr_Occurred()); +#endif + return return_value; } #else #error, "NOTIMPLEMENTED pyobj_to_%(ctype)s" diff --git a/numpy/f2py/lib/main.py b/numpy/f2py/lib/main.py new file mode 100644 index 000000000..64b9447f5 --- /dev/null +++ b/numpy/f2py/lib/main.py @@ -0,0 +1,143 @@ +""" +Tools for building F2PY generated extension modules. + +----- +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. See http://scipy.org. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +Author: Pearu Peterson <pearu@cens.ioc.ee> +Created: Oct 2006 +----- +""" + +import os +import sys + +try: + from numpy import __version__ as numpy_version +except ImportError: + numpy_version = 'N/A' + +__all__ = ['main'] + +__usage__ = """ +F2PY G3 --- The third generation of Fortran to Python Interface Generator +========================================================================= + +Description +----------- + +f2py program generates a Python C/API file (<modulename>module.c) that +contains wrappers for given Fortran functions and data so that they +can be accessed from Python. With the -c option the corresponding +extension modules are built. + +Options +------- + + --3g-numpy Use numpy.f2py.lib tool, the 3rd generation of F2PY, + with NumPy support. + --2d-numpy Use numpy.f2py tool with NumPy support. [DEFAULT] + --2d-numeric Use f2py2e tool with Numeric support. + --2d-numarray Use f2py2e tool with Numarray support. + +""" + +from parser.api import parse, PythonModule, EndStatement + +def dump_signature(): + """ Read Fortran files and dump the signatures to file or stdout. + """ + # get signature output + i = sys.argv.index('-h') + if len(sys.argv)-1==i: + signature_output = 'stdout' + else: + signature_output = sys.argv[i+1] + del sys.argv[i+1] + del sys.argv[i] + + # get module name + try: + i = sys.argv.index('-m') + except ValueError: + i = None + module_name = 'unknown' + if i is not None: + if len(sys.argv)-1==i: + module_name = 'unspecified' + else: + module_name = sys.argv[i+1] + del sys.argv[i+1] + del sys.argv[i] + + # initialize output stream + if signature_output in ['stdout','stderr']: + output_stream = getattr(sys, signature_output) + else: + if os.path.isfile(signature_output): + try: + i = sys.argv.index('--overwrite-signature') + del sys.argv[i] + except ValueError: + print >> sys.stderr, 'Signature file %r exists. Use --overwrite-signature to overwrite.' % (signature_output) + sys.exit() + output_stream = open(signature_output,'w') + + flag = 'file' + file_names = [] + only_names = [] + skip_names = [] + options = [] + for word in sys.argv[1:]: + if word=='': pass + elif word=='only:': flag = 'only' + elif word=='skip:': flag = 'skip' + elif word==':': flag = 'file' + elif word.startswith('--'): options.append(word) + else: + {'file': file_names,'only': only_names, 'skip': skip_names}[flag].append(word) + + output_stream.write('''! -*- f90 -*- +! Note: the context of this file is case sensitive. +''') + output_stream.write('PYTHON MODULE %s\n' % (module_name)) + output_stream.write(' INTERFACE\n\n') + for filename in file_names: + block = parse(filename) + output_stream.write('! File: %s, source mode = %s\n' % (filename, block.reader.mode)) + if isinstance(block.content[0],PythonModule): + for subblock in block.content[0].content[0].content: + if isinstance(subblock, EndStatement): + break + output_stream.write(subblock.topyf(' ')+'\n') + else: + output_stream.write(block.topyf(' ')+'\n') + output_stream.write(' END INTERFACE\n') + output_stream.write('END PYTHON MODULE %s\n' % (module_name)) + + if signature_output not in ['stdout','stderr']: + output_stream.close() + return + +def build_extension(): + raise NotImplementedError,'build_extension' + +def main(): + """ Main function of f2py script. + """ + if '--help-link' in sys.argv[1:]: + sys.argv.remove('--help-link') + from numpy.distutils.system_info import show_all + show_all() + return + if '-c' in sys.argv[1:]: + i = sys.argv.index('-c') + del sys.argv[i] + build_extension() + return + if '-h' in sys.argv[1:]: + dump_signature() + return + print >> sys.stdout, __usage__ diff --git a/numpy/f2py/lib/parser/api.py b/numpy/f2py/lib/parser/api.py index efcfcbf28..0a7346095 100644 --- a/numpy/f2py/lib/parser/api.py +++ b/numpy/f2py/lib/parser/api.py @@ -12,6 +12,7 @@ Created: Oct 2006 """ # import all Statement classes: +from base_classes import EndStatement from block_statements import * # CHAR_BIT is used to convert object bit sizes to byte sizes @@ -34,8 +35,8 @@ def parse(input, isfree=None, isstrict=None, include_dirs = None): if os.path.isfile(input): reader = FortranFileReader(input, include_dirs = include_dirs) - if isfree is None: reader.isfree - if isstrict is None: reader.isstrict + if isfree is None: isfree = reader.isfree + if isstrict is None: isstrict = reader.isstrict reader.set_mode(isfree, isstrict) elif isinstance(input, str): if isfree is None: isfree = True diff --git a/numpy/f2py/lib/parser/base_classes.py b/numpy/f2py/lib/parser/base_classes.py index 81e38ace1..7feafd74f 100644 --- a/numpy/f2py/lib/parser/base_classes.py +++ b/numpy/f2py/lib/parser/base_classes.py @@ -675,7 +675,7 @@ class EndStatement(Statement): item = self.item line = item.get_line().replace(' ','')[3:] blocktype = self.blocktype - if line.startswith(blocktype): + if line.lower().startswith(blocktype): line = line[len(blocktype):].strip() else: if line: diff --git a/numpy/f2py/lib/parser/block_statements.py b/numpy/f2py/lib/parser/block_statements.py index 1f2d33dca..223d7659c 100644 --- a/numpy/f2py/lib/parser/block_statements.py +++ b/numpy/f2py/lib/parser/block_statements.py @@ -12,8 +12,12 @@ Created: May 2006 """ __all__ = ['BeginSource','Module','PythonModule','Program','BlockData','Interface', - 'Subroutine','Function','Select','EndWhere','WhereConstruct','ForallConstruct', - 'IfThen','If','Do','Associate','TypeDecl','Enum'] + 'Subroutine','Function','Select','WhereConstruct','ForallConstruct', + 'IfThen','If','Do','Associate','TypeDecl','Enum', + 'EndSource','EndModule','EndPythonModule','EndProgram','EndBlockData','EndInterface', + 'EndSubroutine','EndFunction','EndSelect','EndWhere','EndForall', + 'EndIfThen','EndDo','EndAssociate','EndType','EndEnum', + ] import re import sys @@ -100,9 +104,12 @@ class HasVariables: self.a.variable_names.append(name) return var - def topyf(self,tab=''): + def topyf(self,tab='', only_variables = None): s = '' - for name, var in self.a.variables.items(): + if only_variables is None: + only_variables = self.a.variables.keys() + for name in only_variables: + var = self.a.variables[name] s += tab + str(var) + '\n' return s @@ -206,6 +213,8 @@ class BeginSource(BeginStatement): return def get_classes(self): + if self.reader.ispyf: + return [PythonModule] + program_unit return program_unit def process_subitem(self, item): @@ -231,11 +240,11 @@ class BeginSource(BeginStatement): def topyf(self, tab=''): # XXXX s = '' for name, stmt in self.a.module.items(): - s += stmt.topyf() + s += stmt.topyf(tab=tab) for name, stmt in self.a.external_subprogram.items(): - s += stmt.topyf() + s += stmt.topyf(tab=tab) for name, stmt in self.a.blockdata.items(): - s += stmt.topyf() + s += stmt.topyf(tab=tab) return s # Module @@ -415,7 +424,10 @@ class Interface(BeginStatement, HasImplicitStmt, HasUseStmt, a = AttributeHolder(interface_provides = {}) def get_classes(self): - return intrinsic_type_spec + interface_specification + l = intrinsic_type_spec + interface_specification + if self.reader.mode=='pyf': + return [Subroutine, Function] + l + return l def process_item(self): line = self.item.get_line() @@ -456,6 +468,9 @@ class Interface(BeginStatement, HasImplicitStmt, HasUseStmt, return + def is_public(self): + return True # TODO: need review. + # Subroutine class SubProgramStatement(BeginStatement, ProgramBlock, @@ -475,8 +490,8 @@ class SubProgramStatement(BeginStatement, ProgramBlock, item = self.item line = item.get_line() m = self.match(line) - i = line.find(clsname) - assert i!=-1,`line` + i = line.lower().find(clsname) + assert i!=-1,`clsname, line` self.prefix = line[:i].rstrip() self.name = line[i:m.end()].lstrip()[len(clsname):].strip() line = line[m.end():].lstrip() @@ -575,7 +590,7 @@ class SubProgramStatement(BeginStatement, ProgramBlock, s += '\n' s += HasImplicitStmt.topyf(self, tab=tab+' ') s += HasTypeDecls.topyf(self, tab=tab+' ') - s += HasVariables.topyf(self, tab=tab+' ') + s += HasVariables.topyf(self, tab=tab+' ', only_variables = self.args) s += tab + 'END ' + self.__class__.__name__.upper() + ' ' + self.name + '\n' return s @@ -771,7 +786,7 @@ class If(BeginStatement): IF ( <scalar-logical-expr> ) action-stmt """ - match = re.compile(r'if\s*\(').match + match = re.compile(r'if\s*\(',re.I).match def process_item(self): item = self.item @@ -779,14 +794,14 @@ class If(BeginStatement): classes = self.get_classes() classes = [cls for cls in classes if mode in cls.modes] - line = item.get_line()[2:] + line = item.get_line()[2:].lstrip() i = line.find(')') expr = line[1:i].strip() line = line[i+1:].strip() if line.lower()=='then': self.isvalid = False return - self.expr = expr[1:-1] + self.expr = item.apply_map(expr) if not line: newitem = self.get_item() diff --git a/numpy/f2py/lib/parser/statements.py b/numpy/f2py/lib/parser/statements.py index 5c982ea8b..7966692d2 100644 --- a/numpy/f2py/lib/parser/statements.py +++ b/numpy/f2py/lib/parser/statements.py @@ -185,8 +185,7 @@ class Call(Statement): if hasattr(a, 'external'): external = a.external if self.designator in external: - print 'Need to analyze:',self - print self + print >> sys.stderr, 'Need to analyze:',self return class Goto(Statement): diff --git a/numpy/f2py/lib/python_wrapper.py b/numpy/f2py/lib/python_wrapper.py index 432f96c8f..6f7500b1e 100644 --- a/numpy/f2py/lib/python_wrapper.py +++ b/numpy/f2py/lib/python_wrapper.py @@ -248,20 +248,29 @@ static void %(init_func)s_c( capi_code_template = '''\ static void %(oname)s_dealloc(%(oname)sObject* self) { - PyMem_Free(self->data); + if (self->data) + PyMem_Free(self->data); self->ob_type->tp_free((PyObject*)self); } static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value_ptr) { + int return_value = 0; +#if defined(F2PY_DEBUG_PYOBJ_TOFROM) + fprintf(stderr,"pyobj_to_%(ctype)s(type=%%s)\\n",PyString_AS_STRING(PyObject_Repr(PyObject_Type(obj)))); +#endif 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."); + } else { + return_value = 1; } - return 1; } - return 0; +#if defined(F2PY_DEBUG_PYOBJ_TOFROM) + fprintf(stderr,"pyobj_to_%(ctype)s: return_value=%%d, PyErr_Occurred()=%%p\\n", return_value, PyErr_Occurred()); +#endif + return return_value; } static PyObject* pyobj_from_%(ctype)s(%(ctype)s* value_ptr) { @@ -292,8 +301,17 @@ static PyObject * %(oname)s_new(PyTypeObject *type, 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); + int return_value = 0; +#if defined(F2PY_DEBUG_PYOBJ_TOFROM) + fprintf(stderr,"%(oname)s_init()\\n"); +#endif + if (!PyArg_ParseTuple(capi_args,"%(attr_format_elist)s" + %(attr_init_clist)s)) + return_value = -1; +#if defined(F2PY_DEBUG_PYOBJ_TOFROM) + fprintf(stderr,"%(oname)s_init: return_value=%%d, PyErr_Occurred()=%%p\\n", return_value, PyErr_Occurred()); +#endif + return return_value; } static PyObject * %(oname)s_as_tuple(%(oname)sObject * self) { @@ -597,7 +615,7 @@ if __name__ == '__main__': foo_code = """! -*- f90 -*- module rat type info - complex flag + complex*8 flag end type info type rational !integer n,d @@ -641,6 +659,7 @@ def configuration(parent_package='',top_path=None): config.add_extension('foo', sources=['foomodule.c'], libraries = ['foolib'], + define_macros = [('F2PY_DEBUG_PYOBJ_TOFROM',None)] ) return config if __name__ == '__main__': @@ -656,11 +675,11 @@ if __name__ == '__main__': #print foo.info.__doc__ #print foo.rational.__doc__ #print dir(foo.rational) - i = foo.info(70+3j) + i = foo.info(2) print 'i=',i #print i #,i.as_tuple() #print 'i.flag=',i.flag - r = foo.rational(i) + r = foo.rational(2) print r j = r.i print 'r.i.flag=',(r.i).flag diff --git a/numpy/f2py/lib/setup.py b/numpy/f2py/lib/setup.py new file mode 100644 index 000000000..cd63b07cd --- /dev/null +++ b/numpy/f2py/lib/setup.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python +def configuration(parent_package='',top_path=None): + from numpy.distutils.misc_util import Configuration + config = Configuration('lib',parent_package,top_path) + config.add_subpackage('parser') + config.add_data_files('*.txt','parser/*.txt') + config.add_data_dir('src') + return config + +if __name__ == "__main__": + from numpy.distutils.core import setup + setup(configuration=configuration) diff --git a/numpy/f2py/lib/src/pyobj_to_Py_complex.c b/numpy/f2py/lib/src/pyobj_to_Py_complex.c index 4873e818a..33eb2b6c4 100644 --- a/numpy/f2py/lib/src/pyobj_to_Py_complex.c +++ b/numpy/f2py/lib/src/pyobj_to_Py_complex.c @@ -1,40 +1,54 @@ int pyobj_to_Py_complex(PyObject* obj, Py_complex* value) { + int return_value = 0; +#if defined(F2PY_DEBUG_PYOBJ_TOFROM) + fprintf(stderr,"pyobj_to_Py_complex(type=%s)\n",PyString_AS_STRING(PyObject_Repr(PyObject_Type(obj)))); +#endif if (PyComplex_Check(obj)) { *value =PyComplex_AsCComplex(obj); - return 1; + return_value = 1; + goto capi_done; } /* Python does not provide PyNumber_Complex function :-( */ (*value).imag=0.0; if (PyFloat_Check(obj)) { #ifdef __sgi (*value).real = PyFloat_AsDouble(obj); - return (!PyErr_Occurred()); + return_value = !PyErr_Occurred() #else (*value).real = PyFloat_AS_DOUBLE(obj); - return 1; + return_value = 1; #endif + goto capi_done; } if (PyInt_Check(obj)) { (*value).real = (double)PyInt_AS_LONG(obj); - return 1; + return_value = 1; + goto capi_done; } if (PyLong_Check(obj)) { (*value).real = PyLong_AsDouble(obj); - return (!PyErr_Occurred()); + return_value = !PyErr_Occurred();; + goto capi_done; } if (PySequence_Check(obj) && (!PyString_Check(obj))) { PyObject *tmp = PySequence_GetItem(obj,0); if (tmp) { if (pyobj_to_Py_complex(tmp,value)) { Py_DECREF(tmp); - return 1; + return_value = 1; + goto capi_done; } Py_DECREF(tmp); } } + if (!PyErr_Occurred()) { PyErr_SetString(PyExc_TypeError, "Failed to convert python object to C Py_complex."); } - return 0; + capi_done: +#if defined(F2PY_DEBUG_PYOBJ_TOFROM) + fprintf(stderr,"pyobj_to_Py_complex: return_value=%d, PyErr_Occurred()=%p\n", return_value, PyErr_Occurred()); +#endif + return return_value; } diff --git a/numpy/f2py/setup.py b/numpy/f2py/setup.py index 7906798bf..81d0fd20b 100755 --- a/numpy/f2py/setup.py +++ b/numpy/f2py/setup.py @@ -29,6 +29,8 @@ from __version__ import version def configuration(parent_package='',top_path=None): config = Configuration('f2py', parent_package, top_path) + config.add_subpackage('lib') + config.add_data_dir('docs') config.add_data_files('src/fortranobject.c', @@ -51,10 +53,30 @@ def configuration(parent_package='',top_path=None): f.write('''\ #!/usr/bin/env %s # See http://cens.ioc.ee/projects/f2py2e/ -import os +import os, sys +for mode in ["g3-numpy", "2e-numeric", "2e-numarray", "2e-numpy"]: + try: + i=sys.argv.index("--"+mode) + del sys.argv[i] + break + except ValueError: pass os.environ["NO_SCIPY_IMPORT"]="f2py" -import numpy.f2py as f2py -f2py.main() +if mode=="g3-numpy": + try: + from main import main + except ImportError: + from numpy.f2py.lib.api import main +elif mode=="2e-numeric": + from f2py2e import main +elif mode=="2e-numarray": + sys.argv.append("-DNUMARRAY") + from f2py2e import main +elif mode=="2e-numpy": + from numpy.f2py import main +else: + print >> sys.stderr, "Unknown mode:",`mode` + sys.exit(1) +main() '''%(os.path.basename(sys.executable))) f.close() return target |