summaryrefslogtreecommitdiff
path: root/numpy/f2py
diff options
context:
space:
mode:
Diffstat (limited to 'numpy/f2py')
-rw-r--r--numpy/f2py/__init__.py4
-rw-r--r--numpy/f2py/__main__.py3
-rw-r--r--numpy/f2py/auxfuncs.py6
-rw-r--r--numpy/f2py/capi_maps.py30
-rw-r--r--numpy/f2py/cb_rules.py22
-rw-r--r--numpy/f2py/cfuncs.py48
-rwxr-xr-xnumpy/f2py/crackfortran.py406
-rwxr-xr-xnumpy/f2py/f2py2e.py51
-rwxr-xr-xnumpy/f2py/rules.py510
-rw-r--r--numpy/f2py/setup.py4
-rw-r--r--numpy/f2py/src/fortranobject.c744
-rw-r--r--numpy/f2py/src/fortranobject.h123
-rw-r--r--numpy/f2py/src/test/Makefile96
-rw-r--r--numpy/f2py/src/test/bar.f11
-rw-r--r--numpy/f2py/src/test/foo.f11
-rw-r--r--numpy/f2py/src/test/foo90.f9013
-rw-r--r--numpy/f2py/src/test/foomodule.c148
-rw-r--r--numpy/f2py/src/test/wrap.f70
-rw-r--r--numpy/f2py/symbolic.py1510
-rw-r--r--numpy/f2py/tests/src/array_from_pyobj/wrapmodule.c4
-rw-r--r--numpy/f2py/tests/test_callback.py7
-rw-r--r--numpy/f2py/tests/test_crackfortran.py116
-rw-r--r--numpy/f2py/tests/test_return_character.py4
-rw-r--r--numpy/f2py/tests/test_symbolic.py462
-rw-r--r--numpy/f2py/tests/util.py3
25 files changed, 3057 insertions, 1349 deletions
diff --git a/numpy/f2py/__init__.py b/numpy/f2py/__init__.py
index 47354cd9d..a0fb73619 100644
--- a/numpy/f2py/__init__.py
+++ b/numpy/f2py/__init__.py
@@ -71,8 +71,8 @@ def compile(source,
Examples
--------
- .. include:: compile_session.dat
- :literal:
+ .. literalinclude:: code/results/compile_session.dat
+ :language: python
"""
import tempfile
diff --git a/numpy/f2py/__main__.py b/numpy/f2py/__main__.py
index c6115070e..936a753a2 100644
--- a/numpy/f2py/__main__.py
+++ b/numpy/f2py/__main__.py
@@ -1,4 +1,5 @@
-# See http://cens.ioc.ee/projects/f2py2e/
+# See:
+# https://web.archive.org/web/20140822061353/http://cens.ioc.ee/projects/f2py2e
from numpy.f2py.f2py2e import main
main()
diff --git a/numpy/f2py/auxfuncs.py b/numpy/f2py/auxfuncs.py
index 5250fea84..c8f2067c9 100644
--- a/numpy/f2py/auxfuncs.py
+++ b/numpy/f2py/auxfuncs.py
@@ -347,9 +347,9 @@ def iscomplexfunction_warn(rout):
**************************************************************
Warning: code with a function returning complex value
may not work correctly with your Fortran compiler.
- Run the following test before using it in your applications:
- $(f2py install dir)/test-site/{b/runme_scalar,e/runme}
- When using GNU gcc/g77 compilers, codes should work correctly.
+ When using GNU gcc/g77 compilers, codes should work
+ correctly for callbacks with:
+ f2py -c -DF2PY_CB_RETURNCOMPLEX
**************************************************************\n""")
return 1
return 0
diff --git a/numpy/f2py/capi_maps.py b/numpy/f2py/capi_maps.py
index fe0d4a52b..655cfd768 100644
--- a/numpy/f2py/capi_maps.py
+++ b/numpy/f2py/capi_maps.py
@@ -48,7 +48,7 @@ c2py_map = {'double': 'float',
'unsigned_char': 'int', # forced casting
'short': 'int', # forced casting
'unsigned_short': 'int', # forced casting
- 'int': 'int', # (forced casting)
+ 'int': 'int', # forced casting
'long': 'int',
'long_long': 'long',
'unsigned': 'int', # forced casting
@@ -95,8 +95,8 @@ if using_newcore:
'complex_double': 'NPY_CDOUBLE',
'complex_long_double': 'NPY_CDOUBLE',
'string':'NPY_STRING'
-
}
+
c2pycode_map = {'double': 'd',
'float': 'f',
'long_double': 'd', # forced casting
@@ -114,6 +114,7 @@ c2pycode_map = {'double': 'd',
'complex_long_double': 'D', # forced casting
'string': 'c'
}
+
if using_newcore:
c2pycode_map = {'double': 'd',
'float': 'f',
@@ -133,6 +134,7 @@ if using_newcore:
'complex_double': 'D',
'complex_long_double': 'G',
'string': 'S'}
+
c2buildvalue_map = {'double': 'd',
'float': 'f',
'char': 'b',
@@ -146,10 +148,6 @@ c2buildvalue_map = {'double': 'd',
'complex_long_double': 'N',
'string': 'y'}
-if using_newcore:
- # c2buildvalue_map=???
- pass
-
f2cmap_all = {'real': {'': 'float', '4': 'float', '8': 'double',
'12': 'long_double', '16': 'long_double'},
'integer': {'': 'int', '1': 'signed_char', '2': 'short',
@@ -185,22 +183,22 @@ def load_f2cmap_file(f2cmap_file):
return
# User defined additions to f2cmap_all.
- # f2cmap_file must contain a dictionary of dictionaries, only. For
+ # f2cmap_file must contain a dictionary of dictionaries, only. For
# example, {'real':{'low':'float'}} means that Fortran 'real(low)' is
- # interpreted as C 'float'. This feature is useful for F90/95 users if
- # they use PARAMETERSs in type specifications.
+ # interpreted as C 'float'. This feature is useful for F90/95 users if
+ # they use PARAMETERS in type specifications.
try:
outmess('Reading f2cmap from {!r} ...\n'.format(f2cmap_file))
with open(f2cmap_file, 'r') as f:
d = eval(f.read(), {}, {})
- for k, d1 in list(d.items()):
- for k1 in list(d1.keys()):
+ for k, d1 in d.items():
+ for k1 in d1.keys():
d1[k1.lower()] = d1[k1]
d[k.lower()] = d[k]
- for k in list(d.keys()):
+ for k in d.keys():
if k not in f2cmap_all:
f2cmap_all[k] = {}
- for k1 in list(d[k].keys()):
+ for k1 in d[k].keys():
if d[k][k1] in c2py_map:
if k1 in f2cmap_all[k]:
outmess(
@@ -279,11 +277,9 @@ def getctype(var):
errmess('getctype: "%s(kind=%s)" is mapped to C "%s" (to override define dict(%s = dict(%s="<C typespec>")) in %s/.f2py_f2cmap file).\n'
% (typespec, var['kindselector']['kind'], ctype,
typespec, var['kindselector']['kind'], os.getcwd()))
-
else:
if not isexternal(var):
- errmess(
- 'getctype: No C-type found in "%s", assuming void.\n' % var)
+ errmess('getctype: No C-type found in "%s", assuming void.\n' % var)
return ctype
@@ -523,7 +519,7 @@ def sign2map(a, var):
if f(var):
intent_flags.append('F2PY_%s' % s)
if intent_flags:
- # XXX: Evaluate intent_flags here.
+ # TODO: Evaluate intent_flags here.
ret['intent'] = '|'.join(intent_flags)
else:
ret['intent'] = 'F2PY_INTENT_IN'
diff --git a/numpy/f2py/cb_rules.py b/numpy/f2py/cb_rules.py
index 5c9ddb00a..4848233d4 100644
--- a/numpy/f2py/cb_rules.py
+++ b/numpy/f2py/cb_rules.py
@@ -191,7 +191,7 @@ capi_return_pt:
'maxnofargs': '#maxnofargs#',
'nofoptargs': '#nofoptargs#',
'docstr': """\
-\tdef #argname#(#docsignature#): return #docreturn#\\n\\
+ def #argname#(#docsignature#): return #docreturn#\\n\\
#docstrsigns#""",
'latexdocstr': """
{{}\\verb@def #argname#(#latexdocsignature#): return #docreturn#@{}}
@@ -219,10 +219,10 @@ cb_rout_rules = [
'noargs': '',
'setdims': '/*setdims*/',
'docstrsigns': '', 'latexdocstrsigns': '',
- 'docstrreq': '\tRequired arguments:',
- 'docstropt': '\tOptional arguments:',
- 'docstrout': '\tReturn objects:',
- 'docstrcbs': '\tCall-back functions:',
+ 'docstrreq': ' Required arguments:',
+ 'docstropt': ' Optional arguments:',
+ 'docstrout': ' Return objects:',
+ 'docstrcbs': ' Call-back functions:',
'docreturn': '', 'docsign': '', 'docsignopt': '',
'latexdocstrreq': '\\noindent Required arguments:',
'latexdocstropt': '\\noindent Optional arguments:',
@@ -306,7 +306,7 @@ return_value
'string.h', 'GETSCALARFROMPYTUPLE', '#ctype#'],
'_check': iscomplexfunction
},
- {'docstrout': '\t\t#pydocsignout#',
+ {'docstrout': ' #pydocsignout#',
'latexdocstrout': ['\\item[]{{}\\verb@#pydocsignout#@{}}',
{hasnote: '--- #note#'}],
'docreturn': '#rname#,',
@@ -316,9 +316,9 @@ return_value
cb_arg_rules = [
{ # Doc
- 'docstropt': {l_and(isoptional, isintent_nothide): '\t\t#pydocsign#'},
- 'docstrreq': {l_and(isrequired, isintent_nothide): '\t\t#pydocsign#'},
- 'docstrout': {isintent_out: '\t\t#pydocsignout#'},
+ 'docstropt': {l_and(isoptional, isintent_nothide): ' #pydocsign#'},
+ 'docstrreq': {l_and(isrequired, isintent_nothide): ' #pydocsign#'},
+ 'docstrout': {isintent_out: ' #pydocsignout#'},
'latexdocstropt': {l_and(isoptional, isintent_nothide): ['\\item[]{{}\\verb@#pydocsign#@{}}',
{hasnote: '--- #note#'}]},
'latexdocstrreq': {l_and(isrequired, isintent_nothide): ['\\item[]{{}\\verb@#pydocsign#@{}}',
@@ -492,7 +492,7 @@ def buildcallbacks(m):
def buildcallback(rout, um):
from . import capi_maps
- outmess('\tConstructing call-back function "cb_%s_in_%s"\n' %
+ outmess(' Constructing call-back function "cb_%s_in_%s"\n' %
(rout['name'], um))
args, depargs = getargs(rout)
capi_maps.depargs = depargs
@@ -612,6 +612,6 @@ def buildcallback(rout, um):
'latexdocstr': ar['latexdocstr'],
'argname': rd['argname']
}
- outmess('\t %s\n' % (ar['docstrshort']))
+ outmess(' %s\n' % (ar['docstrshort']))
return
################## Build call-back function #############
diff --git a/numpy/f2py/cfuncs.py b/numpy/f2py/cfuncs.py
index 714f9a932..1d9236dcd 100644
--- a/numpy/f2py/cfuncs.py
+++ b/numpy/f2py/cfuncs.py
@@ -51,7 +51,7 @@ includes0['math.h'] = '#include <math.h>'
includes0['string.h'] = '#include <string.h>'
includes0['setjmp.h'] = '#include <setjmp.h>'
-includes['Python.h'] = '#include "Python.h"'
+includes['Python.h'] = '#include <Python.h>'
needs['arrayobject.h'] = ['Python.h']
includes['arrayobject.h'] = '''#define PY_ARRAY_UNIQUE_SYMBOL PyArray_API
#include "arrayobject.h"'''
@@ -338,16 +338,16 @@ cppmacros['TRYPYARRAYTEMPLATE'] = """\
if (!(arr=(PyArrayObject *)obj)) {fprintf(stderr,\"TRYPYARRAYTEMPLATE:\");PRINTPYOBJERR(obj);return 0;}\\
if (PyArray_DESCR(arr)->type==typecode) {*(ctype *)(PyArray_DATA(arr))=*v; return 1;}\\
switch (PyArray_TYPE(arr)) {\\
- case NPY_DOUBLE: *(double *)(PyArray_DATA(arr))=*v; break;\\
- case NPY_INT: *(int *)(PyArray_DATA(arr))=*v; break;\\
- case NPY_LONG: *(long *)(PyArray_DATA(arr))=*v; break;\\
- case NPY_FLOAT: *(float *)(PyArray_DATA(arr))=*v; break;\\
- case NPY_CDOUBLE: *(double *)(PyArray_DATA(arr))=*v; break;\\
- case NPY_CFLOAT: *(float *)(PyArray_DATA(arr))=*v; break;\\
+ case NPY_DOUBLE: *(npy_double *)(PyArray_DATA(arr))=*v; break;\\
+ case NPY_INT: *(npy_int *)(PyArray_DATA(arr))=*v; break;\\
+ case NPY_LONG: *(npy_long *)(PyArray_DATA(arr))=*v; break;\\
+ case NPY_FLOAT: *(npy_float *)(PyArray_DATA(arr))=*v; break;\\
+ case NPY_CDOUBLE: *(npy_double *)(PyArray_DATA(arr))=*v; break;\\
+ case NPY_CFLOAT: *(npy_float *)(PyArray_DATA(arr))=*v; break;\\
case NPY_BOOL: *(npy_bool *)(PyArray_DATA(arr))=(*v!=0); break;\\
- case NPY_UBYTE: *(unsigned char *)(PyArray_DATA(arr))=*v; break;\\
- case NPY_BYTE: *(signed char *)(PyArray_DATA(arr))=*v; break;\\
- case NPY_SHORT: *(short *)(PyArray_DATA(arr))=*v; break;\\
+ case NPY_UBYTE: *(npy_ubyte *)(PyArray_DATA(arr))=*v; break;\\
+ case NPY_BYTE: *(npy_byte *)(PyArray_DATA(arr))=*v; break;\\
+ case NPY_SHORT: *(npy_short *)(PyArray_DATA(arr))=*v; break;\\
case NPY_USHORT: *(npy_ushort *)(PyArray_DATA(arr))=*v; break;\\
case NPY_UINT: *(npy_uint *)(PyArray_DATA(arr))=*v; break;\\
case NPY_ULONG: *(npy_ulong *)(PyArray_DATA(arr))=*v; break;\\
@@ -375,15 +375,19 @@ cppmacros['TRYCOMPLEXPYARRAYTEMPLATE'] = """\
return 1;\\
}\\
switch (PyArray_TYPE(arr)) {\\
- case NPY_CDOUBLE: *(double *)(PyArray_DATA(arr))=(*v).r;*(double *)(PyArray_DATA(arr)+sizeof(double))=(*v).i;break;\\
- case NPY_CFLOAT: *(float *)(PyArray_DATA(arr))=(*v).r;*(float *)(PyArray_DATA(arr)+sizeof(float))=(*v).i;break;\\
- case NPY_DOUBLE: *(double *)(PyArray_DATA(arr))=(*v).r; break;\\
- case NPY_LONG: *(long *)(PyArray_DATA(arr))=(*v).r; break;\\
- case NPY_FLOAT: *(float *)(PyArray_DATA(arr))=(*v).r; break;\\
- case NPY_INT: *(int *)(PyArray_DATA(arr))=(*v).r; break;\\
- case NPY_SHORT: *(short *)(PyArray_DATA(arr))=(*v).r; break;\\
- case NPY_UBYTE: *(unsigned char *)(PyArray_DATA(arr))=(*v).r; break;\\
- case NPY_BYTE: *(signed char *)(PyArray_DATA(arr))=(*v).r; break;\\
+ case NPY_CDOUBLE: *(npy_double *)(PyArray_DATA(arr))=(*v).r;\\
+ *(npy_double *)(PyArray_DATA(arr)+sizeof(npy_double))=(*v).i;\\
+ break;\\
+ case NPY_CFLOAT: *(npy_float *)(PyArray_DATA(arr))=(*v).r;\\
+ *(npy_float *)(PyArray_DATA(arr)+sizeof(npy_float))=(*v).i;\\
+ break;\\
+ case NPY_DOUBLE: *(npy_double *)(PyArray_DATA(arr))=(*v).r; break;\\
+ case NPY_LONG: *(npy_long *)(PyArray_DATA(arr))=(*v).r; break;\\
+ case NPY_FLOAT: *(npy_float *)(PyArray_DATA(arr))=(*v).r; break;\\
+ case NPY_INT: *(npy_int *)(PyArray_DATA(arr))=(*v).r; break;\\
+ case NPY_SHORT: *(npy_short *)(PyArray_DATA(arr))=(*v).r; break;\\
+ case NPY_UBYTE: *(npy_ubyte *)(PyArray_DATA(arr))=(*v).r; break;\\
+ case NPY_BYTE: *(npy_byte *)(PyArray_DATA(arr))=(*v).r; break;\\
case NPY_BOOL: *(npy_bool *)(PyArray_DATA(arr))=((*v).r!=0 && (*v).i!=0); break;\\
case NPY_USHORT: *(npy_ushort *)(PyArray_DATA(arr))=(*v).r; break;\\
case NPY_UINT: *(npy_uint *)(PyArray_DATA(arr))=(*v).r; break;\\
@@ -391,7 +395,9 @@ cppmacros['TRYCOMPLEXPYARRAYTEMPLATE'] = """\
case NPY_LONGLONG: *(npy_longlong *)(PyArray_DATA(arr))=(*v).r; break;\\
case NPY_ULONGLONG: *(npy_ulonglong *)(PyArray_DATA(arr))=(*v).r; break;\\
case NPY_LONGDOUBLE: *(npy_longdouble *)(PyArray_DATA(arr))=(*v).r; break;\\
- case NPY_CLONGDOUBLE: *(npy_longdouble *)(PyArray_DATA(arr))=(*v).r;*(npy_longdouble *)(PyArray_DATA(arr)+sizeof(npy_longdouble))=(*v).i;break;\\
+ case NPY_CLONGDOUBLE: *(npy_longdouble *)(PyArray_DATA(arr))=(*v).r;\\
+ *(npy_longdouble *)(PyArray_DATA(arr)+sizeof(npy_longdouble))=(*v).i;\\
+ break;\\
case NPY_OBJECT: PyArray_SETITEM(arr, PyArray_DATA(arr), pyobj_from_complex_ ## ctype ## 1((*v))); break;\\
default: return -2;\\
};\\
@@ -487,7 +493,7 @@ STRINGPADN replaces null values with padding values from the right.
`to` must have size of at least N bytes.
If the `to[N-1]` has null value, then replace it and all the
-preceeding nulls with the given padding.
+preceding, nulls with the given padding.
STRINGPADN(to, N, PADDING, NULLVALUE) is an inverse operation.
*/
diff --git a/numpy/f2py/crackfortran.py b/numpy/f2py/crackfortran.py
index c3ec792e3..67675af45 100755
--- a/numpy/f2py/crackfortran.py
+++ b/numpy/f2py/crackfortran.py
@@ -153,7 +153,7 @@ from . import __version__
# As the needed functions cannot be determined by static inspection of the
# code, it is safest to use import * pending a major refactoring of f2py.
from .auxfuncs import *
-
+from . import symbolic
f2py_version = __version__.version
@@ -245,7 +245,6 @@ for c in "abcdefghopqrstuvwxyz$_":
defaultimplicitrules[c] = {'typespec': 'real'}
for c in "ijklmn":
defaultimplicitrules[c] = {'typespec': 'integer'}
-del c
badnames = {}
invbadnames = {}
for n in ['int', 'double', 'float', 'char', 'short', 'long', 'void', 'case', 'while',
@@ -875,10 +874,11 @@ def appenddecl(decl, decl2, force=1):
decl[k] = decl2[k]
elif k == 'note':
pass
- elif k in ['intent', 'check', 'dimension', 'optional', 'required']:
+ elif k in ['intent', 'check', 'dimension', 'optional',
+ 'required', 'depend']:
errmess('appenddecl: "%s" not implemented.\n' % k)
else:
- raise Exception('appenddecl: Unknown variable definition key:' +
+ raise Exception('appenddecl: Unknown variable definition key: ' +
str(k))
return decl
@@ -2217,188 +2217,6 @@ def getlincoef(e, xset): # e = a*x+b ; x in xset
break
return None, None, None
-_varname_match = re.compile(r'\A[a-z]\w*\Z').match
-
-
-def getarrlen(dl, args, star='*'):
- """
- Parameters
- ----------
- dl : sequence of two str objects
- dimensions of the array
- args : Iterable[str]
- symbols used in the expression
- star : Any
- unused
-
- Returns
- -------
- expr : str
- Some numeric expression as a string
- arg : Optional[str]
- If understood, the argument from `args` present in `expr`
- expr2 : Optional[str]
- If understood, an expression fragment that should be used as
- ``"(%s%s".format(something, expr2)``.
-
- Examples
- --------
- >>> getarrlen(['10*x + 20', '40*x'], {'x'})
- ('30 * x - 19', 'x', '+19)/(30)')
- >>> getarrlen(['1', '10*x + 20'], {'x'})
- ('10 * x + 20', 'x', '-20)/(10)')
- >>> getarrlen(['10*x + 20', '1'], {'x'})
- ('-10 * x - 18', 'x', '+18)/(-10)')
- >>> getarrlen(['20', '1'], {'x'})
- ('-18', None, None)
- """
- edl = []
- try:
- edl.append(myeval(dl[0], {}, {}))
- except Exception:
- edl.append(dl[0])
- try:
- edl.append(myeval(dl[1], {}, {}))
- except Exception:
- edl.append(dl[1])
- if isinstance(edl[0], int):
- p1 = 1 - edl[0]
- if p1 == 0:
- d = str(dl[1])
- elif p1 < 0:
- d = '%s-%s' % (dl[1], -p1)
- else:
- d = '%s+%s' % (dl[1], p1)
- elif isinstance(edl[1], int):
- p1 = 1 + edl[1]
- if p1 == 0:
- d = '-(%s)' % (dl[0])
- else:
- d = '%s-(%s)' % (p1, dl[0])
- else:
- d = '%s-(%s)+1' % (dl[1], dl[0])
- try:
- return repr(myeval(d, {}, {})), None, None
- except Exception:
- pass
- d1, d2 = getlincoef(dl[0], args), getlincoef(dl[1], args)
- if None not in [d1[0], d2[0]]:
- if (d1[0], d2[0]) == (0, 0):
- return repr(d2[1] - d1[1] + 1), None, None
- b = d2[1] - d1[1] + 1
- d1 = (d1[0], 0, d1[2])
- d2 = (d2[0], b, d2[2])
- if d1[0] == 0 and d2[2] in args:
- if b < 0:
- return '%s * %s - %s' % (d2[0], d2[2], -b), d2[2], '+%s)/(%s)' % (-b, d2[0])
- elif b:
- return '%s * %s + %s' % (d2[0], d2[2], b), d2[2], '-%s)/(%s)' % (b, d2[0])
- else:
- return '%s * %s' % (d2[0], d2[2]), d2[2], ')/(%s)' % (d2[0])
- if d2[0] == 0 and d1[2] in args:
-
- if b < 0:
- return '%s * %s - %s' % (-d1[0], d1[2], -b), d1[2], '+%s)/(%s)' % (-b, -d1[0])
- elif b:
- return '%s * %s + %s' % (-d1[0], d1[2], b), d1[2], '-%s)/(%s)' % (b, -d1[0])
- else:
- return '%s * %s' % (-d1[0], d1[2]), d1[2], ')/(%s)' % (-d1[0])
- if d1[2] == d2[2] and d1[2] in args:
- a = d2[0] - d1[0]
- if not a:
- return repr(b), None, None
- if b < 0:
- return '%s * %s - %s' % (a, d1[2], -b), d2[2], '+%s)/(%s)' % (-b, a)
- elif b:
- return '%s * %s + %s' % (a, d1[2], b), d2[2], '-%s)/(%s)' % (b, a)
- else:
- return '%s * %s' % (a, d1[2]), d2[2], ')/(%s)' % (a)
- if d1[0] == d2[0] == 1:
- c = str(d1[2])
- if c not in args:
- if _varname_match(c):
- outmess('\tgetarrlen:variable "%s" undefined\n' % (c))
- c = '(%s)' % c
- if b == 0:
- d = '%s-%s' % (d2[2], c)
- elif b < 0:
- d = '%s-%s-%s' % (d2[2], c, -b)
- else:
- d = '%s-%s+%s' % (d2[2], c, b)
- elif d1[0] == 0:
- c2 = str(d2[2])
- if c2 not in args:
- if _varname_match(c2):
- outmess('\tgetarrlen:variable "%s" undefined\n' % (c2))
- c2 = '(%s)' % c2
- if d2[0] == 1:
- pass
- elif d2[0] == -1:
- c2 = '-%s' % c2
- else:
- c2 = '%s*%s' % (d2[0], c2)
-
- if b == 0:
- d = c2
- elif b < 0:
- d = '%s-%s' % (c2, -b)
- else:
- d = '%s+%s' % (c2, b)
- elif d2[0] == 0:
- c1 = str(d1[2])
- if c1 not in args:
- if _varname_match(c1):
- outmess('\tgetarrlen:variable "%s" undefined\n' % (c1))
- c1 = '(%s)' % c1
- if d1[0] == 1:
- c1 = '-%s' % c1
- elif d1[0] == -1:
- c1 = '+%s' % c1
- elif d1[0] < 0:
- c1 = '+%s*%s' % (-d1[0], c1)
- else:
- c1 = '-%s*%s' % (d1[0], c1)
-
- if b == 0:
- d = c1
- elif b < 0:
- d = '%s-%s' % (c1, -b)
- else:
- d = '%s+%s' % (c1, b)
- else:
- c1 = str(d1[2])
- if c1 not in args:
- if _varname_match(c1):
- outmess('\tgetarrlen:variable "%s" undefined\n' % (c1))
- c1 = '(%s)' % c1
- if d1[0] == 1:
- c1 = '-%s' % c1
- elif d1[0] == -1:
- c1 = '+%s' % c1
- elif d1[0] < 0:
- c1 = '+%s*%s' % (-d1[0], c1)
- else:
- c1 = '-%s*%s' % (d1[0], c1)
-
- c2 = str(d2[2])
- if c2 not in args:
- if _varname_match(c2):
- outmess('\tgetarrlen:variable "%s" undefined\n' % (c2))
- c2 = '(%s)' % c2
- if d2[0] == 1:
- pass
- elif d2[0] == -1:
- c2 = '-%s' % c2
- else:
- c2 = '%s*%s' % (d2[0], c2)
-
- if b == 0:
- d = '%s%s' % (c2, c1)
- elif b < 0:
- d = '%s%s-%s' % (c2, c1, -b)
- else:
- d = '%s%s+%s' % (c2, c1, b)
- return d, None, None
word_pattern = re.compile(r'\b[a-z][\w$]*\b', re.I)
@@ -2409,7 +2227,9 @@ def _get_depend_dict(name, vars, deps):
if '=' in vars[name] and not isstring(vars[name]):
for word in word_pattern.findall(vars[name]['=']):
- if word not in words and word in vars:
+ # The word_pattern may return values that are not
+ # only variables, they can be string content for instance
+ if word not in words and word in vars and word != name:
words.append(word)
for word in words[:]:
for w in deps.get(word, []) \
@@ -2596,7 +2416,8 @@ def _eval_scalar(value, params):
if _is_kind_number(value):
value = value.split('_')[0]
try:
- value = str(eval(value, {}, params))
+ value = eval(value, {}, params)
+ value = (repr if isinstance(value, str) else str)(value)
except (NameError, SyntaxError, TypeError):
return value
except Exception as msg:
@@ -2683,7 +2504,7 @@ def analyzevars(block):
pass
vars[n]['kindselector']['kind'] = l
- savelindims = {}
+ dimension_exprs = {}
if 'attrspec' in vars[n]:
attr = vars[n]['attrspec']
attr.reverse()
@@ -2736,18 +2557,18 @@ def analyzevars(block):
if dim and 'dimension' not in vars[n]:
vars[n]['dimension'] = []
for d in rmbadname([x.strip() for x in markoutercomma(dim).split('@,@')]):
- star = '*'
- if d == ':':
- star = ':'
+ star = ':' if d == ':' else '*'
+ # Evaluate `d` with respect to params
if d in params:
d = str(params[d])
- for p in list(params.keys()):
+ for p in params:
re_1 = re.compile(r'(?P<before>.*?)\b' + p + r'\b(?P<after>.*)', re.I)
m = re_1.match(d)
while m:
d = m.group('before') + \
str(params[p]) + m.group('after')
m = re_1.match(d)
+
if d == star:
dl = [star]
else:
@@ -2755,22 +2576,46 @@ def analyzevars(block):
if len(dl) == 2 and '*' in dl: # e.g. dimension(5:*)
dl = ['*']
d = '*'
- if len(dl) == 1 and not dl[0] == star:
+ if len(dl) == 1 and dl[0] != star:
dl = ['1', dl[0]]
if len(dl) == 2:
- d, v, di = getarrlen(dl, list(block['vars'].keys()))
- if d[:4] == '1 * ':
- d = d[4:]
- if di and di[-4:] == '/(1)':
- di = di[:-4]
- if v:
- savelindims[d] = v, di
+ d1, d2 = map(symbolic.Expr.parse, dl)
+ dsize = d2 - d1 + 1
+ d = dsize.tostring(language=symbolic.Language.C)
+ # find variables v that define d as a linear
+ # function, `d == a * v + b`, and store
+ # coefficients a and b for further analysis.
+ solver_and_deps = {}
+ for v in block['vars']:
+ s = symbolic.as_symbol(v)
+ if dsize.contains(s):
+ try:
+ a, b = dsize.linear_solve(s)
+ solve_v = lambda s: (s - b) / a
+ all_symbols = set(a.symbols())
+ all_symbols.update(b.symbols())
+ except RuntimeError as msg:
+ # d is not a linear function of v,
+ # however, if v can be determined
+ # from d using other means,
+ # implement the corresponding
+ # solve_v function here.
+ solve_v = None
+ all_symbols = set(dsize.symbols())
+ v_deps = set(
+ s.data for s in all_symbols
+ if s.data in vars)
+ solver_and_deps[v] = solve_v, list(v_deps)
+ # Note that dsize may contain symbols that are
+ # not defined in block['vars']. Here we assume
+ # these correspond to Fortran/C intrinsic
+ # functions or that are defined by other
+ # means. We'll let the compiler validate the
+ # definiteness of such symbols.
+ dimension_exprs[d] = solver_and_deps
vars[n]['dimension'].append(d)
+
if 'dimension' in vars[n]:
- if isintent_c(vars[n]):
- shape_macro = 'shape'
- else:
- shape_macro = 'shape' # 'fshape'
if isstringarray(vars[n]):
if 'charselector' in vars[n]:
d = vars[n]['charselector']
@@ -2789,69 +2634,87 @@ def analyzevars(block):
else:
errmess(
"analyzevars: charselector=%r unhandled." % (d))
+
if 'check' not in vars[n] and 'args' in block and n in block['args']:
- flag = 'depend' not in vars[n]
- if flag:
- vars[n]['depend'] = []
- vars[n]['check'] = []
- if 'dimension' in vars[n]:
- #/----< no check
- i = -1
- ni = len(vars[n]['dimension'])
- for d in vars[n]['dimension']:
- ddeps = [] # dependencies of 'd'
- ad = ''
- pd = ''
- if d not in vars:
- if d in savelindims:
- pd, ad = '(', savelindims[d][1]
- d = savelindims[d][0]
- else:
- for r in block['args']:
- if r not in vars:
- continue
- if re.match(r'.*?\b' + r + r'\b', d, re.I):
- ddeps.append(r)
- if d in vars:
- if 'attrspec' in vars[d]:
- for aa in vars[d]['attrspec']:
- if aa[:6] == 'depend':
- ddeps += aa[6:].strip()[1:-1].split(',')
- if 'depend' in vars[d]:
- ddeps = ddeps + vars[d]['depend']
- i = i + 1
- if d in vars and ('depend' not in vars[d]) \
- and ('=' not in vars[d]) and (d not in vars[n]['depend']) \
- and l_or(isintent_in, isintent_inout, isintent_inplace)(vars[n]):
- vars[d]['depend'] = [n]
- if ni > 1:
- vars[d]['='] = '%s%s(%s,%s)%s' % (
- pd, shape_macro, n, i, ad)
- else:
- vars[d]['='] = '%slen(%s)%s' % (pd, n, ad)
- # /---< no check
- if 1 and 'check' not in vars[d]:
- if ni > 1:
- vars[d]['check'] = ['%s%s(%s,%i)%s==%s'
- % (pd, shape_macro, n, i, ad, d)]
- else:
- vars[d]['check'] = [
- '%slen(%s)%s>=%s' % (pd, n, ad, d)]
- if 'attrspec' not in vars[d]:
- vars[d]['attrspec'] = ['optional']
- if ('optional' not in vars[d]['attrspec']) and\
- ('required' not in vars[d]['attrspec']):
- vars[d]['attrspec'].append('optional')
- elif d not in ['*', ':']:
- #/----< no check
- if flag:
- if d in vars:
- if n not in ddeps:
- vars[n]['depend'].append(d)
+ # n is an argument that has no checks defined. Here we
+ # generate some consistency checks for n, and when n is an
+ # array, generate checks for its dimensions and construct
+ # initialization expressions.
+ n_deps = vars[n].get('depend', [])
+ n_checks = []
+ n_is_input = l_or(isintent_in, isintent_inout,
+ isintent_inplace)(vars[n])
+ if 'dimension' in vars[n]: # n is array
+ for i, d in enumerate(vars[n]['dimension']):
+ coeffs_and_deps = dimension_exprs.get(d)
+ if coeffs_and_deps is None:
+ # d is `:` or `*` or a constant expression
+ pass
+ elif n_is_input:
+ # n is an input array argument and its shape
+ # may define variables used in dimension
+ # specifications.
+ for v, (solver, deps) in coeffs_and_deps.items():
+ if ((v in n_deps
+ or '=' in vars[v]
+ or 'depend' in vars[v])):
+ # Skip a variable that
+ # - n depends on
+ # - has user-defined initialization expression
+ # - has user-defined dependecies
+ continue
+ if solver is not None:
+ # v can be solved from d, hence, we
+ # make it an optional argument with
+ # initialization expression:
+ is_required = False
+ init = solver(symbolic.as_symbol(
+ f'shape({n}, {i})'))
+ init = init.tostring(
+ language=symbolic.Language.C)
+ vars[v]['='] = init
+ # n needs to be initialized before v. So,
+ # making v dependent on n and on any
+ # variables in solver or d.
+ vars[v]['depend'] = [n] + deps
+ if 'check' not in vars[v]:
+ # add check only when no
+ # user-specified checks exist
+ vars[v]['check'] = [
+ f'shape({n}, {i}) == {d}']
else:
- vars[n]['depend'] = vars[n]['depend'] + ddeps
+ # d is a non-linear function on v,
+ # hence, v must be a required input
+ # argument that n will depend on
+ is_required = True
+ if 'intent' not in vars[v]:
+ vars[v]['intent'] = []
+ if 'in' not in vars[v]['intent']:
+ vars[v]['intent'].append('in')
+ # v needs to be initialized before n
+ n_deps.append(v)
+ n_checks.append(
+ f'shape({n}, {i}) == {d}')
+ v_attr = vars[v].get('attrspec', [])
+ if not ('optional' in v_attr
+ or 'required' in v_attr):
+ v_attr.append(
+ 'required' if is_required else 'optional')
+ if v_attr:
+ vars[v]['attrspec'] = v_attr
+ if coeffs_and_deps is not None:
+ # extend v dependencies with ones specified in attrspec
+ for v, (solver, deps) in coeffs_and_deps.items():
+ v_deps = vars[v].get('depend', [])
+ for aa in vars[v].get('attrspec', []):
+ if aa.startswith('depend'):
+ aa = ''.join(aa.split())
+ v_deps.extend(aa[7:-1].split(','))
+ if v_deps:
+ vars[v]['depend'] = list(set(v_deps))
+ if n not in v_deps:
+ n_deps.append(v)
elif isstring(vars[n]):
- length = '1'
if 'charselector' in vars[n]:
if '*' in vars[n]['charselector']:
length = _eval_length(vars[n]['charselector']['*'],
@@ -2862,11 +2725,11 @@ def analyzevars(block):
params)
del vars[n]['charselector']['len']
vars[n]['charselector']['*'] = length
+ if n_checks:
+ vars[n]['check'] = n_checks
+ if n_deps:
+ vars[n]['depend'] = list(set(n_deps))
- if not vars[n]['check']:
- del vars[n]['check']
- if flag and not vars[n]['depend']:
- del vars[n]['depend']
if '=' in vars[n]:
if 'attrspec' not in vars[n]:
vars[n]['attrspec'] = []
@@ -2892,8 +2755,6 @@ def analyzevars(block):
vars[n] = appenddecl(vars[n], vars[block['result']])
if 'prefix' in block:
pr = block['prefix']
- ispure = 0
- isrec = 1
pr1 = pr.replace('pure', '')
ispure = (not pr == pr1)
pr = pr1.replace('recursive', '')
@@ -3357,7 +3218,8 @@ def crack2fortran(block):
"""
footer = """
! This file was auto-generated with f2py (version:%s).
-! See http://cens.ioc.ee/projects/f2py2e/
+! See:
+! https://web.archive.org/web/20140822061353/http://cens.ioc.ee/projects/f2py2e
""" % (f2py_version)
return header + pyf + footer
diff --git a/numpy/f2py/f2py2e.py b/numpy/f2py/f2py2e.py
index f45374be6..605495574 100755
--- a/numpy/f2py/f2py2e.py
+++ b/numpy/f2py/f2py2e.py
@@ -168,7 +168,7 @@ numpy Version: {numpy_version}
Requires: Python 3.5 or higher.
License: NumPy license (see LICENSE.txt in the NumPy source code)
Copyright 1999 - 2011 Pearu Peterson all rights reserved.
-http://cens.ioc.ee/projects/f2py2e/"""
+https://web.archive.org/web/20140822061353/http://cens.ioc.ee/projects/f2py2e"""
def scaninputline(inputline):
@@ -416,8 +416,8 @@ def run_main(comline_list):
Examples
--------
- .. include:: run_main_session.dat
- :literal:
+ .. literalinclude:: code/results/run_main_session.dat
+ :language: python
"""
crackfortran.reset_global_f2py_vars()
@@ -546,30 +546,29 @@ def run_compile():
fc_flags = [_m for _m in sys.argv[1:] if _reg4.match(_m)]
sys.argv = [_m for _m in sys.argv if _m not in fc_flags]
- if 1:
- del_list = []
- for s in flib_flags:
- v = '--fcompiler='
- if s[:len(v)] == v:
- from numpy.distutils import fcompiler
- fcompiler.load_all_fcompiler_classes()
- allowed_keys = list(fcompiler.fcompiler_class.keys())
- nv = ov = s[len(v):].lower()
- if ov not in allowed_keys:
- vmap = {} # XXX
- try:
- nv = vmap[ov]
- except KeyError:
- if ov not in vmap.values():
- print('Unknown vendor: "%s"' % (s[len(v):]))
- nv = ov
- i = flib_flags.index(s)
- flib_flags[i] = '--fcompiler=' + nv
- continue
- for s in del_list:
+ del_list = []
+ for s in flib_flags:
+ v = '--fcompiler='
+ if s[:len(v)] == v:
+ from numpy.distutils import fcompiler
+ fcompiler.load_all_fcompiler_classes()
+ allowed_keys = list(fcompiler.fcompiler_class.keys())
+ nv = ov = s[len(v):].lower()
+ if ov not in allowed_keys:
+ vmap = {} # XXX
+ try:
+ nv = vmap[ov]
+ except KeyError:
+ if ov not in vmap.values():
+ print('Unknown vendor: "%s"' % (s[len(v):]))
+ nv = ov
i = flib_flags.index(s)
- del flib_flags[i]
- assert len(flib_flags) <= 2, repr(flib_flags)
+ flib_flags[i] = '--fcompiler=' + nv
+ continue
+ for s in del_list:
+ i = flib_flags.index(s)
+ del flib_flags[i]
+ assert len(flib_flags) <= 2, repr(flib_flags)
_reg5 = re.compile(r'--(verbose)')
setup_flags = [_m for _m in sys.argv[1:] if _reg5.match(_m)]
diff --git a/numpy/f2py/rules.py b/numpy/f2py/rules.py
index 587ae2e5f..78810a0a7 100755
--- a/numpy/f2py/rules.py
+++ b/numpy/f2py/rules.py
@@ -120,6 +120,10 @@ module_rules = {
extern \"C\" {
#endif
+#ifndef PY_SSIZE_T_CLEAN
+#define PY_SSIZE_T_CLEAN
+#endif /* PY_SSIZE_T_CLEAN */
+
""" + gentitle("See f2py2e/cfuncs.py: includes") + """
#includes#
#includes0#
@@ -170,67 +174,67 @@ static PyObject *#modulename#_module;
static FortranDataDef f2py_routine_defs[] = {
#routine_defs#
-\t{NULL}
+ {NULL}
};
static PyMethodDef f2py_module_methods[] = {
#pymethoddef#
-\t{NULL,NULL}
+ {NULL,NULL}
};
static struct PyModuleDef moduledef = {
-\tPyModuleDef_HEAD_INIT,
-\t"#modulename#",
-\tNULL,
-\t-1,
-\tf2py_module_methods,
-\tNULL,
-\tNULL,
-\tNULL,
-\tNULL
+ PyModuleDef_HEAD_INIT,
+ "#modulename#",
+ NULL,
+ -1,
+ f2py_module_methods,
+ NULL,
+ NULL,
+ NULL,
+ NULL
};
PyMODINIT_FUNC PyInit_#modulename#(void) {
-\tint i;
-\tPyObject *m,*d, *s, *tmp;
-\tm = #modulename#_module = PyModule_Create(&moduledef);
-\tPy_SET_TYPE(&PyFortran_Type, &PyType_Type);
-\timport_array();
-\tif (PyErr_Occurred())
-\t\t{PyErr_SetString(PyExc_ImportError, \"can't initialize module #modulename# (failed to import numpy)\"); return m;}
-\td = PyModule_GetDict(m);
-\ts = PyUnicode_FromString(\"#f2py_version#\");
-\tPyDict_SetItemString(d, \"__version__\", s);
-\tPy_DECREF(s);
-\ts = PyUnicode_FromString(
-\t\t\"This module '#modulename#' is auto-generated with f2py (version:#f2py_version#).\\nFunctions:\\n\"\n#docs#\".\");
-\tPyDict_SetItemString(d, \"__doc__\", s);
-\tPy_DECREF(s);
-\ts = PyUnicode_FromString(\"""" + numpy_version + """\");
-\tPyDict_SetItemString(d, \"__f2py_numpy_version__\", s);
-\tPy_DECREF(s);
-\t#modulename#_error = PyErr_NewException (\"#modulename#.error\", NULL, NULL);
-\t/*
-\t * Store the error object inside the dict, so that it could get deallocated.
-\t * (in practice, this is a module, so it likely will not and cannot.)
-\t */
-\tPyDict_SetItemString(d, \"_#modulename#_error\", #modulename#_error);
-\tPy_DECREF(#modulename#_error);
-\tfor(i=0;f2py_routine_defs[i].name!=NULL;i++) {
-\t\ttmp = PyFortranObject_NewAsAttr(&f2py_routine_defs[i]);
-\t\tPyDict_SetItemString(d, f2py_routine_defs[i].name, tmp);
-\t\tPy_DECREF(tmp);
-\t}
+ int i;
+ PyObject *m,*d, *s, *tmp;
+ m = #modulename#_module = PyModule_Create(&moduledef);
+ Py_SET_TYPE(&PyFortran_Type, &PyType_Type);
+ import_array();
+ if (PyErr_Occurred())
+ {PyErr_SetString(PyExc_ImportError, \"can't initialize module #modulename# (failed to import numpy)\"); return m;}
+ d = PyModule_GetDict(m);
+ s = PyUnicode_FromString(\"#f2py_version#\");
+ PyDict_SetItemString(d, \"__version__\", s);
+ Py_DECREF(s);
+ s = PyUnicode_FromString(
+ \"This module '#modulename#' is auto-generated with f2py (version:#f2py_version#).\\nFunctions:\\n\"\n#docs#\".\");
+ PyDict_SetItemString(d, \"__doc__\", s);
+ Py_DECREF(s);
+ s = PyUnicode_FromString(\"""" + numpy_version + """\");
+ PyDict_SetItemString(d, \"__f2py_numpy_version__\", s);
+ Py_DECREF(s);
+ #modulename#_error = PyErr_NewException (\"#modulename#.error\", NULL, NULL);
+ /*
+ * Store the error object inside the dict, so that it could get deallocated.
+ * (in practice, this is a module, so it likely will not and cannot.)
+ */
+ PyDict_SetItemString(d, \"_#modulename#_error\", #modulename#_error);
+ Py_DECREF(#modulename#_error);
+ for(i=0;f2py_routine_defs[i].name!=NULL;i++) {
+ tmp = PyFortranObject_NewAsAttr(&f2py_routine_defs[i]);
+ PyDict_SetItemString(d, f2py_routine_defs[i].name, tmp);
+ Py_DECREF(tmp);
+ }
#initf2pywraphooks#
#initf90modhooks#
#initcommonhooks#
#interface_usercode#
#ifdef F2PY_REPORT_ATEXIT
-\tif (! PyErr_Occurred())
-\t\ton_exit(f2py_report_on_exit,(void*)\"#modulename#\");
+ if (! PyErr_Occurred())
+ on_exit(f2py_report_on_exit,(void*)\"#modulename#\");
#endif
-\treturn m;
+ return m;
}
#ifdef __cplusplus
}
@@ -322,7 +326,7 @@ f2py_stop_clock();
'externroutines': '#declfortranroutine#',
'doc': '#docreturn##name#(#docsignature#)',
'docshort': '#docreturn##name#(#docsignatureshort#)',
- 'docs': '"\t#docreturn##name#(#docsignature#)\\n"\n',
+ 'docs': '" #docreturn##name#(#docsignature#)\\n"\n',
'need': ['arrayobject.h', 'CFUNCSMESS', 'MINMAX'],
'cppmacros': {debugcapi: '#define DEBUGCFUNCS'},
'latexdoc': ['\\subsection{Wrapper function \\texttt{#texname#}}\n',
@@ -396,25 +400,25 @@ rout_rules = [
ismoduleroutine: '',
isdummyroutine: ''
},
- 'routine_def': {l_not(l_or(ismoduleroutine, isintent_c, isdummyroutine)): '\t{\"#name#\",-1,{{-1}},0,(char *)#F_FUNC#(#fortranname#,#FORTRANNAME#),(f2py_init_func)#apiname#,doc_#apiname#},',
- l_and(l_not(ismoduleroutine), isintent_c, l_not(isdummyroutine)): '\t{\"#name#\",-1,{{-1}},0,(char *)#fortranname#,(f2py_init_func)#apiname#,doc_#apiname#},',
- l_and(l_not(ismoduleroutine), isdummyroutine): '\t{\"#name#\",-1,{{-1}},0,NULL,(f2py_init_func)#apiname#,doc_#apiname#},',
+ 'routine_def': {l_not(l_or(ismoduleroutine, isintent_c, isdummyroutine)): ' {\"#name#\",-1,{{-1}},0,(char *)#F_FUNC#(#fortranname#,#FORTRANNAME#),(f2py_init_func)#apiname#,doc_#apiname#},',
+ l_and(l_not(ismoduleroutine), isintent_c, l_not(isdummyroutine)): ' {\"#name#\",-1,{{-1}},0,(char *)#fortranname#,(f2py_init_func)#apiname#,doc_#apiname#},',
+ l_and(l_not(ismoduleroutine), isdummyroutine): ' {\"#name#\",-1,{{-1}},0,NULL,(f2py_init_func)#apiname#,doc_#apiname#},',
},
'need': {l_and(l_not(l_or(ismoduleroutine, isintent_c)), l_not(isdummyroutine)): 'F_FUNC'},
'callfortranroutine': [
{debugcapi: [
- """\tfprintf(stderr,\"debug-capi:Fortran subroutine `#fortranname#(#callfortran#)\'\\n\");"""]},
+ """ fprintf(stderr,\"debug-capi:Fortran subroutine `#fortranname#(#callfortran#)\'\\n\");"""]},
{hasexternals: """\
-\t\tif (#setjmpbuf#) {
-\t\t\tf2py_success = 0;
-\t\t} else {"""},
- {isthreadsafe: '\t\t\tPy_BEGIN_ALLOW_THREADS'},
- {hascallstatement: '''\t\t\t\t#callstatement#;
-\t\t\t\t/*(*f2py_func)(#callfortran#);*/'''},
+ if (#setjmpbuf#) {
+ f2py_success = 0;
+ } else {"""},
+ {isthreadsafe: ' Py_BEGIN_ALLOW_THREADS'},
+ {hascallstatement: ''' #callstatement#;
+ /*(*f2py_func)(#callfortran#);*/'''},
{l_not(l_or(hascallstatement, isdummyroutine))
- : '\t\t\t\t(*f2py_func)(#callfortran#);'},
- {isthreadsafe: '\t\t\tPy_END_ALLOW_THREADS'},
- {hasexternals: """\t\t}"""}
+ : ' (*f2py_func)(#callfortran#);'},
+ {isthreadsafe: ' Py_END_ALLOW_THREADS'},
+ {hasexternals: """ }"""}
],
'_check': l_and(issubroutine, l_not(issubroutine_wrap)),
}, { # Wrapped function
@@ -423,8 +427,8 @@ rout_rules = [
isdummyroutine: '',
},
- 'routine_def': {l_not(l_or(ismoduleroutine, isdummyroutine)): '\t{\"#name#\",-1,{{-1}},0,(char *)#F_WRAPPEDFUNC#(#name_lower#,#NAME#),(f2py_init_func)#apiname#,doc_#apiname#},',
- isdummyroutine: '\t{\"#name#\",-1,{{-1}},0,NULL,(f2py_init_func)#apiname#,doc_#apiname#},',
+ 'routine_def': {l_not(l_or(ismoduleroutine, isdummyroutine)): ' {\"#name#\",-1,{{-1}},0,(char *)#F_WRAPPEDFUNC#(#name_lower#,#NAME#),(f2py_init_func)#apiname#,doc_#apiname#},',
+ isdummyroutine: ' {\"#name#\",-1,{{-1}},0,NULL,(f2py_init_func)#apiname#,doc_#apiname#},',
},
'initf2pywraphook': {l_not(l_or(ismoduleroutine, isdummyroutine)): '''
{
@@ -441,18 +445,18 @@ rout_rules = [
'need': {l_not(l_or(ismoduleroutine, isdummyroutine)): ['F_WRAPPEDFUNC', 'F_FUNC']},
'callfortranroutine': [
{debugcapi: [
- """\tfprintf(stderr,\"debug-capi:Fortran subroutine `f2pywrap#name_lower#(#callfortran#)\'\\n\");"""]},
+ """ fprintf(stderr,\"debug-capi:Fortran subroutine `f2pywrap#name_lower#(#callfortran#)\'\\n\");"""]},
{hasexternals: """\
-\tif (#setjmpbuf#) {
-\t\tf2py_success = 0;
-\t} else {"""},
- {isthreadsafe: '\tPy_BEGIN_ALLOW_THREADS'},
+ if (#setjmpbuf#) {
+ f2py_success = 0;
+ } else {"""},
+ {isthreadsafe: ' Py_BEGIN_ALLOW_THREADS'},
{l_not(l_or(hascallstatement, isdummyroutine))
- : '\t(*f2py_func)(#callfortran#);'},
+ : ' (*f2py_func)(#callfortran#);'},
{hascallstatement:
- '\t#callstatement#;\n\t/*(*f2py_func)(#callfortran#);*/'},
- {isthreadsafe: '\tPy_END_ALLOW_THREADS'},
- {hasexternals: '\t}'}
+ ' #callstatement#;\n /*(*f2py_func)(#callfortran#);*/'},
+ {isthreadsafe: ' Py_END_ALLOW_THREADS'},
+ {hasexternals: ' }'}
],
'_check': isfunction_wrap,
}, { # Wrapped subroutine
@@ -461,8 +465,8 @@ rout_rules = [
isdummyroutine: '',
},
- 'routine_def': {l_not(l_or(ismoduleroutine, isdummyroutine)): '\t{\"#name#\",-1,{{-1}},0,(char *)#F_WRAPPEDFUNC#(#name_lower#,#NAME#),(f2py_init_func)#apiname#,doc_#apiname#},',
- isdummyroutine: '\t{\"#name#\",-1,{{-1}},0,NULL,(f2py_init_func)#apiname#,doc_#apiname#},',
+ 'routine_def': {l_not(l_or(ismoduleroutine, isdummyroutine)): ' {\"#name#\",-1,{{-1}},0,(char *)#F_WRAPPEDFUNC#(#name_lower#,#NAME#),(f2py_init_func)#apiname#,doc_#apiname#},',
+ isdummyroutine: ' {\"#name#\",-1,{{-1}},0,NULL,(f2py_init_func)#apiname#,doc_#apiname#},',
},
'initf2pywraphook': {l_not(l_or(ismoduleroutine, isdummyroutine)): '''
{
@@ -479,18 +483,18 @@ rout_rules = [
'need': {l_not(l_or(ismoduleroutine, isdummyroutine)): ['F_WRAPPEDFUNC', 'F_FUNC']},
'callfortranroutine': [
{debugcapi: [
- """\tfprintf(stderr,\"debug-capi:Fortran subroutine `f2pywrap#name_lower#(#callfortran#)\'\\n\");"""]},
+ """ fprintf(stderr,\"debug-capi:Fortran subroutine `f2pywrap#name_lower#(#callfortran#)\'\\n\");"""]},
{hasexternals: """\
-\tif (#setjmpbuf#) {
-\t\tf2py_success = 0;
-\t} else {"""},
- {isthreadsafe: '\tPy_BEGIN_ALLOW_THREADS'},
+ if (#setjmpbuf#) {
+ f2py_success = 0;
+ } else {"""},
+ {isthreadsafe: ' Py_BEGIN_ALLOW_THREADS'},
{l_not(l_or(hascallstatement, isdummyroutine))
- : '\t(*f2py_func)(#callfortran#);'},
+ : ' (*f2py_func)(#callfortran#);'},
{hascallstatement:
- '\t#callstatement#;\n\t/*(*f2py_func)(#callfortran#);*/'},
- {isthreadsafe: '\tPy_END_ALLOW_THREADS'},
- {hasexternals: '\t}'}
+ ' #callstatement#;\n /*(*f2py_func)(#callfortran#);*/'},
+ {isthreadsafe: ' Py_END_ALLOW_THREADS'},
+ {hasexternals: ' }'}
],
'_check': issubroutine_wrap,
}, { # Function
@@ -501,13 +505,13 @@ rout_rules = [
{hasresultnote: '--- #resultnote#'}],
'callfortranroutine': [{l_and(debugcapi, isstringfunction): """\
#ifdef USESCOMPAQFORTRAN
-\tfprintf(stderr,\"debug-capi:Fortran function #ctype# #fortranname#(#callcompaqfortran#)\\n\");
+ fprintf(stderr,\"debug-capi:Fortran function #ctype# #fortranname#(#callcompaqfortran#)\\n\");
#else
-\tfprintf(stderr,\"debug-capi:Fortran function #ctype# #fortranname#(#callfortran#)\\n\");
+ fprintf(stderr,\"debug-capi:Fortran function #ctype# #fortranname#(#callfortran#)\\n\");
#endif
"""},
{l_and(debugcapi, l_not(isstringfunction)): """\
-\tfprintf(stderr,\"debug-capi:Fortran function #ctype# #fortranname#(#callfortran#)\\n\");
+ fprintf(stderr,\"debug-capi:Fortran function #ctype# #fortranname#(#callfortran#)\\n\");
"""}
],
'_check': l_and(isfunction, l_not(isfunction_wrap))
@@ -516,32 +520,32 @@ rout_rules = [
l_and(l_not(ismoduleroutine), isintent_c, l_not(isdummyroutine)): 'extern #ctype# #fortranname#(#callprotoargument#);',
isdummyroutine: ''
},
- 'routine_def': {l_and(l_not(l_or(ismoduleroutine, isintent_c)), l_not(isdummyroutine)): '\t{\"#name#\",-1,{{-1}},0,(char *)#F_FUNC#(#fortranname#,#FORTRANNAME#),(f2py_init_func)#apiname#,doc_#apiname#},',
- l_and(l_not(ismoduleroutine), isintent_c, l_not(isdummyroutine)): '\t{\"#name#\",-1,{{-1}},0,(char *)#fortranname#,(f2py_init_func)#apiname#,doc_#apiname#},',
- isdummyroutine: '\t{\"#name#\",-1,{{-1}},0,NULL,(f2py_init_func)#apiname#,doc_#apiname#},',
+ 'routine_def': {l_and(l_not(l_or(ismoduleroutine, isintent_c)), l_not(isdummyroutine)): ' {\"#name#\",-1,{{-1}},0,(char *)#F_FUNC#(#fortranname#,#FORTRANNAME#),(f2py_init_func)#apiname#,doc_#apiname#},',
+ l_and(l_not(ismoduleroutine), isintent_c, l_not(isdummyroutine)): ' {\"#name#\",-1,{{-1}},0,(char *)#fortranname#,(f2py_init_func)#apiname#,doc_#apiname#},',
+ isdummyroutine: ' {\"#name#\",-1,{{-1}},0,NULL,(f2py_init_func)#apiname#,doc_#apiname#},',
},
- 'decl': [{iscomplexfunction_warn: '\t#ctype# #name#_return_value={0,0};',
- l_not(iscomplexfunction): '\t#ctype# #name#_return_value=0;'},
+ 'decl': [{iscomplexfunction_warn: ' #ctype# #name#_return_value={0,0};',
+ l_not(iscomplexfunction): ' #ctype# #name#_return_value=0;'},
{iscomplexfunction:
- '\tPyObject *#name#_return_value_capi = Py_None;'}
+ ' PyObject *#name#_return_value_capi = Py_None;'}
],
'callfortranroutine': [
{hasexternals: """\
-\tif (#setjmpbuf#) {
-\t\tf2py_success = 0;
-\t} else {"""},
- {isthreadsafe: '\tPy_BEGIN_ALLOW_THREADS'},
- {hascallstatement: '''\t#callstatement#;
-/*\t#name#_return_value = (*f2py_func)(#callfortran#);*/
+ if (#setjmpbuf#) {
+ f2py_success = 0;
+ } else {"""},
+ {isthreadsafe: ' Py_BEGIN_ALLOW_THREADS'},
+ {hascallstatement: ''' #callstatement#;
+/* #name#_return_value = (*f2py_func)(#callfortran#);*/
'''},
{l_not(l_or(hascallstatement, isdummyroutine))
- : '\t#name#_return_value = (*f2py_func)(#callfortran#);'},
- {isthreadsafe: '\tPy_END_ALLOW_THREADS'},
- {hasexternals: '\t}'},
+ : ' #name#_return_value = (*f2py_func)(#callfortran#);'},
+ {isthreadsafe: ' Py_END_ALLOW_THREADS'},
+ {hasexternals: ' }'},
{l_and(debugcapi, iscomplexfunction)
- : '\tfprintf(stderr,"#routdebugshowvalue#\\n",#name#_return_value.r,#name#_return_value.i);'},
- {l_and(debugcapi, l_not(iscomplexfunction)): '\tfprintf(stderr,"#routdebugshowvalue#\\n",#name#_return_value);'}],
- 'pyobjfrom': {iscomplexfunction: '\t#name#_return_value_capi = pyobj_from_#ctype#1(#name#_return_value);'},
+ : ' fprintf(stderr,"#routdebugshowvalue#\\n",#name#_return_value.r,#name#_return_value.i);'},
+ {l_and(debugcapi, l_not(iscomplexfunction)): ' fprintf(stderr,"#routdebugshowvalue#\\n",#name#_return_value);'}],
+ 'pyobjfrom': {iscomplexfunction: ' #name#_return_value_capi = pyobj_from_#ctype#1(#name#_return_value);'},
'need': [{l_not(isdummyroutine): 'F_FUNC'},
{iscomplexfunction: 'pyobj_from_#ctype#1'},
{islong_longfunction: 'long_long'},
@@ -553,50 +557,50 @@ rout_rules = [
}, { # String function # in use for --no-wrap
'declfortranroutine': 'extern void #F_FUNC#(#fortranname#,#FORTRANNAME#)(#callprotoargument#);',
'routine_def': {l_not(l_or(ismoduleroutine, isintent_c)):
- '\t{\"#name#\",-1,{{-1}},0,(char *)#F_FUNC#(#fortranname#,#FORTRANNAME#),(f2py_init_func)#apiname#,doc_#apiname#},',
+ ' {\"#name#\",-1,{{-1}},0,(char *)#F_FUNC#(#fortranname#,#FORTRANNAME#),(f2py_init_func)#apiname#,doc_#apiname#},',
l_and(l_not(ismoduleroutine), isintent_c):
- '\t{\"#name#\",-1,{{-1}},0,(char *)#fortranname#,(f2py_init_func)#apiname#,doc_#apiname#},'
+ ' {\"#name#\",-1,{{-1}},0,(char *)#fortranname#,(f2py_init_func)#apiname#,doc_#apiname#},'
},
- 'decl': ['\t#ctype# #name#_return_value = NULL;',
- '\tint #name#_return_value_len = 0;'],
+ 'decl': [' #ctype# #name#_return_value = NULL;',
+ ' int #name#_return_value_len = 0;'],
'callfortran':'#name#_return_value,#name#_return_value_len,',
- 'callfortranroutine':['\t#name#_return_value_len = #rlength#;',
- '\tif ((#name#_return_value = (string)malloc('
- '#name#_return_value_len+1) == NULL) {',
- '\t\tPyErr_SetString(PyExc_MemoryError, \"out of memory\");',
- '\t\tf2py_success = 0;',
- '\t} else {',
- "\t\t(#name#_return_value)[#name#_return_value_len] = '\\0';",
- '\t}',
- '\tif (f2py_success) {',
+ 'callfortranroutine':[' #name#_return_value_len = #rlength#;',
+ ' if ((#name#_return_value = (string)malloc('
+ + '#name#_return_value_len+1) == NULL) {',
+ ' PyErr_SetString(PyExc_MemoryError, \"out of memory\");',
+ ' f2py_success = 0;',
+ ' } else {',
+ " (#name#_return_value)[#name#_return_value_len] = '\\0';",
+ ' }',
+ ' if (f2py_success) {',
{hasexternals: """\
-\t\tif (#setjmpbuf#) {
-\t\t\tf2py_success = 0;
-\t\t} else {"""},
- {isthreadsafe: '\t\tPy_BEGIN_ALLOW_THREADS'},
+ if (#setjmpbuf#) {
+ f2py_success = 0;
+ } else {"""},
+ {isthreadsafe: ' Py_BEGIN_ALLOW_THREADS'},
"""\
#ifdef USESCOMPAQFORTRAN
-\t\t(*f2py_func)(#callcompaqfortran#);
+ (*f2py_func)(#callcompaqfortran#);
#else
-\t\t(*f2py_func)(#callfortran#);
+ (*f2py_func)(#callfortran#);
#endif
""",
- {isthreadsafe: '\t\tPy_END_ALLOW_THREADS'},
- {hasexternals: '\t\t}'},
+ {isthreadsafe: ' Py_END_ALLOW_THREADS'},
+ {hasexternals: ' }'},
{debugcapi:
- '\t\tfprintf(stderr,"#routdebugshowvalue#\\n",#name#_return_value_len,#name#_return_value);'},
- '\t} /* if (f2py_success) after (string)malloc */',
+ ' fprintf(stderr,"#routdebugshowvalue#\\n",#name#_return_value_len,#name#_return_value);'},
+ ' } /* if (f2py_success) after (string)malloc */',
],
'returnformat': '#rformat#',
'return': ',#name#_return_value',
- 'freemem': '\tSTRINGFREE(#name#_return_value);',
+ 'freemem': ' STRINGFREE(#name#_return_value);',
'need': ['F_FUNC', '#ctype#', 'STRINGFREE'],
'_check':l_and(isstringfunction, l_not(isfunction_wrap)) # ???obsolete
},
{ # Debugging
- 'routdebugenter': '\tfprintf(stderr,"debug-capi:Python C/API function #modulename#.#name#(#docsignature#)\\n");',
- 'routdebugleave': '\tfprintf(stderr,"debug-capi:Python C/API function #modulename#.#name#: successful.\\n");',
- 'routdebugfailure': '\tfprintf(stderr,"debug-capi:Python C/API function #modulename#.#name#: failure.\\n");',
+ 'routdebugenter': ' fprintf(stderr,"debug-capi:Python C/API function #modulename#.#name#(#docsignature#)\\n");',
+ 'routdebugleave': ' fprintf(stderr,"debug-capi:Python C/API function #modulename#.#name#: successful.\\n");',
+ 'routdebugfailure': ' fprintf(stderr,"debug-capi:Python C/API function #modulename#.#name#: failure.\\n");',
'_check': debugcapi
}
]
@@ -621,16 +625,16 @@ aux_rules = [
'separatorsfor': sepdict
},
{ # Common
- 'frompyobj': ['\t/* Processing auxiliary variable #varname# */',
- {debugcapi: '\tfprintf(stderr,"#vardebuginfo#\\n");'}, ],
- 'cleanupfrompyobj': '\t/* End of cleaning variable #varname# */',
+ 'frompyobj': [' /* Processing auxiliary variable #varname# */',
+ {debugcapi: ' fprintf(stderr,"#vardebuginfo#\\n");'}, ],
+ 'cleanupfrompyobj': ' /* End of cleaning variable #varname# */',
'need': typedef_need_dict,
},
# Scalars (not complex)
{ # Common
- 'decl': '\t#ctype# #varname# = 0;',
+ 'decl': ' #ctype# #varname# = 0;',
'need': {hasinitvalue: 'math.h'},
- 'frompyobj': {hasinitvalue: '\t#varname# = #init#;'},
+ 'frompyobj': {hasinitvalue: ' #varname# = #init#;'},
'_check': l_and(isscalar, l_not(iscomplex)),
},
{
@@ -642,23 +646,23 @@ aux_rules = [
},
# Complex scalars
{ # Common
- 'decl': '\t#ctype# #varname#;',
- 'frompyobj': {hasinitvalue: '\t#varname#.r = #init.r#, #varname#.i = #init.i#;'},
+ 'decl': ' #ctype# #varname#;',
+ 'frompyobj': {hasinitvalue: ' #varname#.r = #init.r#, #varname#.i = #init.i#;'},
'_check': iscomplex
},
# String
{ # Common
- 'decl': ['\t#ctype# #varname# = NULL;',
- '\tint slen(#varname#);',
+ 'decl': [' #ctype# #varname# = NULL;',
+ ' int slen(#varname#);',
],
'need':['len..'],
'_check':isstring
},
# Array
{ # Common
- 'decl': ['\t#ctype# *#varname# = NULL;',
- '\tnpy_intp #varname#_Dims[#rank#] = {#rank*[-1]#};',
- '\tconst int #varname#_Rank = #rank#;',
+ 'decl': [' #ctype# *#varname# = NULL;',
+ ' npy_intp #varname#_Dims[#rank#] = {#rank*[-1]#};',
+ ' const int #varname#_Rank = #rank#;',
],
'need':['len..', {hasinitvalue: 'forcomb'}, {hasinitvalue: 'CFUNCSMESS'}],
'_check': isarray
@@ -707,9 +711,9 @@ arg_rules = [
'separatorsfor': sepdict
},
{ # Common
- 'frompyobj': ['\t/* Processing variable #varname# */',
- {debugcapi: '\tfprintf(stderr,"#vardebuginfo#\\n");'}, ],
- 'cleanupfrompyobj': '\t/* End of cleaning variable #varname# */',
+ 'frompyobj': [' /* Processing variable #varname# */',
+ {debugcapi: ' fprintf(stderr,"#vardebuginfo#\\n");'}, ],
+ 'cleanupfrompyobj': ' /* End of cleaning variable #varname# */',
'_depend': '',
'need': typedef_need_dict,
},
@@ -828,8 +832,8 @@ if (#varname#_cb.capi==Py_None) {
},
# Scalars (not complex)
{ # Common
- 'decl': '\t#ctype# #varname# = 0;',
- 'pyobjfrom': {debugcapi: '\tfprintf(stderr,"#vardebugshowvalue#\\n",#varname#);'},
+ 'decl': ' #ctype# #varname# = 0;',
+ 'pyobjfrom': {debugcapi: ' fprintf(stderr,"#vardebugshowvalue#\\n",#varname#);'},
'callfortran': {isintent_c: '#varname#,', l_not(isintent_c): '&#varname#,'},
'return': {isintent_out: ',#varname#'},
'_check': l_and(isscalar, l_not(iscomplex))
@@ -837,15 +841,15 @@ if (#varname#_cb.capi==Py_None) {
'need': {hasinitvalue: 'math.h'},
'_check': l_and(isscalar, l_not(iscomplex)),
}, { # Not hidden
- 'decl': '\tPyObject *#varname#_capi = Py_None;',
+ 'decl': ' PyObject *#varname#_capi = Py_None;',
'argformat': {isrequired: 'O'},
'keyformat': {isoptional: 'O'},
'args_capi': {isrequired: ',&#varname#_capi'},
'keys_capi': {isoptional: ',&#varname#_capi'},
'pyobjfrom': {isintent_inout: """\
-\tf2py_success = try_pyarr_from_#ctype#(#varname#_capi,&#varname#);
-\tif (f2py_success) {"""},
- 'closepyobjfrom': {isintent_inout: "\t} /*if (f2py_success) of #varname# pyobjfrom*/"},
+ f2py_success = try_pyarr_from_#ctype#(#varname#_capi,&#varname#);
+ if (f2py_success) {"""},
+ 'closepyobjfrom': {isintent_inout: " } /*if (f2py_success) of #varname# pyobjfrom*/"},
'need': {isintent_inout: 'try_pyarr_from_#ctype#'},
'_check': l_and(isscalar, l_not(iscomplex), isintent_nothide)
}, {
@@ -865,91 +869,91 @@ if (#varname#_cb.capi==Py_None) {
# ...
# from_pyobj(varname)
#
- {hasinitvalue: '\tif (#varname#_capi == Py_None) #varname# = #init#; else',
+ {hasinitvalue: ' if (#varname#_capi == Py_None) #varname# = #init#; else',
'_depend': ''},
- {l_and(isoptional, l_not(hasinitvalue)): '\tif (#varname#_capi != Py_None)',
+ {l_and(isoptional, l_not(hasinitvalue)): ' if (#varname#_capi != Py_None)',
'_depend': ''},
{l_not(islogical): '''\
-\t\tf2py_success = #ctype#_from_pyobj(&#varname#,#varname#_capi,"#pyname#() #nth# (#varname#) can\'t be converted to #ctype#");
-\tif (f2py_success) {'''},
+ f2py_success = #ctype#_from_pyobj(&#varname#,#varname#_capi,"#pyname#() #nth# (#varname#) can\'t be converted to #ctype#");
+ if (f2py_success) {'''},
{islogical: '''\
-\t\t#varname# = (#ctype#)PyObject_IsTrue(#varname#_capi);
-\t\tf2py_success = 1;
-\tif (f2py_success) {'''},
+ #varname# = (#ctype#)PyObject_IsTrue(#varname#_capi);
+ f2py_success = 1;
+ if (f2py_success) {'''},
],
- 'cleanupfrompyobj': '\t} /*if (f2py_success) of #varname#*/',
+ 'cleanupfrompyobj': ' } /*if (f2py_success) of #varname#*/',
'need': {l_not(islogical): '#ctype#_from_pyobj'},
'_check': l_and(isscalar, l_not(iscomplex), isintent_nothide),
'_depend': ''
}, { # Hidden
- 'frompyobj': {hasinitvalue: '\t#varname# = #init#;'},
+ 'frompyobj': {hasinitvalue: ' #varname# = #init#;'},
'need': typedef_need_dict,
'_check': l_and(isscalar, l_not(iscomplex), isintent_hide),
'_depend': ''
}, { # Common
- 'frompyobj': {debugcapi: '\tfprintf(stderr,"#vardebugshowvalue#\\n",#varname#);'},
+ 'frompyobj': {debugcapi: ' fprintf(stderr,"#vardebugshowvalue#\\n",#varname#);'},
'_check': l_and(isscalar, l_not(iscomplex)),
'_depend': ''
},
# Complex scalars
{ # Common
- 'decl': '\t#ctype# #varname#;',
+ 'decl': ' #ctype# #varname#;',
'callfortran': {isintent_c: '#varname#,', l_not(isintent_c): '&#varname#,'},
- 'pyobjfrom': {debugcapi: '\tfprintf(stderr,"#vardebugshowvalue#\\n",#varname#.r,#varname#.i);'},
+ 'pyobjfrom': {debugcapi: ' fprintf(stderr,"#vardebugshowvalue#\\n",#varname#.r,#varname#.i);'},
'return': {isintent_out: ',#varname#_capi'},
'_check': iscomplex
}, { # Not hidden
- 'decl': '\tPyObject *#varname#_capi = Py_None;',
+ 'decl': ' PyObject *#varname#_capi = Py_None;',
'argformat': {isrequired: 'O'},
'keyformat': {isoptional: 'O'},
'args_capi': {isrequired: ',&#varname#_capi'},
'keys_capi': {isoptional: ',&#varname#_capi'},
'need': {isintent_inout: 'try_pyarr_from_#ctype#'},
'pyobjfrom': {isintent_inout: """\
-\t\tf2py_success = try_pyarr_from_#ctype#(#varname#_capi,&#varname#);
-\t\tif (f2py_success) {"""},
- 'closepyobjfrom': {isintent_inout: "\t\t} /*if (f2py_success) of #varname# pyobjfrom*/"},
+ f2py_success = try_pyarr_from_#ctype#(#varname#_capi,&#varname#);
+ if (f2py_success) {"""},
+ 'closepyobjfrom': {isintent_inout: " } /*if (f2py_success) of #varname# pyobjfrom*/"},
'_check': l_and(iscomplex, isintent_nothide)
}, {
- 'frompyobj': [{hasinitvalue: '\tif (#varname#_capi==Py_None) {#varname#.r = #init.r#, #varname#.i = #init.i#;} else'},
+ 'frompyobj': [{hasinitvalue: ' if (#varname#_capi==Py_None) {#varname#.r = #init.r#, #varname#.i = #init.i#;} else'},
{l_and(isoptional, l_not(hasinitvalue))
- : '\tif (#varname#_capi != Py_None)'},
- '\t\tf2py_success = #ctype#_from_pyobj(&#varname#,#varname#_capi,"#pyname#() #nth# (#varname#) can\'t be converted to #ctype#");'
- '\n\tif (f2py_success) {'],
- 'cleanupfrompyobj': '\t} /*if (f2py_success) of #varname# frompyobj*/',
+ : ' if (#varname#_capi != Py_None)'},
+ ' f2py_success = #ctype#_from_pyobj(&#varname#,#varname#_capi,"#pyname#() #nth# (#varname#) can\'t be converted to #ctype#");'
+ '\n if (f2py_success) {'],
+ 'cleanupfrompyobj': ' } /*if (f2py_success) of #varname# frompyobj*/',
'need': ['#ctype#_from_pyobj'],
'_check': l_and(iscomplex, isintent_nothide),
'_depend': ''
}, { # Hidden
- 'decl': {isintent_out: '\tPyObject *#varname#_capi = Py_None;'},
+ 'decl': {isintent_out: ' PyObject *#varname#_capi = Py_None;'},
'_check': l_and(iscomplex, isintent_hide)
}, {
- 'frompyobj': {hasinitvalue: '\t#varname#.r = #init.r#, #varname#.i = #init.i#;'},
+ 'frompyobj': {hasinitvalue: ' #varname#.r = #init.r#, #varname#.i = #init.i#;'},
'_check': l_and(iscomplex, isintent_hide),
'_depend': ''
}, { # Common
- 'pyobjfrom': {isintent_out: '\t#varname#_capi = pyobj_from_#ctype#1(#varname#);'},
+ 'pyobjfrom': {isintent_out: ' #varname#_capi = pyobj_from_#ctype#1(#varname#);'},
'need': ['pyobj_from_#ctype#1'],
'_check': iscomplex
}, {
- 'frompyobj': {debugcapi: '\tfprintf(stderr,"#vardebugshowvalue#\\n",#varname#.r,#varname#.i);'},
+ 'frompyobj': {debugcapi: ' fprintf(stderr,"#vardebugshowvalue#\\n",#varname#.r,#varname#.i);'},
'_check': iscomplex,
'_depend': ''
},
# String
{ # Common
- 'decl': ['\t#ctype# #varname# = NULL;',
- '\tint slen(#varname#);',
- '\tPyObject *#varname#_capi = Py_None;'],
+ 'decl': [' #ctype# #varname# = NULL;',
+ ' int slen(#varname#);',
+ ' PyObject *#varname#_capi = Py_None;'],
'callfortran':'#varname#,',
'callfortranappend':'slen(#varname#),',
'pyobjfrom':[
{debugcapi:
- '\tfprintf(stderr,'
+ ' fprintf(stderr,'
'"#vardebugshowvalue#\\n",slen(#varname#),#varname#);'},
# The trailing null value for Fortran is blank.
{l_and(isintent_out, l_not(isintent_c)):
- "\t\tSTRINGPADN(#varname#, slen(#varname#), ' ', '\\0');"},
+ " STRINGPADN(#varname#, slen(#varname#), ' ', '\\0');"},
],
'return': {isintent_out: ',#varname#'},
'need': ['len..',
@@ -958,18 +962,18 @@ if (#varname#_cb.capi==Py_None) {
}, { # Common
'frompyobj': [
"""\
-\tslen(#varname#) = #length#;
-\tf2py_success = #ctype#_from_pyobj(&#varname#,&slen(#varname#),#init#,"""
+ slen(#varname#) = #length#;
+ f2py_success = #ctype#_from_pyobj(&#varname#,&slen(#varname#),#init#,"""
"""#varname#_capi,\"#ctype#_from_pyobj failed in converting #nth#"""
"""`#varname#\' of #pyname# to C #ctype#\");
-\tif (f2py_success) {""",
+ if (f2py_success) {""",
# The trailing null value for Fortran is blank.
{l_not(isintent_c):
- "\t\tSTRINGPADN(#varname#, slen(#varname#), '\\0', ' ');"},
+ " STRINGPADN(#varname#, slen(#varname#), '\\0', ' ');"},
],
'cleanupfrompyobj': """\
-\t\tSTRINGFREE(#varname#);
-\t} /*if (f2py_success) of #varname#*/""",
+ STRINGFREE(#varname#);
+ } /*if (f2py_success) of #varname#*/""",
'need': ['#ctype#_from_pyobj', 'len..', 'STRINGFREE',
{l_not(isintent_c): 'STRINGPADN'}],
'_check':isstring,
@@ -981,36 +985,36 @@ if (#varname#_cb.capi==Py_None) {
'keys_capi': {isoptional: ',&#varname#_capi'},
'pyobjfrom': [
{l_and(isintent_inout, l_not(isintent_c)):
- "\t\tSTRINGPADN(#varname#, slen(#varname#), ' ', '\\0');"},
+ " STRINGPADN(#varname#, slen(#varname#), ' ', '\\0');"},
{isintent_inout: '''\
-\tf2py_success = try_pyarr_from_#ctype#(#varname#_capi, #varname#,
-\t slen(#varname#));
-\tif (f2py_success) {'''}],
- 'closepyobjfrom': {isintent_inout: '\t} /*if (f2py_success) of #varname# pyobjfrom*/'},
+ f2py_success = try_pyarr_from_#ctype#(#varname#_capi, #varname#,
+ slen(#varname#));
+ if (f2py_success) {'''}],
+ 'closepyobjfrom': {isintent_inout: ' } /*if (f2py_success) of #varname# pyobjfrom*/'},
'need': {isintent_inout: 'try_pyarr_from_#ctype#',
l_and(isintent_inout, l_not(isintent_c)): 'STRINGPADN'},
'_check': l_and(isstring, isintent_nothide)
}, { # Hidden
'_check': l_and(isstring, isintent_hide)
}, {
- 'frompyobj': {debugcapi: '\tfprintf(stderr,"#vardebugshowvalue#\\n",slen(#varname#),#varname#);'},
+ 'frompyobj': {debugcapi: ' fprintf(stderr,"#vardebugshowvalue#\\n",slen(#varname#),#varname#);'},
'_check': isstring,
'_depend': ''
},
# Array
{ # Common
- 'decl': ['\t#ctype# *#varname# = NULL;',
- '\tnpy_intp #varname#_Dims[#rank#] = {#rank*[-1]#};',
- '\tconst int #varname#_Rank = #rank#;',
- '\tPyArrayObject *capi_#varname#_tmp = NULL;',
- '\tint capi_#varname#_intent = 0;',
+ 'decl': [' #ctype# *#varname# = NULL;',
+ ' npy_intp #varname#_Dims[#rank#] = {#rank*[-1]#};',
+ ' const int #varname#_Rank = #rank#;',
+ ' PyArrayObject *capi_#varname#_tmp = NULL;',
+ ' int capi_#varname#_intent = 0;',
],
'callfortran':'#varname#,',
'return':{isintent_out: ',capi_#varname#_tmp'},
'need': 'len..',
'_check': isarray
}, { # intent(overwrite) array
- 'decl': '\tint capi_overwrite_#varname# = 1;',
+ 'decl': ' int capi_overwrite_#varname# = 1;',
'kwlistxa': '"overwrite_#varname#",',
'xaformat': 'i',
'keys_xa': ',&capi_overwrite_#varname#',
@@ -1019,12 +1023,12 @@ if (#varname#_cb.capi==Py_None) {
'docstropt': 'overwrite_#varname# : input int, optional\\n Default: 1',
'_check': l_and(isarray, isintent_overwrite),
}, {
- 'frompyobj': '\tcapi_#varname#_intent |= (capi_overwrite_#varname#?0:F2PY_INTENT_COPY);',
+ 'frompyobj': ' capi_#varname#_intent |= (capi_overwrite_#varname#?0:F2PY_INTENT_COPY);',
'_check': l_and(isarray, isintent_overwrite),
'_depend': '',
},
{ # intent(copy) array
- 'decl': '\tint capi_overwrite_#varname# = 0;',
+ 'decl': ' int capi_overwrite_#varname# = 0;',
'kwlistxa': '"overwrite_#varname#",',
'xaformat': 'i',
'keys_xa': ',&capi_overwrite_#varname#',
@@ -1033,7 +1037,7 @@ if (#varname#_cb.capi==Py_None) {
'docstropt': 'overwrite_#varname# : input int, optional\\n Default: 0',
'_check': l_and(isarray, isintent_copy),
}, {
- 'frompyobj': '\tcapi_#varname#_intent |= (capi_overwrite_#varname#?0:F2PY_INTENT_COPY);',
+ 'frompyobj': ' capi_#varname#_intent |= (capi_overwrite_#varname#?0:F2PY_INTENT_COPY);',
'_check': l_and(isarray, isintent_copy),
'_depend': '',
}, {
@@ -1041,57 +1045,57 @@ if (#varname#_cb.capi==Py_None) {
'_check': isarray,
'_depend': ''
}, { # Not hidden
- 'decl': '\tPyObject *#varname#_capi = Py_None;',
+ 'decl': ' PyObject *#varname#_capi = Py_None;',
'argformat': {isrequired: 'O'},
'keyformat': {isoptional: 'O'},
'args_capi': {isrequired: ',&#varname#_capi'},
'keys_capi': {isoptional: ',&#varname#_capi'},
'_check': l_and(isarray, isintent_nothide)
}, {
- 'frompyobj': ['\t#setdims#;',
- '\tcapi_#varname#_intent |= #intent#;',
+ 'frompyobj': [' #setdims#;',
+ ' capi_#varname#_intent |= #intent#;',
{isintent_hide:
- '\tcapi_#varname#_tmp = array_from_pyobj(#atype#,#varname#_Dims,#varname#_Rank,capi_#varname#_intent,Py_None);'},
+ ' capi_#varname#_tmp = array_from_pyobj(#atype#,#varname#_Dims,#varname#_Rank,capi_#varname#_intent,Py_None);'},
{isintent_nothide:
- '\tcapi_#varname#_tmp = array_from_pyobj(#atype#,#varname#_Dims,#varname#_Rank,capi_#varname#_intent,#varname#_capi);'},
+ ' capi_#varname#_tmp = array_from_pyobj(#atype#,#varname#_Dims,#varname#_Rank,capi_#varname#_intent,#varname#_capi);'},
"""\
-\tif (capi_#varname#_tmp == NULL) {
-\t\tPyObject *exc, *val, *tb;
-\t\tPyErr_Fetch(&exc, &val, &tb);
-\t\tPyErr_SetString(exc ? exc : #modulename#_error,\"failed in converting #nth# `#varname#\' of #pyname# to C/Fortran array\" );
-\t\tnpy_PyErr_ChainExceptionsCause(exc, val, tb);
-\t} else {
-\t\t#varname# = (#ctype# *)(PyArray_DATA(capi_#varname#_tmp));
+ if (capi_#varname#_tmp == NULL) {
+ PyObject *exc, *val, *tb;
+ PyErr_Fetch(&exc, &val, &tb);
+ PyErr_SetString(exc ? exc : #modulename#_error,\"failed in converting #nth# `#varname#\' of #pyname# to C/Fortran array\" );
+ npy_PyErr_ChainExceptionsCause(exc, val, tb);
+ } else {
+ #varname# = (#ctype# *)(PyArray_DATA(capi_#varname#_tmp));
""",
{hasinitvalue: [
{isintent_nothide:
- '\tif (#varname#_capi == Py_None) {'},
- {isintent_hide: '\t{'},
- {iscomplexarray: '\t\t#ctype# capi_c;'},
+ ' if (#varname#_capi == Py_None) {'},
+ {isintent_hide: ' {'},
+ {iscomplexarray: ' #ctype# capi_c;'},
"""\
-\t\tint *_i,capi_i=0;
-\t\tCFUNCSMESS(\"#name#: Initializing #varname#=#init#\\n\");
-\t\tif (initforcomb(PyArray_DIMS(capi_#varname#_tmp),PyArray_NDIM(capi_#varname#_tmp),1)) {
-\t\t\twhile ((_i = nextforcomb()))
-\t\t\t\t#varname#[capi_i++] = #init#; /* fortran way */
-\t\t} else {
-\t\t\tPyObject *exc, *val, *tb;
-\t\t\tPyErr_Fetch(&exc, &val, &tb);
-\t\t\tPyErr_SetString(exc ? exc : #modulename#_error,\"Initialization of #nth# #varname# failed (initforcomb).\");
-\t\t\tnpy_PyErr_ChainExceptionsCause(exc, val, tb);
-\t\t\tf2py_success = 0;
-\t\t}
-\t}
-\tif (f2py_success) {"""]},
+ int *_i,capi_i=0;
+ CFUNCSMESS(\"#name#: Initializing #varname#=#init#\\n\");
+ if (initforcomb(PyArray_DIMS(capi_#varname#_tmp),PyArray_NDIM(capi_#varname#_tmp),1)) {
+ while ((_i = nextforcomb()))
+ #varname#[capi_i++] = #init#; /* fortran way */
+ } else {
+ PyObject *exc, *val, *tb;
+ PyErr_Fetch(&exc, &val, &tb);
+ PyErr_SetString(exc ? exc : #modulename#_error,\"Initialization of #nth# #varname# failed (initforcomb).\");
+ npy_PyErr_ChainExceptionsCause(exc, val, tb);
+ f2py_success = 0;
+ }
+ }
+ if (f2py_success) {"""]},
],
'cleanupfrompyobj': [ # note that this list will be reversed
- '\t} /*if (capi_#varname#_tmp == NULL) ... else of #varname#*/',
+ ' } /*if (capi_#varname#_tmp == NULL) ... else of #varname#*/',
{l_not(l_or(isintent_out, isintent_hide)): """\
-\tif((PyObject *)capi_#varname#_tmp!=#varname#_capi) {
-\t\tPy_XDECREF(capi_#varname#_tmp); }"""},
+ if((PyObject *)capi_#varname#_tmp!=#varname#_capi) {
+ Py_XDECREF(capi_#varname#_tmp); }"""},
{l_and(isintent_hide, l_not(isintent_out))
- : """\t\tPy_XDECREF(capi_#varname#_tmp);"""},
- {hasinitvalue: '\t} /*if (f2py_success) of #varname# init*/'},
+ : """ Py_XDECREF(capi_#varname#_tmp);"""},
+ {hasinitvalue: ' } /*if (f2py_success) of #varname# init*/'},
],
'_check': isarray,
'_depend': ''
@@ -1139,30 +1143,30 @@ if (#varname#_cb.capi==Py_None) {
check_rules = [
{
- 'frompyobj': {debugcapi: '\tfprintf(stderr,\"debug-capi:Checking `#check#\'\\n\");'},
+ 'frompyobj': {debugcapi: ' fprintf(stderr,\"debug-capi:Checking `#check#\'\\n\");'},
'need': 'len..'
}, {
- 'frompyobj': '\tCHECKSCALAR(#check#,\"#check#\",\"#nth# #varname#\",\"#varshowvalue#\",#varname#) {',
- 'cleanupfrompyobj': '\t} /*CHECKSCALAR(#check#)*/',
+ 'frompyobj': ' CHECKSCALAR(#check#,\"#check#\",\"#nth# #varname#\",\"#varshowvalue#\",#varname#) {',
+ 'cleanupfrompyobj': ' } /*CHECKSCALAR(#check#)*/',
'need': 'CHECKSCALAR',
'_check': l_and(isscalar, l_not(iscomplex)),
'_break': ''
}, {
- 'frompyobj': '\tCHECKSTRING(#check#,\"#check#\",\"#nth# #varname#\",\"#varshowvalue#\",#varname#) {',
- 'cleanupfrompyobj': '\t} /*CHECKSTRING(#check#)*/',
+ 'frompyobj': ' CHECKSTRING(#check#,\"#check#\",\"#nth# #varname#\",\"#varshowvalue#\",#varname#) {',
+ 'cleanupfrompyobj': ' } /*CHECKSTRING(#check#)*/',
'need': 'CHECKSTRING',
'_check': isstring,
'_break': ''
}, {
'need': 'CHECKARRAY',
- 'frompyobj': '\tCHECKARRAY(#check#,\"#check#\",\"#nth# #varname#\") {',
- 'cleanupfrompyobj': '\t} /*CHECKARRAY(#check#)*/',
+ 'frompyobj': ' CHECKARRAY(#check#,\"#check#\",\"#nth# #varname#\") {',
+ 'cleanupfrompyobj': ' } /*CHECKARRAY(#check#)*/',
'_check': isarray,
'_break': ''
}, {
'need': 'CHECKGENERIC',
- 'frompyobj': '\tCHECKGENERIC(#check#,\"#check#\",\"#nth# #varname#\") {',
- 'cleanupfrompyobj': '\t} /*CHECKGENERIC(#check#)*/',
+ 'frompyobj': ' CHECKGENERIC(#check#,\"#check#\",\"#nth# #varname#\") {',
+ 'cleanupfrompyobj': ' } /*CHECKGENERIC(#check#)*/',
}
]
@@ -1175,7 +1179,7 @@ def buildmodule(m, um):
"""
Return
"""
- outmess('\tBuilding module "%s"...\n' % (m['name']))
+ outmess(' Building module "%s"...\n' % (m['name']))
ret = {}
mod_rules = defmod_rules[:]
vrd = capi_maps.modsign2map(m)
@@ -1277,7 +1281,7 @@ def buildmodule(m, um):
ret['csrc'] = fn
with open(fn, 'w') as f:
f.write(ar['modulebody'].replace('\t', 2 * ' '))
- outmess('\tWrote C/API module "%s" to file "%s"\n' % (m['name'], fn))
+ outmess(' Wrote C/API module "%s" to file "%s"\n' % (m['name'], fn))
if options['dorestdoc']:
fn = os.path.join(
@@ -1285,7 +1289,7 @@ def buildmodule(m, um):
with open(fn, 'w') as f:
f.write('.. -*- rest -*-\n')
f.write('\n'.join(ar['restdoc']))
- outmess('\tReST Documentation is saved to file "%s/%smodule.rest"\n' %
+ outmess(' ReST Documentation is saved to file "%s/%smodule.rest"\n' %
(options['buildpath'], vrd['modulename']))
if options['dolatexdoc']:
fn = os.path.join(
@@ -1300,7 +1304,7 @@ def buildmodule(m, um):
f.write('\n'.join(ar['latexdoc']))
if 'shortlatex' not in options:
f.write('\\end{document}')
- outmess('\tDocumentation is saved to file "%s/%smodule.tex"\n' %
+ outmess(' Documentation is saved to file "%s/%smodule.tex"\n' %
(options['buildpath'], vrd['modulename']))
if funcwrappers:
wn = os.path.join(options['buildpath'], vrd['f2py_wrapper_output'])
@@ -1325,7 +1329,7 @@ def buildmodule(m, um):
lines.append(l + '\n')
lines = ''.join(lines).replace('\n &\n', '\n')
f.write(lines)
- outmess('\tFortran 77 wrappers are saved to "%s"\n' % (wn))
+ outmess(' Fortran 77 wrappers are saved to "%s"\n' % (wn))
if funcwrappers2:
wn = os.path.join(
options['buildpath'], '%s-f2pywrappers2.f90' % (vrd['modulename']))
@@ -1352,7 +1356,7 @@ def buildmodule(m, um):
lines.append(l + '\n')
lines = ''.join(lines).replace('\n &\n', '\n')
f.write(lines)
- outmess('\tFortran 90 wrappers are saved to "%s"\n' % (wn))
+ outmess(' Fortran 90 wrappers are saved to "%s"\n' % (wn))
return ret
################## Build C/API function #############
@@ -1368,10 +1372,10 @@ def buildapi(rout):
var = rout['vars']
if ismoduleroutine(rout):
- outmess('\t\t\tConstructing wrapper function "%s.%s"...\n' %
+ outmess(' Constructing wrapper function "%s.%s"...\n' %
(rout['modulename'], rout['name']))
else:
- outmess('\t\tConstructing wrapper function "%s"...\n' % (rout['name']))
+ outmess(' Constructing wrapper function "%s"...\n' % (rout['name']))
# Routine
vrd = capi_maps.routsign2map(rout)
rd = dictappend({}, vrd)
@@ -1473,9 +1477,9 @@ def buildapi(rout):
ar = applyrules(routine_rules, rd)
if ismoduleroutine(rout):
- outmess('\t\t\t %s\n' % (ar['docshort']))
+ outmess(' %s\n' % (ar['docshort']))
else:
- outmess('\t\t %s\n' % (ar['docshort']))
+ outmess(' %s\n' % (ar['docshort']))
return ar, wrap
diff --git a/numpy/f2py/setup.py b/numpy/f2py/setup.py
index 0a35db477..499609f96 100644
--- a/numpy/f2py/setup.py
+++ b/numpy/f2py/setup.py
@@ -39,8 +39,6 @@ if __name__ == "__main__":
config = configuration(top_path='')
config = config.todict()
- config['download_url'] = "http://cens.ioc.ee/projects/f2py2e/2.x"\
- "/F2PY-2-latest.tar.gz"
config['classifiers'] = [
'Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
@@ -68,6 +66,6 @@ command line tool (f2py) for generating Python C/API modules for
wrapping Fortran 77/90/95 subroutines, accessing common blocks from
Python, and calling Python functions from Fortran (call-backs).
Interfacing subroutines/data from Fortran 90/95 modules is supported.""",
- url="http://cens.ioc.ee/projects/f2py2e/",
+ url="https://numpy.org/doc/stable/f2py/",
keywords=['Fortran', 'f2py'],
**config)
diff --git a/numpy/f2py/src/fortranobject.c b/numpy/f2py/src/fortranobject.c
index b9ef18701..0b32137ef 100644
--- a/numpy/f2py/src/fortranobject.c
+++ b/numpy/f2py/src/fortranobject.c
@@ -19,7 +19,7 @@ extern "C" {
int
F2PyDict_SetItemString(PyObject *dict, char *name, PyObject *obj)
{
- if (obj==NULL) {
+ if (obj == NULL) {
fprintf(stderr, "Error loading %s\n", name);
if (PyErr_Occurred()) {
PyErr_Print();
@@ -33,21 +33,25 @@ F2PyDict_SetItemString(PyObject *dict, char *name, PyObject *obj)
/*
* Python-only fallback for thread-local callback pointers
*/
-void *F2PySwapThreadLocalCallbackPtr(char *key, void *ptr)
+void *
+F2PySwapThreadLocalCallbackPtr(char *key, void *ptr)
{
PyObject *local_dict, *value;
void *prev;
local_dict = PyThreadState_GetDict();
if (local_dict == NULL) {
- Py_FatalError("F2PySwapThreadLocalCallbackPtr: PyThreadState_GetDict failed");
+ Py_FatalError(
+ "F2PySwapThreadLocalCallbackPtr: PyThreadState_GetDict "
+ "failed");
}
value = PyDict_GetItemString(local_dict, key);
if (value != NULL) {
prev = PyLong_AsVoidPtr(value);
if (PyErr_Occurred()) {
- Py_FatalError("F2PySwapThreadLocalCallbackPtr: PyLong_AsVoidPtr failed");
+ Py_FatalError(
+ "F2PySwapThreadLocalCallbackPtr: PyLong_AsVoidPtr failed");
}
}
else {
@@ -56,11 +60,13 @@ void *F2PySwapThreadLocalCallbackPtr(char *key, void *ptr)
value = PyLong_FromVoidPtr((void *)ptr);
if (value == NULL) {
- Py_FatalError("F2PySwapThreadLocalCallbackPtr: PyLong_FromVoidPtr failed");
+ Py_FatalError(
+ "F2PySwapThreadLocalCallbackPtr: PyLong_FromVoidPtr failed");
}
if (PyDict_SetItemString(local_dict, key, value) != 0) {
- Py_FatalError("F2PySwapThreadLocalCallbackPtr: PyDict_SetItemString failed");
+ Py_FatalError(
+ "F2PySwapThreadLocalCallbackPtr: PyDict_SetItemString failed");
}
Py_DECREF(value);
@@ -68,21 +74,24 @@ void *F2PySwapThreadLocalCallbackPtr(char *key, void *ptr)
return prev;
}
-void *F2PyGetThreadLocalCallbackPtr(char *key)
+void *
+F2PyGetThreadLocalCallbackPtr(char *key)
{
PyObject *local_dict, *value;
void *prev;
local_dict = PyThreadState_GetDict();
if (local_dict == NULL) {
- Py_FatalError("F2PyGetThreadLocalCallbackPtr: PyThreadState_GetDict failed");
+ Py_FatalError(
+ "F2PyGetThreadLocalCallbackPtr: PyThreadState_GetDict failed");
}
value = PyDict_GetItemString(local_dict, key);
if (value != NULL) {
prev = PyLong_AsVoidPtr(value);
if (PyErr_Occurred()) {
- Py_FatalError("F2PyGetThreadLocalCallbackPtr: PyLong_AsVoidPtr failed");
+ Py_FatalError(
+ "F2PyGetThreadLocalCallbackPtr: PyLong_AsVoidPtr failed");
}
}
else {
@@ -94,14 +103,15 @@ void *F2PyGetThreadLocalCallbackPtr(char *key)
/************************* FortranObject *******************************/
-typedef PyObject *(*fortranfunc)(PyObject *,PyObject *,PyObject *,void *);
+typedef PyObject *(*fortranfunc)(PyObject *, PyObject *, PyObject *, void *);
PyObject *
-PyFortranObject_New(FortranDataDef* defs, f2py_void_func init) {
+PyFortranObject_New(FortranDataDef *defs, f2py_void_func init)
+{
int i;
PyFortranObject *fp = NULL;
PyObject *v = NULL;
- if (init!=NULL) { /* Initialize F90 module objects */
+ if (init != NULL) { /* Initialize F90 module objects */
(*(init))();
}
fp = PyObject_New(PyFortranObject, &PyFortran_Type);
@@ -120,46 +130,49 @@ PyFortranObject_New(FortranDataDef* defs, f2py_void_func init) {
goto fail;
}
fp->defs = defs;
- for (i=0;i<fp->len;i++) {
- if (fp->defs[i].rank == -1) { /* Is Fortran routine */
+ for (i = 0; i < fp->len; i++) {
+ if (fp->defs[i].rank == -1) { /* Is Fortran routine */
v = PyFortranObject_NewAsAttr(&(fp->defs[i]));
- if (v==NULL) {
+ if (v == NULL) {
goto fail;
}
- PyDict_SetItemString(fp->dict,fp->defs[i].name,v);
+ PyDict_SetItemString(fp->dict, fp->defs[i].name, v);
Py_XDECREF(v);
- } else
- if ((fp->defs[i].data)!=NULL) { /* Is Fortran variable or array (not allocatable) */
- if (fp->defs[i].type == NPY_STRING) {
- int n = fp->defs[i].rank-1;
- v = PyArray_New(&PyArray_Type, n, fp->defs[i].dims.d,
- NPY_STRING, NULL, fp->defs[i].data, fp->defs[i].dims.d[n],
- NPY_ARRAY_FARRAY, NULL);
- }
- else {
- v = PyArray_New(&PyArray_Type, fp->defs[i].rank, fp->defs[i].dims.d,
- fp->defs[i].type, NULL, fp->defs[i].data, 0, NPY_ARRAY_FARRAY,
- NULL);
- }
- if (v==NULL) {
- goto fail;
- }
- PyDict_SetItemString(fp->dict,fp->defs[i].name,v);
- Py_XDECREF(v);
+ }
+ else if ((fp->defs[i].data) !=
+ NULL) { /* Is Fortran variable or array (not allocatable) */
+ if (fp->defs[i].type == NPY_STRING) {
+ npy_intp n = fp->defs[i].rank - 1;
+ v = PyArray_New(&PyArray_Type, n, fp->defs[i].dims.d,
+ NPY_STRING, NULL, fp->defs[i].data,
+ fp->defs[i].dims.d[n], NPY_ARRAY_FARRAY, NULL);
+ }
+ else {
+ v = PyArray_New(&PyArray_Type, fp->defs[i].rank,
+ fp->defs[i].dims.d, fp->defs[i].type, NULL,
+ fp->defs[i].data, 0, NPY_ARRAY_FARRAY, NULL);
+ }
+ if (v == NULL) {
+ goto fail;
}
+ PyDict_SetItemString(fp->dict, fp->defs[i].name, v);
+ Py_XDECREF(v);
+ }
}
return (PyObject *)fp;
- fail:
+fail:
Py_XDECREF(fp);
return NULL;
}
PyObject *
-PyFortranObject_NewAsAttr(FortranDataDef* defs) { /* used for calling F90 module routines */
+PyFortranObject_NewAsAttr(FortranDataDef *defs)
+{ /* used for calling F90 module routines */
PyFortranObject *fp = NULL;
fp = PyObject_New(PyFortranObject, &PyFortran_Type);
- if (fp == NULL) return NULL;
- if ((fp->dict = PyDict_New())==NULL) {
+ if (fp == NULL)
+ return NULL;
+ if ((fp->dict = PyDict_New()) == NULL) {
PyObject_Del(fp);
return NULL;
}
@@ -171,18 +184,19 @@ PyFortranObject_NewAsAttr(FortranDataDef* defs) { /* used for calling F90 module
/* Fortran methods */
static void
-fortran_dealloc(PyFortranObject *fp) {
+fortran_dealloc(PyFortranObject *fp)
+{
Py_XDECREF(fp->dict);
PyObject_Del(fp);
}
-
/* Returns number of bytes consumed from buf, or -1 on error. */
static Py_ssize_t
format_def(char *buf, Py_ssize_t size, FortranDataDef def)
{
char *p = buf;
- int i, n;
+ int i;
+ npy_intp n;
n = PyOS_snprintf(p, size, "array(%" NPY_INTP_FMT, def.dims.d[0]);
if (n < 0 || n >= size) {
@@ -209,7 +223,7 @@ format_def(char *buf, Py_ssize_t size, FortranDataDef def)
if (def.data == NULL) {
static const char notalloc[] = ", not allocated";
- if ((size_t) size < sizeof(notalloc)) {
+ if ((size_t)size < sizeof(notalloc)) {
return -1;
}
memcpy(p, notalloc, sizeof(notalloc));
@@ -290,7 +304,6 @@ fortran_doc(FortranDataDef def)
p += n;
size -= n;
}
-
}
if (size <= 1) {
goto fail;
@@ -304,17 +317,20 @@ fortran_doc(FortranDataDef def)
PyMem_Free(buf);
return s;
- fail:
- fprintf(stderr, "fortranobject.c: fortran_doc: len(p)=%zd>%zd=size:"
- " too long docstring required, increase size\n",
+fail:
+ fprintf(stderr,
+ "fortranobject.c: fortran_doc: len(p)=%zd>%zd=size:"
+ " too long docstring required, increase size\n",
p - buf, origsize);
PyMem_Free(buf);
return NULL;
}
static FortranDataDef *save_def; /* save pointer of an allocatable array */
-static void set_data(char *d,npy_intp *f) { /* callback from Fortran */
- if (*f) /* In fortran f=allocated(d) */
+static void
+set_data(char *d, npy_intp *f)
+{ /* callback from Fortran */
+ if (*f) /* In fortran f=allocated(d) */
save_def->data = d;
else
save_def->data = NULL;
@@ -322,8 +338,9 @@ static void set_data(char *d,npy_intp *f) { /* callback from Fortran */
}
static PyObject *
-fortran_getattr(PyFortranObject *fp, char *name) {
- int i,j,k,flag;
+fortran_getattr(PyFortranObject *fp, char *name)
+{
+ int i, j, k, flag;
if (fp->dict != NULL) {
PyObject *v = _PyDict_GetItemStringWithError(fp->dict, name);
if (v == NULL && PyErr_Occurred()) {
@@ -334,36 +351,41 @@ fortran_getattr(PyFortranObject *fp, char *name) {
return v;
}
}
- for (i=0,j=1;i<fp->len && (j=strcmp(name,fp->defs[i].name));i++);
- if (j==0)
- if (fp->defs[i].rank!=-1) { /* F90 allocatable array */
- if (fp->defs[i].func==NULL) return NULL;
- for(k=0;k<fp->defs[i].rank;++k)
- fp->defs[i].dims.d[k]=-1;
+ for (i = 0, j = 1; i < fp->len && (j = strcmp(name, fp->defs[i].name));
+ i++)
+ ;
+ if (j == 0)
+ if (fp->defs[i].rank != -1) { /* F90 allocatable array */
+ if (fp->defs[i].func == NULL)
+ return NULL;
+ for (k = 0; k < fp->defs[i].rank; ++k) fp->defs[i].dims.d[k] = -1;
save_def = &fp->defs[i];
- (*(fp->defs[i].func))(&fp->defs[i].rank,fp->defs[i].dims.d,set_data,&flag);
- if (flag==2)
+ (*(fp->defs[i].func))(&fp->defs[i].rank, fp->defs[i].dims.d,
+ set_data, &flag);
+ if (flag == 2)
k = fp->defs[i].rank + 1;
else
k = fp->defs[i].rank;
- if (fp->defs[i].data !=NULL) { /* array is allocated */
- PyObject *v = PyArray_New(&PyArray_Type, k, fp->defs[i].dims.d,
- fp->defs[i].type, NULL, fp->defs[i].data, 0, NPY_ARRAY_FARRAY,
- NULL);
- if (v==NULL) return NULL;
+ if (fp->defs[i].data != NULL) { /* array is allocated */
+ PyObject *v = PyArray_New(
+ &PyArray_Type, k, fp->defs[i].dims.d, fp->defs[i].type,
+ NULL, fp->defs[i].data, 0, NPY_ARRAY_FARRAY, NULL);
+ if (v == NULL)
+ return NULL;
/* Py_INCREF(v); */
return v;
- } else { /* array is not allocated */
+ }
+ else { /* array is not allocated */
Py_RETURN_NONE;
}
}
- if (strcmp(name,"__dict__")==0) {
+ if (strcmp(name, "__dict__") == 0) {
Py_INCREF(fp->dict);
return fp->dict;
}
- if (strcmp(name,"__doc__")==0) {
+ if (strcmp(name, "__doc__") == 0) {
PyObject *s = PyUnicode_FromString(""), *s2, *s3;
- for (i=0;i<fp->len;i++) {
+ for (i = 0; i < fp->len; i++) {
s2 = fortran_doc(fp->defs[i]);
s3 = PyUnicode_Concat(s, s2);
Py_DECREF(s2);
@@ -374,8 +396,9 @@ fortran_getattr(PyFortranObject *fp, char *name) {
return NULL;
return s;
}
- if ((strcmp(name,"_cpointer")==0) && (fp->len==1)) {
- PyObject *cobj = F2PyCapsule_FromVoidPtr((void *)(fp->defs[0].data),NULL);
+ if ((strcmp(name, "_cpointer") == 0) && (fp->len == 1)) {
+ PyObject *cobj =
+ F2PyCapsule_FromVoidPtr((void *)(fp->defs[0].data), NULL);
if (PyDict_SetItemString(fp->dict, name, cobj))
return NULL;
return cobj;
@@ -388,51 +411,68 @@ fortran_getattr(PyFortranObject *fp, char *name) {
}
static int
-fortran_setattr(PyFortranObject *fp, char *name, PyObject *v) {
- int i,j,flag;
+fortran_setattr(PyFortranObject *fp, char *name, PyObject *v)
+{
+ int i, j, flag;
PyArrayObject *arr = NULL;
- for (i=0,j=1;i<fp->len && (j=strcmp(name,fp->defs[i].name));i++);
- if (j==0) {
- if (fp->defs[i].rank==-1) {
- PyErr_SetString(PyExc_AttributeError,"over-writing fortran routine");
+ for (i = 0, j = 1; i < fp->len && (j = strcmp(name, fp->defs[i].name));
+ i++)
+ ;
+ if (j == 0) {
+ if (fp->defs[i].rank == -1) {
+ PyErr_SetString(PyExc_AttributeError,
+ "over-writing fortran routine");
return -1;
}
- if (fp->defs[i].func!=NULL) { /* is allocatable array */
+ if (fp->defs[i].func != NULL) { /* is allocatable array */
npy_intp dims[F2PY_MAX_DIMS];
int k;
save_def = &fp->defs[i];
- if (v!=Py_None) { /* set new value (reallocate if needed --
- see f2py generated code for more
- details ) */
- for(k=0;k<fp->defs[i].rank;k++) dims[k]=-1;
- if ((arr = array_from_pyobj(fp->defs[i].type,dims,fp->defs[i].rank,F2PY_INTENT_IN,v))==NULL)
+ if (v != Py_None) { /* set new value (reallocate if needed --
+ see f2py generated code for more
+ details ) */
+ for (k = 0; k < fp->defs[i].rank; k++) dims[k] = -1;
+ if ((arr = array_from_pyobj(fp->defs[i].type, dims,
+ fp->defs[i].rank, F2PY_INTENT_IN,
+ v)) == NULL)
return -1;
- (*(fp->defs[i].func))(&fp->defs[i].rank,PyArray_DIMS(arr),set_data,&flag);
- } else { /* deallocate */
- for(k=0;k<fp->defs[i].rank;k++) dims[k]=0;
- (*(fp->defs[i].func))(&fp->defs[i].rank,dims,set_data,&flag);
- for(k=0;k<fp->defs[i].rank;k++) dims[k]=-1;
+ (*(fp->defs[i].func))(&fp->defs[i].rank, PyArray_DIMS(arr),
+ set_data, &flag);
+ }
+ else { /* deallocate */
+ for (k = 0; k < fp->defs[i].rank; k++) dims[k] = 0;
+ (*(fp->defs[i].func))(&fp->defs[i].rank, dims, set_data,
+ &flag);
+ for (k = 0; k < fp->defs[i].rank; k++) dims[k] = -1;
}
- memcpy(fp->defs[i].dims.d,dims,fp->defs[i].rank*sizeof(npy_intp));
- } else { /* not allocatable array */
- if ((arr = array_from_pyobj(fp->defs[i].type,fp->defs[i].dims.d,fp->defs[i].rank,F2PY_INTENT_IN,v))==NULL)
+ memcpy(fp->defs[i].dims.d, dims,
+ fp->defs[i].rank * sizeof(npy_intp));
+ }
+ else { /* not allocatable array */
+ if ((arr = array_from_pyobj(fp->defs[i].type, fp->defs[i].dims.d,
+ fp->defs[i].rank, F2PY_INTENT_IN,
+ v)) == NULL)
return -1;
}
- if (fp->defs[i].data!=NULL) { /* copy Python object to Fortran array */
- npy_intp s = PyArray_MultiplyList(fp->defs[i].dims.d,PyArray_NDIM(arr));
- if (s==-1)
- s = PyArray_MultiplyList(PyArray_DIMS(arr),PyArray_NDIM(arr));
- if (s<0 ||
- (memcpy(fp->defs[i].data,PyArray_DATA(arr),s*PyArray_ITEMSIZE(arr)))==NULL) {
- if ((PyObject*)arr!=v) {
+ if (fp->defs[i].data !=
+ NULL) { /* copy Python object to Fortran array */
+ npy_intp s = PyArray_MultiplyList(fp->defs[i].dims.d,
+ PyArray_NDIM(arr));
+ if (s == -1)
+ s = PyArray_MultiplyList(PyArray_DIMS(arr), PyArray_NDIM(arr));
+ if (s < 0 || (memcpy(fp->defs[i].data, PyArray_DATA(arr),
+ s * PyArray_ITEMSIZE(arr))) == NULL) {
+ if ((PyObject *)arr != v) {
Py_DECREF(arr);
}
return -1;
}
- if ((PyObject*)arr!=v) {
+ if ((PyObject *)arr != v) {
Py_DECREF(arr);
}
- } else return (fp->defs[i].func==NULL?-1:0);
+ }
+ else
+ return (fp->defs[i].func == NULL ? -1 : 0);
return 0; /* successful */
}
if (fp->dict == NULL) {
@@ -443,30 +483,33 @@ fortran_setattr(PyFortranObject *fp, char *name, PyObject *v) {
if (v == NULL) {
int rv = PyDict_DelItemString(fp->dict, name);
if (rv < 0)
- PyErr_SetString(PyExc_AttributeError,"delete non-existing fortran attribute");
+ PyErr_SetString(PyExc_AttributeError,
+ "delete non-existing fortran attribute");
return rv;
}
else
return PyDict_SetItemString(fp->dict, name, v);
}
-static PyObject*
-fortran_call(PyFortranObject *fp, PyObject *arg, PyObject *kw) {
+static PyObject *
+fortran_call(PyFortranObject *fp, PyObject *arg, PyObject *kw)
+{
int i = 0;
/* printf("fortran call
name=%s,func=%p,data=%p,%p\n",fp->defs[i].name,
fp->defs[i].func,fp->defs[i].data,&fp->defs[i].data); */
- if (fp->defs[i].rank==-1) {/* is Fortran routine */
- if (fp->defs[i].func==NULL) {
+ if (fp->defs[i].rank == -1) { /* is Fortran routine */
+ if (fp->defs[i].func == NULL) {
PyErr_Format(PyExc_RuntimeError, "no function to call");
return NULL;
}
- else if (fp->defs[i].data==NULL)
+ else if (fp->defs[i].data == NULL)
/* dummy routine */
- return (*((fortranfunc)(fp->defs[i].func)))((PyObject *)fp,arg,kw,NULL);
+ return (*((fortranfunc)(fp->defs[i].func)))((PyObject *)fp, arg,
+ kw, NULL);
else
- return (*((fortranfunc)(fp->defs[i].func)))((PyObject *)fp,arg,kw,
- (void *)fp->defs[i].data);
+ return (*((fortranfunc)(fp->defs[i].func)))(
+ (PyObject *)fp, arg, kw, (void *)fp->defs[i].data);
}
PyErr_Format(PyExc_TypeError, "this fortran object is not callable");
return NULL;
@@ -488,16 +531,14 @@ fortran_repr(PyFortranObject *fp)
return repr;
}
-
PyTypeObject PyFortran_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- .tp_name ="fortran",
- .tp_basicsize = sizeof(PyFortranObject),
- .tp_dealloc = (destructor)fortran_dealloc,
- .tp_getattr = (getattrfunc)fortran_getattr,
- .tp_setattr = (setattrfunc)fortran_setattr,
- .tp_repr = (reprfunc)fortran_repr,
- .tp_call = (ternaryfunc)fortran_call,
+ PyVarObject_HEAD_INIT(NULL, 0).tp_name = "fortran",
+ .tp_basicsize = sizeof(PyFortranObject),
+ .tp_dealloc = (destructor)fortran_dealloc,
+ .tp_getattr = (getattrfunc)fortran_getattr,
+ .tp_setattr = (setattrfunc)fortran_setattr,
+ .tp_repr = (reprfunc)fortran_repr,
+ .tp_call = (ternaryfunc)fortran_call,
};
/************************* f2py_report_atexit *******************************/
@@ -518,99 +559,123 @@ static struct timeb cb_stop_time;
static struct timeb cb_start_call_time;
static struct timeb cb_stop_call_time;
-extern void f2py_start_clock(void) { ftime(&start_time); }
-extern
-void f2py_start_call_clock(void) {
+extern void
+f2py_start_clock(void)
+{
+ ftime(&start_time);
+}
+extern void
+f2py_start_call_clock(void)
+{
f2py_stop_clock();
ftime(&start_call_time);
}
-extern
-void f2py_stop_clock(void) {
+extern void
+f2py_stop_clock(void)
+{
ftime(&stop_time);
- passed_time += 1000*(stop_time.time - start_time.time);
+ passed_time += 1000 * (stop_time.time - start_time.time);
passed_time += stop_time.millitm - start_time.millitm;
}
-extern
-void f2py_stop_call_clock(void) {
+extern void
+f2py_stop_call_clock(void)
+{
ftime(&stop_call_time);
- passed_call_time += 1000*(stop_call_time.time - start_call_time.time);
+ passed_call_time += 1000 * (stop_call_time.time - start_call_time.time);
passed_call_time += stop_call_time.millitm - start_call_time.millitm;
passed_counter += 1;
f2py_start_clock();
}
-extern void f2py_cb_start_clock(void) { ftime(&cb_start_time); }
-extern
-void f2py_cb_start_call_clock(void) {
+extern void
+f2py_cb_start_clock(void)
+{
+ ftime(&cb_start_time);
+}
+extern void
+f2py_cb_start_call_clock(void)
+{
f2py_cb_stop_clock();
ftime(&cb_start_call_time);
}
-extern
-void f2py_cb_stop_clock(void) {
+extern void
+f2py_cb_stop_clock(void)
+{
ftime(&cb_stop_time);
- cb_passed_time += 1000*(cb_stop_time.time - cb_start_time.time);
+ cb_passed_time += 1000 * (cb_stop_time.time - cb_start_time.time);
cb_passed_time += cb_stop_time.millitm - cb_start_time.millitm;
}
-extern
-void f2py_cb_stop_call_clock(void) {
+extern void
+f2py_cb_stop_call_clock(void)
+{
ftime(&cb_stop_call_time);
- cb_passed_call_time += 1000*(cb_stop_call_time.time - cb_start_call_time.time);
- cb_passed_call_time += cb_stop_call_time.millitm - cb_start_call_time.millitm;
+ cb_passed_call_time +=
+ 1000 * (cb_stop_call_time.time - cb_start_call_time.time);
+ cb_passed_call_time +=
+ cb_stop_call_time.millitm - cb_start_call_time.millitm;
cb_passed_counter += 1;
f2py_cb_start_clock();
}
static int f2py_report_on_exit_been_here = 0;
-extern
-void f2py_report_on_exit(int exit_flag,void *name) {
+extern void
+f2py_report_on_exit(int exit_flag, void *name)
+{
if (f2py_report_on_exit_been_here) {
- fprintf(stderr," %s\n",(char*)name);
+ fprintf(stderr, " %s\n", (char *)name);
return;
}
f2py_report_on_exit_been_here = 1;
- fprintf(stderr," /-----------------------\\\n");
- fprintf(stderr," < F2PY performance report >\n");
- fprintf(stderr," \\-----------------------/\n");
- fprintf(stderr,"Overall time spent in ...\n");
- fprintf(stderr,"(a) wrapped (Fortran/C) functions : %8d msec\n",
+ fprintf(stderr, " /-----------------------\\\n");
+ fprintf(stderr, " < F2PY performance report >\n");
+ fprintf(stderr, " \\-----------------------/\n");
+ fprintf(stderr, "Overall time spent in ...\n");
+ fprintf(stderr, "(a) wrapped (Fortran/C) functions : %8d msec\n",
passed_call_time);
- fprintf(stderr,"(b) f2py interface, %6d calls : %8d msec\n",
- passed_counter,passed_time);
- fprintf(stderr,"(c) call-back (Python) functions : %8d msec\n",
+ fprintf(stderr, "(b) f2py interface, %6d calls : %8d msec\n",
+ passed_counter, passed_time);
+ fprintf(stderr, "(c) call-back (Python) functions : %8d msec\n",
cb_passed_call_time);
- fprintf(stderr,"(d) f2py call-back interface, %6d calls : %8d msec\n",
- cb_passed_counter,cb_passed_time);
-
- fprintf(stderr,"(e) wrapped (Fortran/C) functions (actual) : %8d msec\n\n",
- passed_call_time-cb_passed_call_time-cb_passed_time);
- fprintf(stderr,"Use -DF2PY_REPORT_ATEXIT_DISABLE to disable this message.\n");
- fprintf(stderr,"Exit status: %d\n",exit_flag);
- fprintf(stderr,"Modules : %s\n",(char*)name);
+ fprintf(stderr, "(d) f2py call-back interface, %6d calls : %8d msec\n",
+ cb_passed_counter, cb_passed_time);
+
+ fprintf(stderr,
+ "(e) wrapped (Fortran/C) functions (actual) : %8d msec\n\n",
+ passed_call_time - cb_passed_call_time - cb_passed_time);
+ fprintf(stderr,
+ "Use -DF2PY_REPORT_ATEXIT_DISABLE to disable this message.\n");
+ fprintf(stderr, "Exit status: %d\n", exit_flag);
+ fprintf(stderr, "Modules : %s\n", (char *)name);
}
#endif
/********************** report on array copy ****************************/
#ifdef F2PY_REPORT_ON_ARRAY_COPY
-static void f2py_report_on_array_copy(PyArrayObject* arr) {
+static void
+f2py_report_on_array_copy(PyArrayObject *arr)
+{
const npy_intp arr_size = PyArray_Size((PyObject *)arr);
- if (arr_size>F2PY_REPORT_ON_ARRAY_COPY) {
- fprintf(stderr,"copied an array: size=%ld, elsize=%"NPY_INTP_FMT"\n",
+ if (arr_size > F2PY_REPORT_ON_ARRAY_COPY) {
+ fprintf(stderr,
+ "copied an array: size=%ld, elsize=%" NPY_INTP_FMT "\n",
arr_size, (npy_intp)PyArray_ITEMSIZE(arr));
}
}
-static void f2py_report_on_array_copy_fromany(void) {
- fprintf(stderr,"created an array from object\n");
+static void
+f2py_report_on_array_copy_fromany(void)
+{
+ fprintf(stderr, "created an array from object\n");
}
-#define F2PY_REPORT_ON_ARRAY_COPY_FROMARR f2py_report_on_array_copy((PyArrayObject *)arr)
+#define F2PY_REPORT_ON_ARRAY_COPY_FROMARR \
+ f2py_report_on_array_copy((PyArrayObject *)arr)
#define F2PY_REPORT_ON_ARRAY_COPY_FROMANY f2py_report_on_array_copy_fromany()
#else
#define F2PY_REPORT_ON_ARRAY_COPY_FROMARR
#define F2PY_REPORT_ON_ARRAY_COPY_FROMANY
#endif
-
/************************* array_from_obj *******************************/
/*
@@ -632,72 +697,82 @@ static void f2py_report_on_array_copy_fromany(void) {
* $Id: fortranobject.c,v 1.52 2005/07/11 07:44:20 pearu Exp $
*/
-static int check_and_fix_dimensions(const PyArrayObject* arr,
- const int rank,
- npy_intp *dims);
+static int
+check_and_fix_dimensions(const PyArrayObject *arr, const int rank,
+ npy_intp *dims);
static int
-count_negative_dimensions(const int rank,
- const npy_intp *dims) {
- int i=0,r=0;
- while (i<rank) {
- if (dims[i] < 0) ++r;
+count_negative_dimensions(const int rank, const npy_intp *dims)
+{
+ int i = 0, r = 0;
+ while (i < rank) {
+ if (dims[i] < 0)
+ ++r;
++i;
}
return r;
}
#ifdef DEBUG_COPY_ND_ARRAY
-void dump_dims(int rank, npy_intp const* dims) {
+void
+dump_dims(int rank, npy_intp const *dims)
+{
int i;
printf("[");
- for(i=0;i<rank;++i) {
+ for (i = 0; i < rank; ++i) {
printf("%3" NPY_INTP_FMT, dims[i]);
}
printf("]\n");
}
-void dump_attrs(const PyArrayObject* obj) {
- const PyArrayObject_fields *arr = (const PyArrayObject_fields*) obj;
+void
+dump_attrs(const PyArrayObject *obj)
+{
+ const PyArrayObject_fields *arr = (const PyArrayObject_fields *)obj;
int rank = PyArray_NDIM(arr);
npy_intp size = PyArray_Size((PyObject *)arr);
- printf("\trank = %d, flags = %d, size = %" NPY_INTP_FMT "\n",
- rank,arr->flags,size);
+ printf("\trank = %d, flags = %d, size = %" NPY_INTP_FMT "\n", rank,
+ arr->flags, size);
printf("\tstrides = ");
- dump_dims(rank,arr->strides);
+ dump_dims(rank, arr->strides);
printf("\tdimensions = ");
- dump_dims(rank,arr->dimensions);
+ dump_dims(rank, arr->dimensions);
}
#endif
-#define SWAPTYPE(a,b,t) {t c; c = (a); (a) = (b); (b) = c; }
-
-static int swap_arrays(PyArrayObject* obj1, PyArrayObject* obj2) {
- PyArrayObject_fields *arr1 = (PyArrayObject_fields*) obj1,
- *arr2 = (PyArrayObject_fields*) obj2;
- SWAPTYPE(arr1->data,arr2->data,char*);
- SWAPTYPE(arr1->nd,arr2->nd,int);
- SWAPTYPE(arr1->dimensions,arr2->dimensions,npy_intp*);
- SWAPTYPE(arr1->strides,arr2->strides,npy_intp*);
- SWAPTYPE(arr1->base,arr2->base,PyObject*);
- SWAPTYPE(arr1->descr,arr2->descr,PyArray_Descr*);
- SWAPTYPE(arr1->flags,arr2->flags,int);
+#define SWAPTYPE(a, b, t) \
+ { \
+ t c; \
+ c = (a); \
+ (a) = (b); \
+ (b) = c; \
+ }
+
+static int
+swap_arrays(PyArrayObject *obj1, PyArrayObject *obj2)
+{
+ PyArrayObject_fields *arr1 = (PyArrayObject_fields *)obj1,
+ *arr2 = (PyArrayObject_fields *)obj2;
+ SWAPTYPE(arr1->data, arr2->data, char *);
+ SWAPTYPE(arr1->nd, arr2->nd, int);
+ SWAPTYPE(arr1->dimensions, arr2->dimensions, npy_intp *);
+ SWAPTYPE(arr1->strides, arr2->strides, npy_intp *);
+ SWAPTYPE(arr1->base, arr2->base, PyObject *);
+ SWAPTYPE(arr1->descr, arr2->descr, PyArray_Descr *);
+ SWAPTYPE(arr1->flags, arr2->flags, int);
/* SWAPTYPE(arr1->weakreflist,arr2->weakreflist,PyObject*); */
return 0;
}
-#define ARRAY_ISCOMPATIBLE(arr,type_num) \
- ( (PyArray_ISINTEGER(arr) && PyTypeNum_ISINTEGER(type_num)) \
- ||(PyArray_ISFLOAT(arr) && PyTypeNum_ISFLOAT(type_num)) \
- ||(PyArray_ISCOMPLEX(arr) && PyTypeNum_ISCOMPLEX(type_num)) \
- ||(PyArray_ISBOOL(arr) && PyTypeNum_ISBOOL(type_num)) \
- )
-
-extern
-PyArrayObject* array_from_pyobj(const int type_num,
- npy_intp *dims,
- const int rank,
- const int intent,
- PyObject *obj) {
+#define ARRAY_ISCOMPATIBLE(arr, type_num) \
+ ((PyArray_ISINTEGER(arr) && PyTypeNum_ISINTEGER(type_num)) || \
+ (PyArray_ISFLOAT(arr) && PyTypeNum_ISFLOAT(type_num)) || \
+ (PyArray_ISCOMPLEX(arr) && PyTypeNum_ISCOMPLEX(type_num)) || \
+ (PyArray_ISBOOL(arr) && PyTypeNum_ISBOOL(type_num)))
+
+extern PyArrayObject *
+array_from_pyobj(const int type_num, npy_intp *dims, const int rank,
+ const int intent, PyObject *obj)
+{
/*
* Note about reference counting
* -----------------------------
@@ -716,27 +791,26 @@ PyArrayObject* array_from_pyobj(const int type_num,
char typechar;
int elsize;
- if ((intent & F2PY_INTENT_HIDE)
- || ((intent & F2PY_INTENT_CACHE) && (obj==Py_None))
- || ((intent & F2PY_OPTIONAL) && (obj==Py_None))
- ) {
+ if ((intent & F2PY_INTENT_HIDE) ||
+ ((intent & F2PY_INTENT_CACHE) && (obj == Py_None)) ||
+ ((intent & F2PY_OPTIONAL) && (obj == Py_None))) {
/* intent(cache), optional, intent(hide) */
- if (count_negative_dimensions(rank,dims) > 0) {
+ if (count_negative_dimensions(rank, dims) > 0) {
int i;
- strcpy(mess, "failed to create intent(cache|hide)|optional array"
+ strcpy(mess,
+ "failed to create intent(cache|hide)|optional array"
"-- must have defined dimensions but got (");
- for(i=0;i<rank;++i)
- sprintf(mess+strlen(mess),"%" NPY_INTP_FMT ",",dims[i]);
+ for (i = 0; i < rank; ++i)
+ sprintf(mess + strlen(mess), "%" NPY_INTP_FMT ",", dims[i]);
strcat(mess, ")");
- PyErr_SetString(PyExc_ValueError,mess);
+ PyErr_SetString(PyExc_ValueError, mess);
return NULL;
}
- arr = (PyArrayObject *)
- PyArray_New(&PyArray_Type, rank, dims, type_num,
- NULL,NULL,1,
- !(intent&F2PY_INTENT_C),
- NULL);
- if (arr==NULL) return NULL;
+ arr = (PyArrayObject *)PyArray_New(&PyArray_Type, rank, dims, type_num,
+ NULL, NULL, 1,
+ !(intent & F2PY_INTENT_C), NULL);
+ if (arr == NULL)
+ return NULL;
if (!(intent & F2PY_INTENT_CACHE))
PyArray_FILLWBYTE(arr, 0);
return arr;
@@ -760,8 +834,7 @@ PyArrayObject* array_from_pyobj(const int type_num,
if (intent & F2PY_INTENT_CACHE) {
/* intent(cache) */
- if (PyArray_ISONESEGMENT(arr)
- && PyArray_ITEMSIZE(arr)>=elsize) {
+ if (PyArray_ISONESEGMENT(arr) && PyArray_ITEMSIZE(arr) >= elsize) {
if (check_and_fix_dimensions(arr, rank, dims)) {
return NULL;
}
@@ -772,17 +845,17 @@ PyArrayObject* array_from_pyobj(const int type_num,
strcpy(mess, "failed to initialize intent(cache) array");
if (!PyArray_ISONESEGMENT(arr))
strcat(mess, " -- input must be in one segment");
- if (PyArray_ITEMSIZE(arr)<elsize)
- sprintf(mess+strlen(mess),
- " -- expected at least elsize=%d but got %" NPY_INTP_FMT,
- elsize,
- (npy_intp)PyArray_ITEMSIZE(arr)
- );
- PyErr_SetString(PyExc_ValueError,mess);
+ if (PyArray_ITEMSIZE(arr) < elsize)
+ sprintf(mess + strlen(mess),
+ " -- expected at least elsize=%d but got "
+ "%" NPY_INTP_FMT,
+ elsize, (npy_intp)PyArray_ITEMSIZE(arr));
+ PyErr_SetString(PyExc_ValueError, mess);
return NULL;
}
- /* here we have always intent(in) or intent(inout) or intent(inplace) */
+ /* here we have always intent(in) or intent(inout) or intent(inplace)
+ */
if (check_and_fix_dimensions(arr, rank, dims)) {
return NULL;
@@ -794,12 +867,12 @@ PyArrayObject* array_from_pyobj(const int type_num,
for (i=1;i<=16;i++)
printf("i=%d isaligned=%d\n", i, ARRAY_ISALIGNED(arr, i));
*/
- if ((! (intent & F2PY_INTENT_COPY))
- && PyArray_ITEMSIZE(arr)==elsize
- && ARRAY_ISCOMPATIBLE(arr,type_num)
- && F2PY_CHECK_ALIGNMENT(arr, intent)
- ) {
- if ((intent & F2PY_INTENT_C)?PyArray_ISCARRAY_RO(arr):PyArray_ISFARRAY_RO(arr)) {
+ if ((!(intent & F2PY_INTENT_COPY)) &&
+ PyArray_ITEMSIZE(arr) == elsize &&
+ ARRAY_ISCOMPATIBLE(arr, type_num) &&
+ F2PY_CHECK_ALIGNMENT(arr, intent)) {
+ if ((intent & F2PY_INTENT_C) ? PyArray_ISCARRAY_RO(arr)
+ : PyArray_ISFARRAY_RO(arr)) {
if ((intent & F2PY_INTENT_OUT)) {
Py_INCREF(arr);
}
@@ -809,36 +882,35 @@ PyArrayObject* array_from_pyobj(const int type_num,
}
if (intent & F2PY_INTENT_INOUT) {
strcpy(mess, "failed to initialize intent(inout) array");
- /* Must use PyArray_IS*ARRAY because intent(inout) requires writable input */
+ /* Must use PyArray_IS*ARRAY because intent(inout) requires
+ * writable input */
if ((intent & F2PY_INTENT_C) && !PyArray_ISCARRAY(arr))
strcat(mess, " -- input not contiguous");
if (!(intent & F2PY_INTENT_C) && !PyArray_ISFARRAY(arr))
strcat(mess, " -- input not fortran contiguous");
- if (PyArray_ITEMSIZE(arr)!=elsize)
- sprintf(mess+strlen(mess),
+ if (PyArray_ITEMSIZE(arr) != elsize)
+ sprintf(mess + strlen(mess),
" -- expected elsize=%d but got %" NPY_INTP_FMT,
- elsize,
- (npy_intp)PyArray_ITEMSIZE(arr)
- );
- if (!(ARRAY_ISCOMPATIBLE(arr,type_num)))
- sprintf(mess+strlen(mess)," -- input '%c' not compatible to '%c'",
- PyArray_DESCR(arr)->type,typechar);
+ elsize, (npy_intp)PyArray_ITEMSIZE(arr));
+ if (!(ARRAY_ISCOMPATIBLE(arr, type_num)))
+ sprintf(mess + strlen(mess),
+ " -- input '%c' not compatible to '%c'",
+ PyArray_DESCR(arr)->type, typechar);
if (!(F2PY_CHECK_ALIGNMENT(arr, intent)))
- sprintf(mess+strlen(mess)," -- input not %d-aligned", F2PY_GET_ALIGNMENT(intent));
- PyErr_SetString(PyExc_ValueError,mess);
+ sprintf(mess + strlen(mess), " -- input not %d-aligned",
+ F2PY_GET_ALIGNMENT(intent));
+ PyErr_SetString(PyExc_ValueError, mess);
return NULL;
}
/* here we have always intent(in) or intent(inplace) */
{
- PyArrayObject * retarr;
- retarr = (PyArrayObject *) \
- PyArray_New(&PyArray_Type, PyArray_NDIM(arr), PyArray_DIMS(arr), type_num,
- NULL,NULL,1,
- !(intent&F2PY_INTENT_C),
- NULL);
- if (retarr==NULL)
+ PyArrayObject *retarr;
+ retarr = (PyArrayObject *)PyArray_New(
+ &PyArray_Type, PyArray_NDIM(arr), PyArray_DIMS(arr),
+ type_num, NULL, NULL, 1, !(intent & F2PY_INTENT_C), NULL);
+ if (retarr == NULL)
return NULL;
F2PY_REPORT_ON_ARRAY_COPY_FROMARR;
if (PyArray_CopyInto(retarr, arr)) {
@@ -846,21 +918,21 @@ PyArrayObject* array_from_pyobj(const int type_num,
return NULL;
}
if (intent & F2PY_INTENT_INPLACE) {
- if (swap_arrays(arr,retarr))
+ if (swap_arrays(arr, retarr))
return NULL; /* XXX: set exception */
Py_XDECREF(retarr);
if (intent & F2PY_INTENT_OUT)
Py_INCREF(arr);
- } else {
+ }
+ else {
arr = retarr;
}
}
return arr;
}
- if ((intent & F2PY_INTENT_INOUT) ||
- (intent & F2PY_INTENT_INPLACE) ||
- (intent & F2PY_INTENT_CACHE)) {
+ if ((intent & F2PY_INTENT_INOUT) || (intent & F2PY_INTENT_INPLACE) ||
+ (intent & F2PY_INTENT_CACHE)) {
PyErr_Format(PyExc_TypeError,
"failed to initialize intent(inout|inplace|cache) "
"array, input '%s' object is not an array",
@@ -869,7 +941,7 @@ PyArrayObject* array_from_pyobj(const int type_num,
}
{
- PyArray_Descr * descr = PyArray_DescrFromType(type_num);
+ PyArray_Descr *descr = PyArray_DescrFromType(type_num);
/* compatibility with NPY_CHAR */
if (type_num == NPY_STRING) {
PyArray_DESCR_REPLACE(descr);
@@ -880,26 +952,28 @@ PyArrayObject* array_from_pyobj(const int type_num,
descr->type = NPY_CHARLTR;
}
F2PY_REPORT_ON_ARRAY_COPY_FROMANY;
- arr = (PyArrayObject *) \
- PyArray_FromAny(obj, descr, 0,0,
- ((intent & F2PY_INTENT_C)?NPY_ARRAY_CARRAY:NPY_ARRAY_FARRAY) \
- | NPY_ARRAY_FORCECAST, NULL);
- if (arr==NULL)
+ arr = (PyArrayObject *)PyArray_FromAny(
+ obj, descr, 0, 0,
+ ((intent & F2PY_INTENT_C) ? NPY_ARRAY_CARRAY
+ : NPY_ARRAY_FARRAY) |
+ NPY_ARRAY_FORCECAST,
+ NULL);
+ if (arr == NULL)
return NULL;
if (check_and_fix_dimensions(arr, rank, dims)) {
return NULL;
}
return arr;
}
-
}
/*****************************************/
/* Helper functions for array_from_pyobj */
/*****************************************/
-static
-int check_and_fix_dimensions(const PyArrayObject* arr, const int rank, npy_intp *dims)
+static int
+check_and_fix_dimensions(const PyArrayObject *arr, const int rank,
+ npy_intp *dims)
{
/*
* This function fills in blanks (that are -1's) in dims list using
@@ -908,13 +982,15 @@ int check_and_fix_dimensions(const PyArrayObject* arr, const int rank, npy_intp
*
* Returns 0 if the function is successful.
*
- * If an error condition is detected, an exception is set and 1 is returned.
+ * If an error condition is detected, an exception is set and 1 is
+ * returned.
*/
- const npy_intp arr_size = (PyArray_NDIM(arr))?PyArray_Size((PyObject *)arr):1;
+ const npy_intp arr_size =
+ (PyArray_NDIM(arr)) ? PyArray_Size((PyObject *)arr) : 1;
#ifdef DEBUG_COPY_ND_ARRAY
dump_attrs(arr);
printf("check_and_fix_dimensions:init: dims=");
- dump_dims(rank,dims);
+ dump_dims(rank, dims);
#endif
if (rank > PyArray_NDIM(arr)) { /* [1,2] -> [[1],[2]]; 1 -> [[1]] */
npy_intp new_size = 1;
@@ -922,35 +998,39 @@ int check_and_fix_dimensions(const PyArrayObject* arr, const int rank, npy_intp
int i;
npy_intp d;
/* Fill dims where -1 or 0; check dimensions; calc new_size; */
- for(i=0;i<PyArray_NDIM(arr);++i) {
- d = PyArray_DIM(arr,i);
+ for (i = 0; i < PyArray_NDIM(arr); ++i) {
+ d = PyArray_DIM(arr, i);
if (dims[i] >= 0) {
- if (d>1 && dims[i]!=d) {
- PyErr_Format(PyExc_ValueError,
- "%d-th dimension must be fixed to %"
- NPY_INTP_FMT " but got %" NPY_INTP_FMT "\n",
- i, dims[i], d);
+ if (d > 1 && dims[i] != d) {
+ PyErr_Format(
+ PyExc_ValueError,
+ "%d-th dimension must be fixed to %" NPY_INTP_FMT
+ " but got %" NPY_INTP_FMT "\n",
+ i, dims[i], d);
return 1;
}
- if (!dims[i]) dims[i] = 1;
- } else {
+ if (!dims[i])
+ dims[i] = 1;
+ }
+ else {
dims[i] = d ? d : 1;
}
new_size *= dims[i];
}
- for(i=PyArray_NDIM(arr);i<rank;++i)
- if (dims[i]>1) {
+ for (i = PyArray_NDIM(arr); i < rank; ++i)
+ if (dims[i] > 1) {
PyErr_Format(PyExc_ValueError,
"%d-th dimension must be %" NPY_INTP_FMT
" but got 0 (not defined).\n",
i, dims[i]);
return 1;
- } else if (free_axe<0)
+ }
+ else if (free_axe < 0)
free_axe = i;
else
dims[i] = 1;
- if (free_axe>=0) {
- dims[free_axe] = arr_size/new_size;
+ if (free_axe >= 0) {
+ dims[free_axe] = arr_size / new_size;
new_size *= dims[free_axe];
}
if (new_size != arr_size) {
@@ -961,22 +1041,27 @@ int check_and_fix_dimensions(const PyArrayObject* arr, const int rank, npy_intp
new_size, arr_size);
return 1;
}
- } else if (rank==PyArray_NDIM(arr)) {
+ }
+ else if (rank == PyArray_NDIM(arr)) {
npy_intp new_size = 1;
int i;
npy_intp d;
- for (i=0; i<rank; ++i) {
- d = PyArray_DIM(arr,i);
- if (dims[i]>=0) {
- if (d > 1 && d!=dims[i]) {
- PyErr_Format(PyExc_ValueError,
- "%d-th dimension must be fixed to %"
- NPY_INTP_FMT " but got %" NPY_INTP_FMT "\n",
- i, dims[i], d);
+ for (i = 0; i < rank; ++i) {
+ d = PyArray_DIM(arr, i);
+ if (dims[i] >= 0) {
+ if (d > 1 && d != dims[i]) {
+ PyErr_Format(
+ PyExc_ValueError,
+ "%d-th dimension must be fixed to %" NPY_INTP_FMT
+ " but got %" NPY_INTP_FMT "\n",
+ i, dims[i], d);
return 1;
}
- if (!dims[i]) dims[i] = 1;
- } else dims[i] = d;
+ if (!dims[i])
+ dims[i] = 1;
+ }
+ else
+ dims[i] = d;
new_size *= dims[i];
}
if (new_size != arr_size) {
@@ -986,15 +1071,17 @@ int check_and_fix_dimensions(const PyArrayObject* arr, const int rank, npy_intp
new_size, arr_size);
return 1;
}
- } else { /* [[1,2]] -> [[1],[2]] */
- int i,j;
+ }
+ else { /* [[1,2]] -> [[1],[2]] */
+ int i, j;
npy_intp d;
int effrank;
npy_intp size;
- for (i=0,effrank=0;i<PyArray_NDIM(arr);++i)
- if (PyArray_DIM(arr,i)>1) ++effrank;
- if (dims[rank-1]>=0)
- if (effrank>rank) {
+ for (i = 0, effrank = 0; i < PyArray_NDIM(arr); ++i)
+ if (PyArray_DIM(arr, i) > 1)
+ ++effrank;
+ if (dims[rank - 1] >= 0)
+ if (effrank > rank) {
PyErr_Format(PyExc_ValueError,
"too many axes: %d (effrank=%d), "
"expected rank=%d\n",
@@ -1002,31 +1089,38 @@ int check_and_fix_dimensions(const PyArrayObject* arr, const int rank, npy_intp
return 1;
}
- for (i=0,j=0;i<rank;++i) {
- while (j<PyArray_NDIM(arr) && PyArray_DIM(arr,j)<2) ++j;
- if (j>=PyArray_NDIM(arr)) d = 1;
- else d = PyArray_DIM(arr,j++);
- if (dims[i]>=0) {
- if (d>1 && d!=dims[i]) {
- PyErr_Format(PyExc_ValueError,
- "%d-th dimension must be fixed to %"
- NPY_INTP_FMT " but got %" NPY_INTP_FMT
- " (real index=%d)\n",
- i, dims[i], d, j-1);
+ for (i = 0, j = 0; i < rank; ++i) {
+ while (j < PyArray_NDIM(arr) && PyArray_DIM(arr, j) < 2) ++j;
+ if (j >= PyArray_NDIM(arr))
+ d = 1;
+ else
+ d = PyArray_DIM(arr, j++);
+ if (dims[i] >= 0) {
+ if (d > 1 && d != dims[i]) {
+ PyErr_Format(
+ PyExc_ValueError,
+ "%d-th dimension must be fixed to %" NPY_INTP_FMT
+ " but got %" NPY_INTP_FMT " (real index=%d)\n",
+ i, dims[i], d, j - 1);
return 1;
}
- if (!dims[i]) dims[i] = 1;
- } else
+ if (!dims[i])
+ dims[i] = 1;
+ }
+ else
dims[i] = d;
}
- for (i=rank;i<PyArray_NDIM(arr);++i) { /* [[1,2],[3,4]] -> [1,2,3,4] */
- while (j<PyArray_NDIM(arr) && PyArray_DIM(arr,j)<2) ++j;
- if (j>=PyArray_NDIM(arr)) d = 1;
- else d = PyArray_DIM(arr,j++);
- dims[rank-1] *= d;
+ for (i = rank; i < PyArray_NDIM(arr);
+ ++i) { /* [[1,2],[3,4]] -> [1,2,3,4] */
+ while (j < PyArray_NDIM(arr) && PyArray_DIM(arr, j) < 2) ++j;
+ if (j >= PyArray_NDIM(arr))
+ d = 1;
+ else
+ d = PyArray_DIM(arr, j++);
+ dims[rank - 1] *= d;
}
- for (i=0,size=1;i<rank;++i) size *= dims[i];
+ for (i = 0, size = 1; i < rank; ++i) size *= dims[i];
if (size != arr_size) {
char msg[200];
int len;
@@ -1037,15 +1131,15 @@ int check_and_fix_dimensions(const PyArrayObject* arr, const int rank, npy_intp
size, arr_size, rank, effrank, PyArray_NDIM(arr));
for (i = 0; i < rank; ++i) {
len = strlen(msg);
- snprintf(msg + len, sizeof(msg) - len,
- " %" NPY_INTP_FMT, dims[i]);
+ snprintf(msg + len, sizeof(msg) - len, " %" NPY_INTP_FMT,
+ dims[i]);
}
len = strlen(msg);
snprintf(msg + len, sizeof(msg) - len, " ], arr.dims=[");
for (i = 0; i < PyArray_NDIM(arr); ++i) {
len = strlen(msg);
- snprintf(msg + len, sizeof(msg) - len,
- " %" NPY_INTP_FMT, PyArray_DIM(arr, i));
+ snprintf(msg + len, sizeof(msg) - len, " %" NPY_INTP_FMT,
+ PyArray_DIM(arr, i));
}
len = strlen(msg);
snprintf(msg + len, sizeof(msg) - len, " ]\n");
@@ -1055,7 +1149,7 @@ int check_and_fix_dimensions(const PyArrayObject* arr, const int rank, npy_intp
}
#ifdef DEBUG_COPY_ND_ARRAY
printf("check_and_fix_dimensions:end: dims=");
- dump_dims(rank,dims);
+ dump_dims(rank, dims);
#endif
return 0;
}
@@ -1064,8 +1158,8 @@ int check_and_fix_dimensions(const PyArrayObject* arr, const int rank, npy_intp
/************************* copy_ND_array *******************************/
-extern
-int copy_ND_array(const PyArrayObject *arr, PyArrayObject *out)
+extern int
+copy_ND_array(const PyArrayObject *arr, PyArrayObject *out)
{
F2PY_REPORT_ON_ARRAY_COPY_FROMARR;
return PyArray_CopyInto(out, (PyArrayObject *)arr);
diff --git a/numpy/f2py/src/fortranobject.h b/numpy/f2py/src/fortranobject.h
index d4cc10243..a1e9fdbdf 100644
--- a/numpy/f2py/src/fortranobject.h
+++ b/numpy/f2py/src/fortranobject.h
@@ -4,7 +4,7 @@
extern "C" {
#endif
-#include "Python.h"
+#include <Python.h>
#ifdef FORTRANOBJECT_C
#define NO_IMPORT_ARRAY
@@ -13,18 +13,19 @@ extern "C" {
#include "numpy/arrayobject.h"
#include "numpy/npy_3kcompat.h"
-
#ifdef F2PY_REPORT_ATEXIT
#include <sys/timeb.h>
- extern void f2py_start_clock(void);
- extern void f2py_stop_clock(void);
- extern void f2py_start_call_clock(void);
- extern void f2py_stop_call_clock(void);
- extern void f2py_cb_start_clock(void);
- extern void f2py_cb_stop_clock(void);
- extern void f2py_cb_start_call_clock(void);
- extern void f2py_cb_stop_call_clock(void);
- extern void f2py_report_on_exit(int,void*);
+// clang-format off
+extern void f2py_start_clock(void);
+extern void f2py_stop_clock(void);
+extern void f2py_start_call_clock(void);
+extern void f2py_stop_call_clock(void);
+extern void f2py_cb_start_clock(void);
+extern void f2py_cb_stop_clock(void);
+extern void f2py_cb_start_call_clock(void);
+extern void f2py_cb_stop_call_clock(void);
+extern void f2py_report_on_exit(int, void *);
+// clang-format on
#endif
#ifdef DMALLOC
@@ -44,50 +45,60 @@ Author: Pearu Peterson <pearu@cens.ioc.ee>
#define F2PY_MAX_DIMS 40
-typedef void (*f2py_set_data_func)(char*,npy_intp*);
+typedef void (*f2py_set_data_func)(char *, npy_intp *);
typedef void (*f2py_void_func)(void);
-typedef void (*f2py_init_func)(int*,npy_intp*,f2py_set_data_func,int*);
+typedef void (*f2py_init_func)(int *, npy_intp *, f2py_set_data_func, int *);
- /*typedef void* (*f2py_c_func)(void*,...);*/
+/*typedef void* (*f2py_c_func)(void*,...);*/
typedef void *(*f2pycfunc)(void);
typedef struct {
- char *name; /* attribute (array||routine) name */
- int rank; /* array rank, 0 for scalar, max is F2PY_MAX_DIMS,
- || rank=-1 for Fortran routine */
- struct {npy_intp d[F2PY_MAX_DIMS];} dims; /* dimensions of the array, || not used */
- int type; /* PyArray_<type> || not used */
- char *data; /* pointer to array || Fortran routine */
- f2py_init_func func; /* initialization function for
- allocatable arrays:
- func(&rank,dims,set_ptr_func,name,len(name))
- || C/API wrapper for Fortran routine */
- char *doc; /* documentation string; only recommended
- for routines. */
+ char *name; /* attribute (array||routine) name */
+ int rank; /* array rank, 0 for scalar, max is F2PY_MAX_DIMS,
+ || rank=-1 for Fortran routine */
+ struct {
+ npy_intp d[F2PY_MAX_DIMS];
+ } dims; /* dimensions of the array, || not used */
+ int type; /* PyArray_<type> || not used */
+ char *data; /* pointer to array || Fortran routine */
+ f2py_init_func func; /* initialization function for
+ allocatable arrays:
+ func(&rank,dims,set_ptr_func,name,len(name))
+ || C/API wrapper for Fortran routine */
+ char *doc; /* documentation string; only recommended
+ for routines. */
} FortranDataDef;
typedef struct {
- PyObject_HEAD
- int len; /* Number of attributes */
- FortranDataDef *defs; /* An array of FortranDataDef's */
- PyObject *dict; /* Fortran object attribute dictionary */
+ PyObject_HEAD
+ int len; /* Number of attributes */
+ FortranDataDef *defs; /* An array of FortranDataDef's */
+ PyObject *dict; /* Fortran object attribute dictionary */
} PyFortranObject;
#define PyFortran_Check(op) (Py_TYPE(op) == &PyFortran_Type)
-#define PyFortran_Check1(op) (0==strcmp(Py_TYPE(op)->tp_name,"fortran"))
-
- extern PyTypeObject PyFortran_Type;
- extern int F2PyDict_SetItemString(PyObject* dict, char *name, PyObject *obj);
- extern PyObject * PyFortranObject_New(FortranDataDef* defs, f2py_void_func init);
- extern PyObject * PyFortranObject_NewAsAttr(FortranDataDef* defs);
-
-PyObject * F2PyCapsule_FromVoidPtr(void *ptr, void (*dtor)(PyObject *));
-void * F2PyCapsule_AsVoidPtr(PyObject *obj);
-int F2PyCapsule_Check(PyObject *ptr);
-
-extern void *F2PySwapThreadLocalCallbackPtr(char *key, void *ptr);
-extern void *F2PyGetThreadLocalCallbackPtr(char *key);
+#define PyFortran_Check1(op) (0 == strcmp(Py_TYPE(op)->tp_name, "fortran"))
+
+extern PyTypeObject PyFortran_Type;
+extern int
+F2PyDict_SetItemString(PyObject *dict, char *name, PyObject *obj);
+extern PyObject *
+PyFortranObject_New(FortranDataDef *defs, f2py_void_func init);
+extern PyObject *
+PyFortranObject_NewAsAttr(FortranDataDef *defs);
+
+PyObject *
+F2PyCapsule_FromVoidPtr(void *ptr, void (*dtor)(PyObject *));
+void *
+F2PyCapsule_AsVoidPtr(PyObject *obj);
+int
+F2PyCapsule_Check(PyObject *ptr);
+
+extern void *
+F2PySwapThreadLocalCallbackPtr(char *key, void *ptr);
+extern void *
+F2PyGetThreadLocalCallbackPtr(char *key);
#define ISCONTIGUOUS(m) (PyArray_FLAGS(m) & NPY_ARRAY_C_CONTIGUOUS)
#define F2PY_INTENT_IN 1
@@ -109,23 +120,23 @@ extern void *F2PyGetThreadLocalCallbackPtr(char *key);
#define F2PY_ALIGN16(intent) (intent & F2PY_INTENT_ALIGNED16)
#define F2PY_GET_ALIGNMENT(intent) \
- (F2PY_ALIGN4(intent) ? 4 : \
- (F2PY_ALIGN8(intent) ? 8 : \
- (F2PY_ALIGN16(intent) ? 16 : 1) ))
-#define F2PY_CHECK_ALIGNMENT(arr, intent) ARRAY_ISALIGNED(arr, F2PY_GET_ALIGNMENT(intent))
-
- extern PyArrayObject* array_from_pyobj(const int type_num,
- npy_intp *dims,
- const int rank,
- const int intent,
- PyObject *obj);
- extern int copy_ND_array(const PyArrayObject *in, PyArrayObject *out);
+ (F2PY_ALIGN4(intent) \
+ ? 4 \
+ : (F2PY_ALIGN8(intent) ? 8 : (F2PY_ALIGN16(intent) ? 16 : 1)))
+#define F2PY_CHECK_ALIGNMENT(arr, intent) \
+ ARRAY_ISALIGNED(arr, F2PY_GET_ALIGNMENT(intent))
+
+extern PyArrayObject *
+array_from_pyobj(const int type_num, npy_intp *dims, const int rank,
+ const int intent, PyObject *obj);
+extern int
+copy_ND_array(const PyArrayObject *in, PyArrayObject *out);
#ifdef DEBUG_COPY_ND_ARRAY
- extern void dump_attrs(const PyArrayObject* arr);
+extern void
+dump_attrs(const PyArrayObject *arr);
#endif
-
#ifdef __cplusplus
}
#endif
diff --git a/numpy/f2py/src/test/Makefile b/numpy/f2py/src/test/Makefile
deleted file mode 100644
index 0f8869f72..000000000
--- a/numpy/f2py/src/test/Makefile
+++ /dev/null
@@ -1,96 +0,0 @@
-# -*- makefile -*-
-# File: Makefile-foo
-# Usage:
-# make -f Makefile-foo [MODE=opt|debug]
-# Notes:
-# 1) You must use GNU make; try `gmake ..' if `make' fails.
-# 2) This file is auto-generated with f2py (version 2.264).
-# f2py is a Fortran to Python Interface Generator (FPIG), Second Edition,
-# written by Pearu Peterson <pearu@ioc.ee>.
-# See http://cens.ioc.ee/projects/f2py2e/
-# Generation date: Wed Sep 13 16:22:55 2000
-# $Revision: 1.2 $
-# $Date: 2000/09/17 16:10:27 $
-
-# Recommendation notes produced by f2py2e/buildmakefile.py:
-# ***
-
-PYINC = -I/numeric/include/python1.5/Numeric -I/numeric/include/python1.5
-INCLUDES = -I..
-LIBS = -L$(shell gcc -v 2>&1 | grep specs | sed -e 's/Reading specs from //g' | sed -e 's/\/specs//g') -lg2c
-LIBS=-L$$ABSOFT/lib -lfio -lf77math -lf90math
-LIBS=-L/numeric/bin -lvast90 -L/usr/lib/gcc-lib/i586-mandrake-linux/2.95.2 -lg2c
-
-# Wrapper generator:
-F2PY = /home/pearu/bin/f2py-cvs
-
-# Fortran compiler: Absoft f95
-FC = f95
-FC = f90
-FOPT =
-FDEBUG =
-FFLAGS = -B108 -YCFRL=1 -YCOM_NAMES=LCS -YCOM_PFX -YCOM_SFX=_ -YEXT_PFX -YEXT_NAMES=LCS
-FFLAGS =
-# C compiler: cc ('gcc 2.x.x' 2.95.2)
-CC = cc
-COPT =
-CDEBUG =
-CFLAGS = -fpic
-
-# Linker: ld ('GNU ld' 2.9.5)
-LD = ld
-LDFLAGS = -shared -s
-SO = .so
-
-ifeq '$(MODE)' 'debug'
-FFLAGS += $(FDEBUG)
-CFLAGS += $(CDEBUG)
-endif
-ifeq '$(MODE)' 'opt'
-FFLAGS += $(FOPT)
-CFLAGS += $(COPT)
-endif
-FFLAGS += $(INCLUDES)
-CFLAGS += $(PYINC) $(INCLUDES)
-
-SRCC = ../fortranobject.c
-SRCF = mod.f90 bar.f foo90.f90 wrap.f
-SRCS = $(SRCC) $(SRCF)
-OBJC = $(filter %.o,$(SRCC:.c=.o) $(SRCC:.cc=.o) $(SRCC:.C=.o))
-OBJF = $(filter %.o,$(SRCF:.f90=.o) $(SRCF:.f=.o) $(SRCF:.F=.o) $(SRCF:.for=.o))
-OBJS = $(OBJC) $(OBJF)
-
-INSTALLNAME = f2py2e-apps
-INSTALLDIRECTORY = /numeric/lib/python1.5/site-packages/$(INSTALLNAME)
-INSTALLDIR = install -d -c
-INSTALLEXEC = install -m 755 -c
-
-all: foo
-
-foo: foomodule$(SO)
-foomodule$(SO) : foomodule.o $(OBJS)
- $(LD) $(LDFLAGS) -o $@ $< $(OBJS) $(LIBS)
-
-foomodule.o: foomodule.c
-
-
-$(OBJS) : $(SRCS)
-%.o : %.f ; $(FC) -c $(FFLAGS) $<
-%.o : %.f90 ; $(FC) -c $(FFLAGS) $<
-
-test: foomodule$(SO)
- python -c 'import foo;print foo.__doc__'
-install: foomodule$(SO)
- $(INSTALLDIR) $(INSTALLDIRECTORY)
- $(INSTALLEXEC) foomodule$(SO) $(INSTALLDIRECTORY)
- cd $(INSTALLDIRECTORY) && echo "$(INSTALLNAME)" > ../$(INSTALLNAME).pth
-
-.PHONY: clean distclean debug test install foo
-debug:
- echo "OBJS=$(OBJS)"
- echo "SRCS=$(SRCS)"
-clean:
- $(RM) *.o *.mod core foomodule.{dvi,log} $(OBJS)
-distclean: clean
- $(RM) *.so *.sl foomodule.{tex,so}
- $(RM) .f2py_get_compiler_*
diff --git a/numpy/f2py/src/test/bar.f b/numpy/f2py/src/test/bar.f
deleted file mode 100644
index 5354ceaf9..000000000
--- a/numpy/f2py/src/test/bar.f
+++ /dev/null
@@ -1,11 +0,0 @@
- subroutine bar()
- integer a
- real*8 b,c(3)
- common /foodata/ a,b,c
- a = 4
- b = 6.7
- c(2) = 3.0
- write(*,*) "bar:a=",a
- write(*,*) "bar:b=",b
- write(*,*) "bar:c=",c
- end
diff --git a/numpy/f2py/src/test/foo.f b/numpy/f2py/src/test/foo.f
deleted file mode 100644
index 5354ceaf9..000000000
--- a/numpy/f2py/src/test/foo.f
+++ /dev/null
@@ -1,11 +0,0 @@
- subroutine bar()
- integer a
- real*8 b,c(3)
- common /foodata/ a,b,c
- a = 4
- b = 6.7
- c(2) = 3.0
- write(*,*) "bar:a=",a
- write(*,*) "bar:b=",b
- write(*,*) "bar:c=",c
- end
diff --git a/numpy/f2py/src/test/foo90.f90 b/numpy/f2py/src/test/foo90.f90
deleted file mode 100644
index dbca7e95b..000000000
--- a/numpy/f2py/src/test/foo90.f90
+++ /dev/null
@@ -1,13 +0,0 @@
-subroutine foo()
- integer a
- real*8 b,c(3)
- common /foodata/ a,b,c
- print*, " F: in foo"
- a = 5
- b = 6.3
- c(2) = 9.1
-end subroutine foo
-
-
-
-
diff --git a/numpy/f2py/src/test/foomodule.c b/numpy/f2py/src/test/foomodule.c
deleted file mode 100644
index 88ec62440..000000000
--- a/numpy/f2py/src/test/foomodule.c
+++ /dev/null
@@ -1,148 +0,0 @@
-/* File: foomodule.c
- * Example of FortranObject usage. See also wrap.f foo.f foo90.f90.
- * Author: Pearu Peterson <pearu@ioc.ee>.
- * http://cens.ioc.ee/projects/f2py2e/
- * $Revision: 1.2 $
- * $Date: 2000/09/17 16:10:27 $
- */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "Python.h"
-#include "fortranobject.h"
-
-static PyObject *foo_error;
-
-#if defined(NO_APPEND_FORTRAN)
-#if defined(UPPERCASE_FORTRAN)
-#define F_FUNC(f,F) F
-#else
-#define F_FUNC(f,F) f
-#endif
-#else
-#if defined(UPPERCASE_FORTRAN)
-#define F_FUNC(f,F) F##_
-#else
-#define F_FUNC(f,F) f##_
-#endif
-#endif
-
-/************* foo_bar *************/
-static char doc_foo_bar[] = "\
-Function signature:\n\
- bar()\n\
-";
-static PyObject *foo_bar(PyObject *capi_self, PyObject *capi_args,
- PyObject *capi_keywds, void (*f2py_func)()) {
- PyObject *capi_buildvalue = NULL;
- static char *capi_kwlist[] = {NULL};
- if (!PyArg_ParseTupleAndKeywords(capi_args,capi_keywds,\
- "|:foo.bar",\
- capi_kwlist))
- goto capi_fail;
- (*f2py_func)();
- capi_buildvalue = Py_BuildValue("");
- capi_fail:
- return capi_buildvalue;
-}
-/************ mod_init **************/
-static PyObject *mod_init(PyObject *capi_self, PyObject *capi_args,
- PyObject *capi_keywds, void (*f2py_func)()) {
- PyObject *capi_buildvalue = NULL;
- static char *capi_kwlist[] = {NULL};
- if (!PyArg_ParseTupleAndKeywords(capi_args,capi_keywds,\
- "|:mod.init",\
- capi_kwlist))
- goto capi_fail;
- (*f2py_func)();
- capi_buildvalue = Py_BuildValue("");
- capi_fail:
- return capi_buildvalue;
-}
-
-/* F90 module */
-static FortranDataDef f2py_mod_def[] = {
- {"a",0, {}, NPY_INT},
- {"b",0, {}, NPY_DOUBLE},
- {"c",1, {3}, NPY_DOUBLE},
- {"d",1, {-1}, NPY_DOUBLE},
- {"init",-1,{},0,NULL,(void *)mod_init},
- {NULL}
-};
-static void f2py_setup_mod(char *a,char *b,char *c,void (*d)(),char *init) {
- f2py_mod_def[0].data = a;
- f2py_mod_def[1].data = b;
- f2py_mod_def[2].data = c;
- f2py_mod_def[3].func = d;
- f2py_mod_def[4].data = init;
-}
-extern void F_FUNC(f2pyinitmod,F2PYINITMOD)();
- static void f2py_init_mod() {
- F_FUNC(f2pyinitmod,F2PYINITMOD)(f2py_setup_mod);
- }
-
-/* COMMON block */
-static FortranDataDef f2py_foodata_def[] = {
- {"a",0, {}, NPY_INT},
- {"b",0, {}, NPY_DOUBLE},
- {"c",1, {3}, NPY_DOUBLE},
- {NULL}
-};
-static void f2py_setup_foodata(char *a,char *b,char *c) {
- f2py_foodata_def[0].data = a;
- f2py_foodata_def[1].data = b;
- f2py_foodata_def[2].data = c;
-}
-extern void F_FUNC(f2pyinitfoodata,F2PYINITFOODATA)();
- static void f2py_init_foodata() {
- F_FUNC(f2pyinitfoodata,F2PYINITFOODATA)(f2py_setup_foodata);
- }
-
-/* Fortran routines (needs no initialization/setup function) */
-extern void F_FUNC(bar,BAR)();
- extern void F_FUNC(foo,FOO)();
- static FortranDataDef f2py_routines_def[] = {
- {"bar",-1, {}, 0, (char *)F_FUNC(bar,BAR),(void *)foo_bar,doc_foo_bar},
- {"foo",-1, {}, 0, (char *)F_FUNC(foo,FOO),(void *)foo_bar,doc_foo_bar},
- {NULL}
- };
-
-static PyMethodDef foo_module_methods[] = {
- /*eof method*/
- {NULL,NULL}
-};
-
-void initfoo() {
- int i;
- PyObject *m, *d, *s, *tmp;
- import_array();
-
- m = Py_InitModule("foo", foo_module_methods);
-
- d = PyModule_GetDict(m);
- s = PyUnicode_FromString("This module 'foo' demonstrates the usage of fortranobject.");
- PyDict_SetItemString(d, "__doc__", s);
-
- /* Fortran objects: */
- tmp = PyFortranObject_New(f2py_mod_def,f2py_init_mod);
- PyDict_SetItemString(d, "mod", tmp);
- Py_DECREF(tmp);
- tmp = PyFortranObject_New(f2py_foodata_def,f2py_init_foodata);
- PyDict_SetItemString(d, "foodata", tmp);
- Py_DECREF(tmp);
- for(i=0;f2py_routines_def[i].name!=NULL;i++) {
- tmp = PyFortranObject_NewAsAttr(&f2py_routines_def[i]);
- PyDict_SetItemString(d, f2py_routines_def[i].name, tmp);
- Py_DECREF(tmp);
- }
-
- Py_DECREF(s);
-
- if (PyErr_Occurred())
- Py_FatalError("can't initialize module foo");
-}
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/numpy/f2py/src/test/wrap.f b/numpy/f2py/src/test/wrap.f
deleted file mode 100644
index 9414eb9f6..000000000
--- a/numpy/f2py/src/test/wrap.f
+++ /dev/null
@@ -1,70 +0,0 @@
- subroutine f2py_mod_get_dims(f2py_r,f2py_s,f2py_set,f2py_n)
- use mod
- external f2py_set
- logical f2py_ns
- integer f2py_s(*),f2py_r,f2py_i,f2py_j
- character*(*) f2py_n
- if ("d".eq.f2py_n) then
- f2py_ns = .FALSE.
- if (allocated(d)) then
- do f2py_i=1,f2py_r
- if ((size(d,f2py_r-f2py_i+1).ne.f2py_s(f2py_i)).and.
- c (f2py_s(f2py_i).ge.0)) then
- f2py_ns = .TRUE.
- end if
- end do
- if (f2py_ns) then
- deallocate(d)
- end if
- end if
- if (.not.allocated(d)) then
- allocate(d(f2py_s(1)))
- end if
- if (allocated(d)) then
- do f2py_i=1,f2py_r
- f2py_s(f2py_i) = size(d,f2py_r-f2py_i+1)
- end do
- call f2py_set(d)
- end if
- end if
- end subroutine f2py_mod_get_dims
- subroutine f2py_mod_get_dims_d(r,s,set_data)
- use mod, only: d => d
- external set_data
- logical ns
- integer s(*),r,i,j
- ns = .FALSE.
- if (allocated(d)) then
- do i=1,r
- if ((size(d,r-i+1).ne.s(i)).and.(s(i).ge.0)) then
- ns = .TRUE.
- end if
- end do
- if (ns) then
- deallocate(d)
- end if
- end if
- if (.not.allocated(d).and.(s(1).ge.1)) then
- allocate(d(s(1)))
- end if
- if (allocated(d)) then
- do i=1,r
- s(i) = size(d,r-i+1)
- end do
- end if
- call set_data(d,allocated(d))
- end subroutine f2py_mod_get_dims_d
-
- subroutine f2pyinitmod(setupfunc)
- use mod
- external setupfunc,f2py_mod_get_dims_d,init
- call setupfunc(a,b,c,f2py_mod_get_dims_d,init)
- end subroutine f2pyinitmod
-
- subroutine f2pyinitfoodata(setupfunc)
- external setupfunc
- integer a
- real*8 b,c(3)
- common /foodata/ a,b,c
- call setupfunc(a,b,c)
- end subroutine f2pyinitfoodata
diff --git a/numpy/f2py/symbolic.py b/numpy/f2py/symbolic.py
new file mode 100644
index 000000000..1b7b35458
--- /dev/null
+++ b/numpy/f2py/symbolic.py
@@ -0,0 +1,1510 @@
+"""Fortran/C symbolic expressions
+
+References:
+- J3/21-007: Draft Fortran 202x. https://j3-fortran.org/doc/year/21/21-007.pdf
+"""
+
+# To analyze Fortran expressions to solve dimensions specifications,
+# for instances, we implement a minimal symbolic engine for parsing
+# expressions into a tree of expression instances. As a first
+# instance, we care only about arithmetic expressions involving
+# integers and operations like addition (+), subtraction (-),
+# multiplication (*), division (Fortran / is Python //, Fortran // is
+# concatenate), and exponentiation (**). In addition, .pyf files may
+# contain C expressions that support here is implemented as well.
+#
+# TODO: support logical constants (Op.BOOLEAN)
+# TODO: support logical operators (.AND., ...)
+# TODO: support defined operators (.MYOP., ...)
+#
+__all__ = ['Expr']
+
+
+import re
+import warnings
+from enum import Enum
+from math import gcd
+
+
+class Language(Enum):
+ """
+ Used as Expr.tostring language argument.
+ """
+ Python = 0
+ Fortran = 1
+ C = 2
+
+
+class Op(Enum):
+ """
+ Used as Expr op attribute.
+ """
+ INTEGER = 10
+ REAL = 12
+ COMPLEX = 15
+ STRING = 20
+ ARRAY = 30
+ SYMBOL = 40
+ TERNARY = 100
+ APPLY = 200
+ INDEXING = 210
+ CONCAT = 220
+ RELATIONAL = 300
+ TERMS = 1000
+ FACTORS = 2000
+ REF = 3000
+ DEREF = 3001
+
+
+class RelOp(Enum):
+ """
+ Used in Op.RELATIONAL expression to specify the function part.
+ """
+ EQ = 1
+ NE = 2
+ LT = 3
+ LE = 4
+ GT = 5
+ GE = 6
+
+ @classmethod
+ def fromstring(cls, s, language=Language.C):
+ if language is Language.Fortran:
+ return {'.eq.': RelOp.EQ, '.ne.': RelOp.NE,
+ '.lt.': RelOp.LT, '.le.': RelOp.LE,
+ '.gt.': RelOp.GT, '.ge.': RelOp.GE}[s.lower()]
+ return {'==': RelOp.EQ, '!=': RelOp.NE, '<': RelOp.LT,
+ '<=': RelOp.LE, '>': RelOp.GT, '>=': RelOp.GE}[s]
+
+ def tostring(self, language=Language.C):
+ if language is Language.Fortran:
+ return {RelOp.EQ: '.eq.', RelOp.NE: '.ne.',
+ RelOp.LT: '.lt.', RelOp.LE: '.le.',
+ RelOp.GT: '.gt.', RelOp.GE: '.ge.'}[self]
+ return {RelOp.EQ: '==', RelOp.NE: '!=',
+ RelOp.LT: '<', RelOp.LE: '<=',
+ RelOp.GT: '>', RelOp.GE: '>='}[self]
+
+
+class ArithOp(Enum):
+ """
+ Used in Op.APPLY expression to specify the function part.
+ """
+ POS = 1
+ NEG = 2
+ ADD = 3
+ SUB = 4
+ MUL = 5
+ DIV = 6
+ POW = 7
+
+
+class OpError(Exception):
+ pass
+
+
+class Precedence(Enum):
+ """
+ Used as Expr.tostring precedence argument.
+ """
+ ATOM = 0
+ POWER = 1
+ UNARY = 2
+ PRODUCT = 3
+ SUM = 4
+ LT = 6
+ EQ = 7
+ LAND = 11
+ LOR = 12
+ TERNARY = 13
+ ASSIGN = 14
+ TUPLE = 15
+ NONE = 100
+
+
+integer_types = (int,)
+number_types = (int, float)
+
+
+def _pairs_add(d, k, v):
+ # Internal utility method for updating terms and factors data.
+ c = d.get(k)
+ if c is None:
+ d[k] = v
+ else:
+ c = c + v
+ if c:
+ d[k] = c
+ else:
+ del d[k]
+
+
+class ExprWarning(UserWarning):
+ pass
+
+
+def ewarn(message):
+ warnings.warn(message, ExprWarning, stacklevel=2)
+
+
+class Expr:
+ """Represents a Fortran expression as a op-data pair.
+
+ Expr instances are hashable and sortable.
+ """
+
+ @staticmethod
+ def parse(s, language=Language.C):
+ """Parse a Fortran expression to a Expr.
+ """
+ return fromstring(s, language=language)
+
+ def __init__(self, op, data):
+ assert isinstance(op, Op)
+
+ # sanity checks
+ if op is Op.INTEGER:
+ # data is a 2-tuple of numeric object and a kind value
+ # (default is 4)
+ assert isinstance(data, tuple) and len(data) == 2
+ assert isinstance(data[0], int)
+ assert isinstance(data[1], (int, str)), data
+ elif op is Op.REAL:
+ # data is a 2-tuple of numeric object and a kind value
+ # (default is 4)
+ assert isinstance(data, tuple) and len(data) == 2
+ assert isinstance(data[0], float)
+ assert isinstance(data[1], (int, str)), data
+ elif op is Op.COMPLEX:
+ # data is a 2-tuple of constant expressions
+ assert isinstance(data, tuple) and len(data) == 2
+ elif op is Op.STRING:
+ # data is a 2-tuple of quoted string and a kind value
+ # (default is 1)
+ assert isinstance(data, tuple) and len(data) == 2
+ assert (isinstance(data[0], str)
+ and data[0][::len(data[0])-1] in ('""', "''", '@@'))
+ assert isinstance(data[1], (int, str)), data
+ elif op is Op.SYMBOL:
+ # data is any hashable object
+ assert hash(data) is not None
+ elif op in (Op.ARRAY, Op.CONCAT):
+ # data is a tuple of expressions
+ assert isinstance(data, tuple)
+ assert all(isinstance(item, Expr) for item in data), data
+ elif op in (Op.TERMS, Op.FACTORS):
+ # data is {<term|base>:<coeff|exponent>} where dict values
+ # are nonzero Python integers
+ assert isinstance(data, dict)
+ elif op is Op.APPLY:
+ # data is (<function>, <operands>, <kwoperands>) where
+ # operands are Expr instances
+ assert isinstance(data, tuple) and len(data) == 3
+ # function is any hashable object
+ assert hash(data[0]) is not None
+ assert isinstance(data[1], tuple)
+ assert isinstance(data[2], dict)
+ elif op is Op.INDEXING:
+ # data is (<object>, <indices>)
+ assert isinstance(data, tuple) and len(data) == 2
+ # function is any hashable object
+ assert hash(data[0]) is not None
+ elif op is Op.TERNARY:
+ # data is (<cond>, <expr1>, <expr2>)
+ assert isinstance(data, tuple) and len(data) == 3
+ elif op in (Op.REF, Op.DEREF):
+ # data is Expr instance
+ assert isinstance(data, Expr)
+ elif op is Op.RELATIONAL:
+ # data is (<relop>, <left>, <right>)
+ assert isinstance(data, tuple) and len(data) == 3
+ else:
+ raise NotImplementedError(
+ f'unknown op or missing sanity check: {op}')
+
+ self.op = op
+ self.data = data
+
+ def __eq__(self, other):
+ return (isinstance(other, Expr)
+ and self.op is other.op
+ and self.data == other.data)
+
+ def __hash__(self):
+ if self.op in (Op.TERMS, Op.FACTORS):
+ data = tuple(sorted(self.data.items()))
+ elif self.op is Op.APPLY:
+ data = self.data[:2] + tuple(sorted(self.data[2].items()))
+ else:
+ data = self.data
+ return hash((self.op, data))
+
+ def __lt__(self, other):
+ if isinstance(other, Expr):
+ if self.op is not other.op:
+ return self.op.value < other.op.value
+ if self.op in (Op.TERMS, Op.FACTORS):
+ return (tuple(sorted(self.data.items()))
+ < tuple(sorted(other.data.items())))
+ if self.op is Op.APPLY:
+ if self.data[:2] != other.data[:2]:
+ return self.data[:2] < other.data[:2]
+ return tuple(sorted(self.data[2].items())) < tuple(
+ sorted(other.data[2].items()))
+ return self.data < other.data
+ return NotImplemented
+
+ def __le__(self, other): return self == other or self < other
+
+ def __gt__(self, other): return not (self <= other)
+
+ def __ge__(self, other): return not (self < other)
+
+ def __repr__(self):
+ return f'{type(self).__name__}({self.op}, {self.data!r})'
+
+ def __str__(self):
+ return self.tostring()
+
+ def tostring(self, parent_precedence=Precedence.NONE,
+ language=Language.Fortran):
+ """Return a string representation of Expr.
+ """
+ if self.op in (Op.INTEGER, Op.REAL):
+ precedence = (Precedence.SUM if self.data[0] < 0
+ else Precedence.ATOM)
+ r = str(self.data[0]) + (f'_{self.data[1]}'
+ if self.data[1] != 4 else '')
+ elif self.op is Op.COMPLEX:
+ r = ', '.join(item.tostring(Precedence.TUPLE, language=language)
+ for item in self.data)
+ r = '(' + r + ')'
+ precedence = Precedence.ATOM
+ elif self.op is Op.SYMBOL:
+ precedence = Precedence.ATOM
+ r = str(self.data)
+ elif self.op is Op.STRING:
+ r = self.data[0]
+ if self.data[1] != 1:
+ r = self.data[1] + '_' + r
+ precedence = Precedence.ATOM
+ elif self.op is Op.ARRAY:
+ r = ', '.join(item.tostring(Precedence.TUPLE, language=language)
+ for item in self.data)
+ r = '[' + r + ']'
+ precedence = Precedence.ATOM
+ elif self.op is Op.TERMS:
+ terms = []
+ for term, coeff in sorted(self.data.items()):
+ if coeff < 0:
+ op = ' - '
+ coeff = -coeff
+ else:
+ op = ' + '
+ if coeff == 1:
+ term = term.tostring(Precedence.SUM, language=language)
+ else:
+ if term == as_number(1):
+ term = str(coeff)
+ else:
+ term = f'{coeff} * ' + term.tostring(
+ Precedence.PRODUCT, language=language)
+ if terms:
+ terms.append(op)
+ elif op == ' - ':
+ terms.append('-')
+ terms.append(term)
+ r = ''.join(terms) or '0'
+ precedence = Precedence.SUM if terms else Precedence.ATOM
+ elif self.op is Op.FACTORS:
+ factors = []
+ tail = []
+ for base, exp in sorted(self.data.items()):
+ op = ' * '
+ if exp == 1:
+ factor = base.tostring(Precedence.PRODUCT,
+ language=language)
+ elif language is Language.C:
+ if exp in range(2, 10):
+ factor = base.tostring(Precedence.PRODUCT,
+ language=language)
+ factor = ' * '.join([factor] * exp)
+ elif exp in range(-10, 0):
+ factor = base.tostring(Precedence.PRODUCT,
+ language=language)
+ tail += [factor] * -exp
+ continue
+ else:
+ factor = base.tostring(Precedence.TUPLE,
+ language=language)
+ factor = f'pow({factor}, {exp})'
+ else:
+ factor = base.tostring(Precedence.POWER,
+ language=language) + f' ** {exp}'
+ if factors:
+ factors.append(op)
+ factors.append(factor)
+ if tail:
+ if not factors:
+ factors += ['1']
+ factors += ['/', '(', ' * '.join(tail), ')']
+ r = ''.join(factors) or '1'
+ precedence = Precedence.PRODUCT if factors else Precedence.ATOM
+ elif self.op is Op.APPLY:
+ name, args, kwargs = self.data
+ if name is ArithOp.DIV and language is Language.C:
+ numer, denom = [arg.tostring(Precedence.PRODUCT,
+ language=language)
+ for arg in args]
+ r = f'{numer} / {denom}'
+ precedence = Precedence.PRODUCT
+ else:
+ args = [arg.tostring(Precedence.TUPLE, language=language)
+ for arg in args]
+ args += [k + '=' + v.tostring(Precedence.NONE)
+ for k, v in kwargs.items()]
+ r = f'{name}({", ".join(args)})'
+ precedence = Precedence.ATOM
+ elif self.op is Op.INDEXING:
+ name = self.data[0]
+ args = [arg.tostring(Precedence.TUPLE, language=language)
+ for arg in self.data[1:]]
+ r = f'{name}[{", ".join(args)}]'
+ precedence = Precedence.ATOM
+ elif self.op is Op.CONCAT:
+ args = [arg.tostring(Precedence.PRODUCT, language=language)
+ for arg in self.data]
+ r = " // ".join(args)
+ precedence = Precedence.PRODUCT
+ elif self.op is Op.TERNARY:
+ cond, expr1, expr2 = [a.tostring(Precedence.TUPLE,
+ language=language)
+ for a in self.data]
+ if language is Language.C:
+ r = f'({cond} ? {expr1} : {expr2})'
+ elif language is Language.Python:
+ r = f'({expr1} if {cond} else {expr2})'
+ elif language is Language.Fortran:
+ r = f'merge({expr1}, {expr2}, {cond})'
+ else:
+ raise NotImplementedError(
+ f'tostring for {self.op} and {language}')
+ precedence = Precedence.ATOM
+ elif self.op is Op.REF:
+ r = '&' + self.data.tostring(Precedence.UNARY, language=language)
+ precedence = Precedence.UNARY
+ elif self.op is Op.DEREF:
+ r = '*' + self.data.tostring(Precedence.UNARY, language=language)
+ precedence = Precedence.UNARY
+ elif self.op is Op.RELATIONAL:
+ rop, left, right = self.data
+ precedence = (Precedence.EQ if rop in (RelOp.EQ, RelOp.NE)
+ else Precedence.LT)
+ left = left.tostring(precedence, language=language)
+ right = right.tostring(precedence, language=language)
+ rop = rop.tostring(language=language)
+ r = f'{left} {rop} {right}'
+ else:
+ raise NotImplementedError(f'tostring for op {self.op}')
+ if parent_precedence.value < precedence.value:
+ # If parent precedence is higher than operand precedence,
+ # operand will be enclosed in parenthesis.
+ return '(' + r + ')'
+ return r
+
+ def __pos__(self):
+ return self
+
+ def __neg__(self):
+ return self * -1
+
+ def __add__(self, other):
+ other = as_expr(other)
+ if isinstance(other, Expr):
+ if self.op is other.op:
+ if self.op in (Op.INTEGER, Op.REAL):
+ return as_number(
+ self.data[0] + other.data[0],
+ max(self.data[1], other.data[1]))
+ if self.op is Op.COMPLEX:
+ r1, i1 = self.data
+ r2, i2 = other.data
+ return as_complex(r1 + r2, i1 + i2)
+ if self.op is Op.TERMS:
+ r = Expr(self.op, dict(self.data))
+ for k, v in other.data.items():
+ _pairs_add(r.data, k, v)
+ return normalize(r)
+ if self.op is Op.COMPLEX and other.op in (Op.INTEGER, Op.REAL):
+ return self + as_complex(other)
+ elif self.op in (Op.INTEGER, Op.REAL) and other.op is Op.COMPLEX:
+ return as_complex(self) + other
+ elif self.op is Op.REAL and other.op is Op.INTEGER:
+ return self + as_real(other, kind=self.data[1])
+ elif self.op is Op.INTEGER and other.op is Op.REAL:
+ return as_real(self, kind=other.data[1]) + other
+ return as_terms(self) + as_terms(other)
+ return NotImplemented
+
+ def __radd__(self, other):
+ if isinstance(other, number_types):
+ return as_number(other) + self
+ return NotImplemented
+
+ def __sub__(self, other):
+ return self + (-other)
+
+ def __rsub__(self, other):
+ if isinstance(other, number_types):
+ return as_number(other) - self
+ return NotImplemented
+
+ def __mul__(self, other):
+ other = as_expr(other)
+ if isinstance(other, Expr):
+ if self.op is other.op:
+ if self.op in (Op.INTEGER, Op.REAL):
+ return as_number(self.data[0] * other.data[0],
+ max(self.data[1], other.data[1]))
+ elif self.op is Op.COMPLEX:
+ r1, i1 = self.data
+ r2, i2 = other.data
+ return as_complex(r1 * r2 - i1 * i2, r1 * i2 + r2 * i1)
+
+ if self.op is Op.FACTORS:
+ r = Expr(self.op, dict(self.data))
+ for k, v in other.data.items():
+ _pairs_add(r.data, k, v)
+ return normalize(r)
+ elif self.op is Op.TERMS:
+ r = Expr(self.op, {})
+ for t1, c1 in self.data.items():
+ for t2, c2 in other.data.items():
+ _pairs_add(r.data, t1 * t2, c1 * c2)
+ return normalize(r)
+
+ if self.op is Op.COMPLEX and other.op in (Op.INTEGER, Op.REAL):
+ return self * as_complex(other)
+ elif other.op is Op.COMPLEX and self.op in (Op.INTEGER, Op.REAL):
+ return as_complex(self) * other
+ elif self.op is Op.REAL and other.op is Op.INTEGER:
+ return self * as_real(other, kind=self.data[1])
+ elif self.op is Op.INTEGER and other.op is Op.REAL:
+ return as_real(self, kind=other.data[1]) * other
+
+ if self.op is Op.TERMS:
+ return self * as_terms(other)
+ elif other.op is Op.TERMS:
+ return as_terms(self) * other
+
+ return as_factors(self) * as_factors(other)
+ return NotImplemented
+
+ def __rmul__(self, other):
+ if isinstance(other, number_types):
+ return as_number(other) * self
+ return NotImplemented
+
+ def __pow__(self, other):
+ other = as_expr(other)
+ if isinstance(other, Expr):
+ if other.op is Op.INTEGER:
+ exponent = other.data[0]
+ # TODO: other kind not used
+ if exponent == 0:
+ return as_number(1)
+ if exponent == 1:
+ return self
+ if exponent > 0:
+ if self.op is Op.FACTORS:
+ r = Expr(self.op, {})
+ for k, v in self.data.items():
+ r.data[k] = v * exponent
+ return normalize(r)
+ return self * (self ** (exponent - 1))
+ elif exponent != -1:
+ return (self ** (-exponent)) ** -1
+ return Expr(Op.FACTORS, {self: exponent})
+ return as_apply(ArithOp.POW, self, other)
+ return NotImplemented
+
+ def __truediv__(self, other):
+ other = as_expr(other)
+ if isinstance(other, Expr):
+ # Fortran / is different from Python /:
+ # - `/` is a truncate operation for integer operands
+ return normalize(as_apply(ArithOp.DIV, self, other))
+ return NotImplemented
+
+ def __rtruediv__(self, other):
+ other = as_expr(other)
+ if isinstance(other, Expr):
+ return other / self
+ return NotImplemented
+
+ def __floordiv__(self, other):
+ other = as_expr(other)
+ if isinstance(other, Expr):
+ # Fortran // is different from Python //:
+ # - `//` is a concatenate operation for string operands
+ return normalize(Expr(Op.CONCAT, (self, other)))
+ return NotImplemented
+
+ def __rfloordiv__(self, other):
+ other = as_expr(other)
+ if isinstance(other, Expr):
+ return other // self
+ return NotImplemented
+
+ def __call__(self, *args, **kwargs):
+ # In Fortran, parenthesis () are use for both function call as
+ # well as indexing operations.
+ #
+ # TODO: implement a method for deciding when __call__ should
+ # return an INDEXING expression.
+ return as_apply(self, *map(as_expr, args),
+ **dict((k, as_expr(v)) for k, v in kwargs.items()))
+
+ def __getitem__(self, index):
+ # Provided to support C indexing operations that .pyf files
+ # may contain.
+ index = as_expr(index)
+ if not isinstance(index, tuple):
+ index = index,
+ if len(index) > 1:
+ ewarn(f'C-index should be a single expression but got `{index}`')
+ return Expr(Op.INDEXING, (self,) + index)
+
+ def substitute(self, symbols_map):
+ """Recursively substitute symbols with values in symbols map.
+
+ Symbols map is a dictionary of symbol-expression pairs.
+ """
+ if self.op is Op.SYMBOL:
+ value = symbols_map.get(self)
+ if value is None:
+ return self
+ m = re.match(r'\A(@__f2py_PARENTHESIS_(\w+)_\d+@)\Z', self.data)
+ if m:
+ # complement to fromstring method
+ items, paren = m.groups()
+ if paren in ['ROUNDDIV', 'SQUARE']:
+ return as_array(value)
+ assert paren == 'ROUND', (paren, value)
+ return value
+ if self.op in (Op.INTEGER, Op.REAL, Op.STRING):
+ return self
+ if self.op in (Op.ARRAY, Op.COMPLEX):
+ return Expr(self.op, tuple(item.substitute(symbols_map)
+ for item in self.data))
+ if self.op is Op.CONCAT:
+ return normalize(Expr(self.op, tuple(item.substitute(symbols_map)
+ for item in self.data)))
+ if self.op is Op.TERMS:
+ r = None
+ for term, coeff in self.data.items():
+ if r is None:
+ r = term.substitute(symbols_map) * coeff
+ else:
+ r += term.substitute(symbols_map) * coeff
+ if r is None:
+ ewarn('substitute: empty TERMS expression interpreted as'
+ ' int-literal 0')
+ return as_number(0)
+ return r
+ if self.op is Op.FACTORS:
+ r = None
+ for base, exponent in self.data.items():
+ if r is None:
+ r = base.substitute(symbols_map) ** exponent
+ else:
+ r *= base.substitute(symbols_map) ** exponent
+ if r is None:
+ ewarn('substitute: empty FACTORS expression interpreted'
+ ' as int-literal 1')
+ return as_number(1)
+ return r
+ if self.op is Op.APPLY:
+ target, args, kwargs = self.data
+ if isinstance(target, Expr):
+ target = target.substitute(symbols_map)
+ args = tuple(a.substitute(symbols_map) for a in args)
+ kwargs = dict((k, v.substitute(symbols_map))
+ for k, v in kwargs.items())
+ return normalize(Expr(self.op, (target, args, kwargs)))
+ if self.op is Op.INDEXING:
+ func = self.data[0]
+ if isinstance(func, Expr):
+ func = func.substitute(symbols_map)
+ args = tuple(a.substitute(symbols_map) for a in self.data[1:])
+ return normalize(Expr(self.op, (func,) + args))
+ if self.op is Op.TERNARY:
+ operands = tuple(a.substitute(symbols_map) for a in self.data)
+ return normalize(Expr(self.op, operands))
+ if self.op in (Op.REF, Op.DEREF):
+ return normalize(Expr(self.op, self.data.substitute(symbols_map)))
+ if self.op is Op.RELATIONAL:
+ rop, left, right = self.data
+ left = left.substitute(symbols_map)
+ right = right.substitute(symbols_map)
+ return normalize(Expr(self.op, (rop, left, right)))
+ raise NotImplementedError(f'substitute method for {self.op}: {self!r}')
+
+ def traverse(self, visit, *args, **kwargs):
+ """Traverse expression tree with visit function.
+
+ The visit function is applied to an expression with given args
+ and kwargs.
+
+ Traverse call returns an expression returned by visit when not
+ None, otherwise return a new normalized expression with
+ traverse-visit sub-expressions.
+ """
+ result = visit(self, *args, **kwargs)
+ if result is not None:
+ return result
+
+ if self.op in (Op.INTEGER, Op.REAL, Op.STRING, Op.SYMBOL):
+ return self
+ elif self.op in (Op.COMPLEX, Op.ARRAY, Op.CONCAT, Op.TERNARY):
+ return normalize(Expr(self.op, tuple(
+ item.traverse(visit, *args, **kwargs)
+ for item in self.data)))
+ elif self.op in (Op.TERMS, Op.FACTORS):
+ data = {}
+ for k, v in self.data.items():
+ k = k.traverse(visit, *args, **kwargs)
+ v = (v.traverse(visit, *args, **kwargs)
+ if isinstance(v, Expr) else v)
+ if k in data:
+ v = data[k] + v
+ data[k] = v
+ return normalize(Expr(self.op, data))
+ elif self.op is Op.APPLY:
+ obj = self.data[0]
+ func = (obj.traverse(visit, *args, **kwargs)
+ if isinstance(obj, Expr) else obj)
+ operands = tuple(operand.traverse(visit, *args, **kwargs)
+ for operand in self.data[1])
+ kwoperands = dict((k, v.traverse(visit, *args, **kwargs))
+ for k, v in self.data[2].items())
+ return normalize(Expr(self.op, (func, operands, kwoperands)))
+ elif self.op is Op.INDEXING:
+ obj = self.data[0]
+ obj = (obj.traverse(visit, *args, **kwargs)
+ if isinstance(obj, Expr) else obj)
+ indices = tuple(index.traverse(visit, *args, **kwargs)
+ for index in self.data[1:])
+ return normalize(Expr(self.op, (obj,) + indices))
+ elif self.op in (Op.REF, Op.DEREF):
+ return normalize(Expr(self.op,
+ self.data.traverse(visit, *args, **kwargs)))
+ elif self.op is Op.RELATIONAL:
+ rop, left, right = self.data
+ left = left.traverse(visit, *args, **kwargs)
+ right = right.traverse(visit, *args, **kwargs)
+ return normalize(Expr(self.op, (rop, left, right)))
+ raise NotImplementedError(f'traverse method for {self.op}')
+
+ def contains(self, other):
+ """Check if self contains other.
+ """
+ found = []
+
+ def visit(expr, found=found):
+ if found:
+ return expr
+ elif expr == other:
+ found.append(1)
+ return expr
+
+ self.traverse(visit)
+
+ return len(found) != 0
+
+ def symbols(self):
+ """Return a set of symbols contained in self.
+ """
+ found = set()
+
+ def visit(expr, found=found):
+ if expr.op is Op.SYMBOL:
+ found.add(expr)
+
+ self.traverse(visit)
+
+ return found
+
+ def polynomial_atoms(self):
+ """Return a set of expressions used as atoms in polynomial self.
+ """
+ found = set()
+
+ def visit(expr, found=found):
+ if expr.op is Op.FACTORS:
+ for b in expr.data:
+ b.traverse(visit)
+ return expr
+ if expr.op in (Op.TERMS, Op.COMPLEX):
+ return
+ if expr.op is Op.APPLY and isinstance(expr.data[0], ArithOp):
+ if expr.data[0] is ArithOp.POW:
+ expr.data[1][0].traverse(visit)
+ return expr
+ return
+ if expr.op in (Op.INTEGER, Op.REAL):
+ return expr
+
+ found.add(expr)
+
+ if expr.op in (Op.INDEXING, Op.APPLY):
+ return expr
+
+ self.traverse(visit)
+
+ return found
+
+ def linear_solve(self, symbol):
+ """Return a, b such that a * symbol + b == self.
+
+ If self is not linear with respect to symbol, raise RuntimeError.
+ """
+ b = self.substitute({symbol: as_number(0)})
+ ax = self - b
+ a = ax.substitute({symbol: as_number(1)})
+
+ zero, _ = as_numer_denom(a * symbol - ax)
+
+ if zero != as_number(0):
+ raise RuntimeError(f'not a {symbol}-linear equation:'
+ f' {a} * {symbol} + {b} == {self}')
+ return a, b
+
+
+def normalize(obj):
+ """Normalize Expr and apply basic evaluation methods.
+ """
+ if not isinstance(obj, Expr):
+ return obj
+
+ if obj.op is Op.TERMS:
+ d = {}
+ for t, c in obj.data.items():
+ if c == 0:
+ continue
+ if t.op is Op.COMPLEX and c != 1:
+ t = t * c
+ c = 1
+ if t.op is Op.TERMS:
+ for t1, c1 in t.data.items():
+ _pairs_add(d, t1, c1 * c)
+ else:
+ _pairs_add(d, t, c)
+ if len(d) == 0:
+ # TODO: deterimine correct kind
+ return as_number(0)
+ elif len(d) == 1:
+ (t, c), = d.items()
+ if c == 1:
+ return t
+ return Expr(Op.TERMS, d)
+
+ if obj.op is Op.FACTORS:
+ coeff = 1
+ d = {}
+ for b, e in obj.data.items():
+ if e == 0:
+ continue
+ if b.op is Op.TERMS and isinstance(e, integer_types) and e > 1:
+ # expand integer powers of sums
+ b = b * (b ** (e - 1))
+ e = 1
+
+ if b.op in (Op.INTEGER, Op.REAL):
+ if e == 1:
+ coeff *= b.data[0]
+ elif e > 0:
+ coeff *= b.data[0] ** e
+ else:
+ _pairs_add(d, b, e)
+ elif b.op is Op.FACTORS:
+ if e > 0 and isinstance(e, integer_types):
+ for b1, e1 in b.data.items():
+ _pairs_add(d, b1, e1 * e)
+ else:
+ _pairs_add(d, b, e)
+ else:
+ _pairs_add(d, b, e)
+ if len(d) == 0 or coeff == 0:
+ # TODO: deterimine correct kind
+ assert isinstance(coeff, number_types)
+ return as_number(coeff)
+ elif len(d) == 1:
+ (b, e), = d.items()
+ if e == 1:
+ t = b
+ else:
+ t = Expr(Op.FACTORS, d)
+ if coeff == 1:
+ return t
+ return Expr(Op.TERMS, {t: coeff})
+ elif coeff == 1:
+ return Expr(Op.FACTORS, d)
+ else:
+ return Expr(Op.TERMS, {Expr(Op.FACTORS, d): coeff})
+
+ if obj.op is Op.APPLY and obj.data[0] is ArithOp.DIV:
+ dividend, divisor = obj.data[1]
+ t1, c1 = as_term_coeff(dividend)
+ t2, c2 = as_term_coeff(divisor)
+ if isinstance(c1, integer_types) and isinstance(c2, integer_types):
+ g = gcd(c1, c2)
+ c1, c2 = c1//g, c2//g
+ else:
+ c1, c2 = c1/c2, 1
+
+ if t1.op is Op.APPLY and t1.data[0] is ArithOp.DIV:
+ numer = t1.data[1][0] * c1
+ denom = t1.data[1][1] * t2 * c2
+ return as_apply(ArithOp.DIV, numer, denom)
+
+ if t2.op is Op.APPLY and t2.data[0] is ArithOp.DIV:
+ numer = t2.data[1][1] * t1 * c1
+ denom = t2.data[1][0] * c2
+ return as_apply(ArithOp.DIV, numer, denom)
+
+ d = dict(as_factors(t1).data)
+ for b, e in as_factors(t2).data.items():
+ _pairs_add(d, b, -e)
+ numer, denom = {}, {}
+ for b, e in d.items():
+ if e > 0:
+ numer[b] = e
+ else:
+ denom[b] = -e
+ numer = normalize(Expr(Op.FACTORS, numer)) * c1
+ denom = normalize(Expr(Op.FACTORS, denom)) * c2
+
+ if denom.op in (Op.INTEGER, Op.REAL) and denom.data[0] == 1:
+ # TODO: denom kind not used
+ return numer
+ return as_apply(ArithOp.DIV, numer, denom)
+
+ if obj.op is Op.CONCAT:
+ lst = [obj.data[0]]
+ for s in obj.data[1:]:
+ last = lst[-1]
+ if (
+ last.op is Op.STRING
+ and s.op is Op.STRING
+ and last.data[0][0] in '"\''
+ and s.data[0][0] == last.data[0][-1]
+ ):
+ new_last = as_string(last.data[0][:-1] + s.data[0][1:],
+ max(last.data[1], s.data[1]))
+ lst[-1] = new_last
+ else:
+ lst.append(s)
+ if len(lst) == 1:
+ return lst[0]
+ return Expr(Op.CONCAT, tuple(lst))
+
+ if obj.op is Op.TERNARY:
+ cond, expr1, expr2 = map(normalize, obj.data)
+ if cond.op is Op.INTEGER:
+ return expr1 if cond.data[0] else expr2
+ return Expr(Op.TERNARY, (cond, expr1, expr2))
+
+ return obj
+
+
+def as_expr(obj):
+ """Convert non-Expr objects to Expr objects.
+ """
+ if isinstance(obj, complex):
+ return as_complex(obj.real, obj.imag)
+ if isinstance(obj, number_types):
+ return as_number(obj)
+ if isinstance(obj, str):
+ # STRING expression holds string with boundary quotes, hence
+ # applying repr:
+ return as_string(repr(obj))
+ if isinstance(obj, tuple):
+ return tuple(map(as_expr, obj))
+ return obj
+
+
+def as_symbol(obj):
+ """Return object as SYMBOL expression (variable or unparsed expression).
+ """
+ return Expr(Op.SYMBOL, obj)
+
+
+def as_number(obj, kind=4):
+ """Return object as INTEGER or REAL constant.
+ """
+ if isinstance(obj, int):
+ return Expr(Op.INTEGER, (obj, kind))
+ if isinstance(obj, float):
+ return Expr(Op.REAL, (obj, kind))
+ if isinstance(obj, Expr):
+ if obj.op in (Op.INTEGER, Op.REAL):
+ return obj
+ raise OpError(f'cannot convert {obj} to INTEGER or REAL constant')
+
+
+def as_integer(obj, kind=4):
+ """Return object as INTEGER constant.
+ """
+ if isinstance(obj, int):
+ return Expr(Op.INTEGER, (obj, kind))
+ if isinstance(obj, Expr):
+ if obj.op is Op.INTEGER:
+ return obj
+ raise OpError(f'cannot convert {obj} to INTEGER constant')
+
+
+def as_real(obj, kind=4):
+ """Return object as REAL constant.
+ """
+ if isinstance(obj, int):
+ return Expr(Op.REAL, (float(obj), kind))
+ if isinstance(obj, float):
+ return Expr(Op.REAL, (obj, kind))
+ if isinstance(obj, Expr):
+ if obj.op is Op.REAL:
+ return obj
+ elif obj.op is Op.INTEGER:
+ return Expr(Op.REAL, (float(obj.data[0]), kind))
+ raise OpError(f'cannot convert {obj} to REAL constant')
+
+
+def as_string(obj, kind=1):
+ """Return object as STRING expression (string literal constant).
+ """
+ return Expr(Op.STRING, (obj, kind))
+
+
+def as_array(obj):
+ """Return object as ARRAY expression (array constant).
+ """
+ if isinstance(obj, Expr):
+ obj = obj,
+ return Expr(Op.ARRAY, obj)
+
+
+def as_complex(real, imag=0):
+ """Return object as COMPLEX expression (complex literal constant).
+ """
+ return Expr(Op.COMPLEX, (as_expr(real), as_expr(imag)))
+
+
+def as_apply(func, *args, **kwargs):
+ """Return object as APPLY expression (function call, constructor, etc.)
+ """
+ return Expr(Op.APPLY,
+ (func, tuple(map(as_expr, args)),
+ dict((k, as_expr(v)) for k, v in kwargs.items())))
+
+
+def as_ternary(cond, expr1, expr2):
+ """Return object as TERNARY expression (cond?expr1:expr2).
+ """
+ return Expr(Op.TERNARY, (cond, expr1, expr2))
+
+
+def as_ref(expr):
+ """Return object as referencing expression.
+ """
+ return Expr(Op.REF, expr)
+
+
+def as_deref(expr):
+ """Return object as dereferencing expression.
+ """
+ return Expr(Op.DEREF, expr)
+
+
+def as_eq(left, right):
+ return Expr(Op.RELATIONAL, (RelOp.EQ, left, right))
+
+
+def as_ne(left, right):
+ return Expr(Op.RELATIONAL, (RelOp.NE, left, right))
+
+
+def as_lt(left, right):
+ return Expr(Op.RELATIONAL, (RelOp.LT, left, right))
+
+
+def as_le(left, right):
+ return Expr(Op.RELATIONAL, (RelOp.LE, left, right))
+
+
+def as_gt(left, right):
+ return Expr(Op.RELATIONAL, (RelOp.GT, left, right))
+
+
+def as_ge(left, right):
+ return Expr(Op.RELATIONAL, (RelOp.GE, left, right))
+
+
+def as_terms(obj):
+ """Return expression as TERMS expression.
+ """
+ if isinstance(obj, Expr):
+ obj = normalize(obj)
+ if obj.op is Op.TERMS:
+ return obj
+ if obj.op is Op.INTEGER:
+ return Expr(Op.TERMS, {as_integer(1, obj.data[1]): obj.data[0]})
+ if obj.op is Op.REAL:
+ return Expr(Op.TERMS, {as_real(1, obj.data[1]): obj.data[0]})
+ return Expr(Op.TERMS, {obj: 1})
+ raise OpError(f'cannot convert {type(obj)} to terms Expr')
+
+
+def as_factors(obj):
+ """Return expression as FACTORS expression.
+ """
+ if isinstance(obj, Expr):
+ obj = normalize(obj)
+ if obj.op is Op.FACTORS:
+ return obj
+ if obj.op is Op.TERMS:
+ if len(obj.data) == 1:
+ (term, coeff), = obj.data.items()
+ if coeff == 1:
+ return Expr(Op.FACTORS, {term: 1})
+ return Expr(Op.FACTORS, {term: 1, Expr.number(coeff): 1})
+ if ((obj.op is Op.APPLY
+ and obj.data[0] is ArithOp.DIV
+ and not obj.data[2])):
+ return Expr(Op.FACTORS, {obj.data[1][0]: 1, obj.data[1][1]: -1})
+ return Expr(Op.FACTORS, {obj: 1})
+ raise OpError(f'cannot convert {type(obj)} to terms Expr')
+
+
+def as_term_coeff(obj):
+ """Return expression as term-coefficient pair.
+ """
+ if isinstance(obj, Expr):
+ obj = normalize(obj)
+ if obj.op is Op.INTEGER:
+ return as_integer(1, obj.data[1]), obj.data[0]
+ if obj.op is Op.REAL:
+ return as_real(1, obj.data[1]), obj.data[0]
+ if obj.op is Op.TERMS:
+ if len(obj.data) == 1:
+ (term, coeff), = obj.data.items()
+ return term, coeff
+ # TODO: find common divisor of coefficients
+ if obj.op is Op.APPLY and obj.data[0] is ArithOp.DIV:
+ t, c = as_term_coeff(obj.data[1][0])
+ return as_apply(ArithOp.DIV, t, obj.data[1][1]), c
+ return obj, 1
+ raise OpError(f'cannot convert {type(obj)} to term and coeff')
+
+
+def as_numer_denom(obj):
+ """Return expression as numer-denom pair.
+ """
+ if isinstance(obj, Expr):
+ obj = normalize(obj)
+ if obj.op in (Op.INTEGER, Op.REAL, Op.COMPLEX, Op.SYMBOL,
+ Op.INDEXING, Op.TERNARY):
+ return obj, as_number(1)
+ elif obj.op is Op.APPLY:
+ if obj.data[0] is ArithOp.DIV and not obj.data[2]:
+ numers, denoms = map(as_numer_denom, obj.data[1])
+ return numers[0] * denoms[1], numers[1] * denoms[0]
+ return obj, as_number(1)
+ elif obj.op is Op.TERMS:
+ numers, denoms = [], []
+ for term, coeff in obj.data.items():
+ n, d = as_numer_denom(term)
+ n = n * coeff
+ numers.append(n)
+ denoms.append(d)
+ numer, denom = as_number(0), as_number(1)
+ for i in range(len(numers)):
+ n = numers[i]
+ for j in range(len(numers)):
+ if i != j:
+ n *= denoms[j]
+ numer += n
+ denom *= denoms[i]
+ if denom.op in (Op.INTEGER, Op.REAL) and denom.data[0] < 0:
+ numer, denom = -numer, -denom
+ return numer, denom
+ elif obj.op is Op.FACTORS:
+ numer, denom = as_number(1), as_number(1)
+ for b, e in obj.data.items():
+ bnumer, bdenom = as_numer_denom(b)
+ if e > 0:
+ numer *= bnumer ** e
+ denom *= bdenom ** e
+ elif e < 0:
+ numer *= bdenom ** (-e)
+ denom *= bnumer ** (-e)
+ return numer, denom
+ raise OpError(f'cannot convert {type(obj)} to numer and denom')
+
+
+def _counter():
+ # Used internally to generate unique dummy symbols
+ counter = 0
+ while True:
+ counter += 1
+ yield counter
+
+
+COUNTER = _counter()
+
+
+def eliminate_quotes(s):
+ """Replace quoted substrings of input string.
+
+ Return a new string and a mapping of replacements.
+ """
+ d = {}
+
+ def repl(m):
+ kind, value = m.groups()[:2]
+ if kind:
+ # remove trailing underscore
+ kind = kind[:-1]
+ p = {"'": "SINGLE", '"': "DOUBLE"}[value[0]]
+ k = f'{kind}@__f2py_QUOTES_{p}_{COUNTER.__next__()}@'
+ d[k] = value
+ return k
+
+ new_s = re.sub(r'({kind}_|)({single_quoted}|{double_quoted})'.format(
+ kind=r'\w[\w\d_]*',
+ single_quoted=r"('([^'\\]|(\\.))*')",
+ double_quoted=r'("([^"\\]|(\\.))*")'),
+ repl, s)
+
+ assert '"' not in new_s
+ assert "'" not in new_s
+
+ return new_s, d
+
+
+def insert_quotes(s, d):
+ """Inverse of eliminate_quotes.
+ """
+ for k, v in d.items():
+ kind = k[:k.find('@')]
+ if kind:
+ kind += '_'
+ s = s.replace(k, kind + v)
+ return s
+
+
+def replace_parenthesis(s):
+ """Replace substrings of input that are enclosed in parenthesis.
+
+ Return a new string and a mapping of replacements.
+ """
+ # Find a parenthesis pair that appears first.
+
+ # Fortran deliminator are `(`, `)`, `[`, `]`, `(/', '/)`, `/`.
+ # We don't handle `/` deliminator because it is not a part of an
+ # expression.
+ left, right = None, None
+ mn_i = len(s)
+ for left_, right_ in (('(/', '/)'),
+ '()',
+ '{}', # to support C literal structs
+ '[]'):
+ i = s.find(left_)
+ if i == -1:
+ continue
+ if i < mn_i:
+ mn_i = i
+ left, right = left_, right_
+
+ if left is None:
+ return s, {}
+
+ i = mn_i
+ j = s.find(right, i)
+
+ while s.count(left, i + 1, j) != s.count(right, i + 1, j):
+ j = s.find(right, j + 1)
+ if j == -1:
+ raise ValueError(f'Mismatch of {left+right} parenthesis in {s!r}')
+
+ p = {'(': 'ROUND', '[': 'SQUARE', '{': 'CURLY', '(/': 'ROUNDDIV'}[left]
+
+ k = f'@__f2py_PARENTHESIS_{p}_{COUNTER.__next__()}@'
+ v = s[i+len(left):j]
+ r, d = replace_parenthesis(s[j+len(right):])
+ d[k] = v
+ return s[:i] + k + r, d
+
+
+def _get_parenthesis_kind(s):
+ assert s.startswith('@__f2py_PARENTHESIS_'), s
+ return s.split('_')[4]
+
+
+def unreplace_parenthesis(s, d):
+ """Inverse of replace_parenthesis.
+ """
+ for k, v in d.items():
+ p = _get_parenthesis_kind(k)
+ left = dict(ROUND='(', SQUARE='[', CURLY='{', ROUNDDIV='(/')[p]
+ right = dict(ROUND=')', SQUARE=']', CURLY='}', ROUNDDIV='/)')[p]
+ s = s.replace(k, left + v + right)
+ return s
+
+
+def fromstring(s, language=Language.C):
+ """Create an expression from a string.
+
+ This is a "lazy" parser, that is, only arithmetic operations are
+ resolved, non-arithmetic operations are treated as symbols.
+ """
+ r = _FromStringWorker(language=language).parse(s)
+ if isinstance(r, Expr):
+ return r
+ raise ValueError(f'failed to parse `{s}` to Expr instance: got `{r}`')
+
+
+class _Pair:
+ # Internal class to represent a pair of expressions
+
+ def __init__(self, left, right):
+ self.left = left
+ self.right = right
+
+ def substitute(self, symbols_map):
+ left, right = self.left, self.right
+ if isinstance(left, Expr):
+ left = left.substitute(symbols_map)
+ if isinstance(right, Expr):
+ right = right.substitute(symbols_map)
+ return _Pair(left, right)
+
+ def __repr__(self):
+ return f'{type(self).__name__}({self.left}, {self.right})'
+
+
+class _FromStringWorker:
+
+ def __init__(self, language=Language.C):
+ self.original = None
+ self.quotes_map = None
+ self.language = language
+
+ def finalize_string(self, s):
+ return insert_quotes(s, self.quotes_map)
+
+ def parse(self, inp):
+ self.original = inp
+ unquoted, self.quotes_map = eliminate_quotes(inp)
+ return self.process(unquoted)
+
+ def process(self, s, context='expr'):
+ """Parse string within the given context.
+
+ The context may define the result in case of ambiguous
+ expressions. For instance, consider expressions `f(x, y)` and
+ `(x, y) + (a, b)` where `f` is a function and pair `(x, y)`
+ denotes complex number. Specifying context as "args" or
+ "expr", the subexpression `(x, y)` will be parse to an
+ argument list or to a complex number, respectively.
+ """
+ if isinstance(s, (list, tuple)):
+ return type(s)(self.process(s_, context) for s_ in s)
+
+ assert isinstance(s, str), (type(s), s)
+
+ # replace subexpressions in parenthesis with f2py @-names
+ r, raw_symbols_map = replace_parenthesis(s)
+ r = r.strip()
+
+ def restore(r):
+ # restores subexpressions marked with f2py @-names
+ if isinstance(r, (list, tuple)):
+ return type(r)(map(restore, r))
+ return unreplace_parenthesis(r, raw_symbols_map)
+
+ # comma-separated tuple
+ if ',' in r:
+ operands = restore(r.split(','))
+ if context == 'args':
+ return tuple(self.process(operands))
+ if context == 'expr':
+ if len(operands) == 2:
+ # complex number literal
+ return as_complex(*self.process(operands))
+ raise NotImplementedError(
+ f'parsing comma-separated list (context={context}): {r}')
+
+ # ternary operation
+ m = re.match(r'\A([^?]+)[?]([^:]+)[:](.+)\Z', r)
+ if m:
+ assert context == 'expr', context
+ oper, expr1, expr2 = restore(m.groups())
+ oper = self.process(oper)
+ expr1 = self.process(expr1)
+ expr2 = self.process(expr2)
+ return as_ternary(oper, expr1, expr2)
+
+ # relational expression
+ if self.language is Language.Fortran:
+ m = re.match(
+ r'\A(.+)\s*[.](eq|ne|lt|le|gt|ge)[.]\s*(.+)\Z', r, re.I)
+ else:
+ m = re.match(
+ r'\A(.+)\s*([=][=]|[!][=]|[<][=]|[<]|[>][=]|[>])\s*(.+)\Z', r)
+ if m:
+ left, rop, right = m.groups()
+ if self.language is Language.Fortran:
+ rop = '.' + rop + '.'
+ left, right = self.process(restore((left, right)))
+ rop = RelOp.fromstring(rop, language=self.language)
+ return Expr(Op.RELATIONAL, (rop, left, right))
+
+ # keyword argument
+ m = re.match(r'\A(\w[\w\d_]*)\s*[=](.*)\Z', r)
+ if m:
+ keyname, value = m.groups()
+ value = restore(value)
+ return _Pair(keyname, self.process(value))
+
+ # addition/subtraction operations
+ operands = re.split(r'((?<!\d[edED])[+-])', r)
+ if len(operands) > 1:
+ result = self.process(restore(operands[0] or '0'))
+ for op, operand in zip(operands[1::2], operands[2::2]):
+ operand = self.process(restore(operand))
+ op = op.strip()
+ if op == '+':
+ result += operand
+ else:
+ assert op == '-'
+ result -= operand
+ return result
+
+ # string concatenate operation
+ if self.language is Language.Fortran and '//' in r:
+ operands = restore(r.split('//'))
+ return Expr(Op.CONCAT,
+ tuple(self.process(operands)))
+
+ # multiplication/division operations
+ operands = re.split(r'(?<=[@\w\d_])\s*([*]|/)',
+ (r if self.language is Language.C
+ else r.replace('**', '@__f2py_DOUBLE_STAR@')))
+ if len(operands) > 1:
+ operands = restore(operands)
+ if self.language is not Language.C:
+ operands = [operand.replace('@__f2py_DOUBLE_STAR@', '**')
+ for operand in operands]
+ # Expression is an arithmetic product
+ result = self.process(operands[0])
+ for op, operand in zip(operands[1::2], operands[2::2]):
+ operand = self.process(operand)
+ op = op.strip()
+ if op == '*':
+ result *= operand
+ else:
+ assert op == '/'
+ result /= operand
+ return result
+
+ # referencing/dereferencing
+ if r.startswith('*') or r.startswith('&'):
+ op = {'*': Op.DEREF, '&': Op.REF}[r[0]]
+ operand = self.process(restore(r[1:]))
+ return Expr(op, operand)
+
+ # exponentiation operations
+ if self.language is not Language.C and '**' in r:
+ operands = list(reversed(restore(r.split('**'))))
+ result = self.process(operands[0])
+ for operand in operands[1:]:
+ operand = self.process(operand)
+ result = operand ** result
+ return result
+
+ # int-literal-constant
+ m = re.match(r'\A({digit_string})({kind}|)\Z'.format(
+ digit_string=r'\d+',
+ kind=r'_(\d+|\w[\w\d_]*)'), r)
+ if m:
+ value, _, kind = m.groups()
+ if kind and kind.isdigit():
+ kind = int(kind)
+ return as_integer(int(value), kind or 4)
+
+ # real-literal-constant
+ m = re.match(r'\A({significant}({exponent}|)|\d+{exponent})({kind}|)\Z'
+ .format(
+ significant=r'[.]\d+|\d+[.]\d*',
+ exponent=r'[edED][+-]?\d+',
+ kind=r'_(\d+|\w[\w\d_]*)'), r)
+ if m:
+ value, _, _, kind = m.groups()
+ if kind and kind.isdigit():
+ kind = int(kind)
+ value = value.lower()
+ if 'd' in value:
+ return as_real(float(value.replace('d', 'e')), kind or 8)
+ return as_real(float(value), kind or 4)
+
+ # string-literal-constant with kind parameter specification
+ if r in self.quotes_map:
+ kind = r[:r.find('@')]
+ return as_string(self.quotes_map[r], kind or 1)
+
+ # array constructor or literal complex constant or
+ # parenthesized expression
+ if r in raw_symbols_map:
+ paren = _get_parenthesis_kind(r)
+ items = self.process(restore(raw_symbols_map[r]),
+ 'expr' if paren == 'ROUND' else 'args')
+ if paren == 'ROUND':
+ if isinstance(items, Expr):
+ return items
+ if paren in ['ROUNDDIV', 'SQUARE']:
+ # Expression is a array constructor
+ if isinstance(items, Expr):
+ items = (items,)
+ return as_array(items)
+
+ # function call/indexing
+ m = re.match(r'\A(.+)\s*(@__f2py_PARENTHESIS_(ROUND|SQUARE)_\d+@)\Z',
+ r)
+ if m:
+ target, args, paren = m.groups()
+ target = self.process(restore(target))
+ args = self.process(restore(args)[1:-1], 'args')
+ if not isinstance(args, tuple):
+ args = args,
+ if paren == 'ROUND':
+ kwargs = dict((a.left, a.right) for a in args
+ if isinstance(a, _Pair))
+ args = tuple(a for a in args if not isinstance(a, _Pair))
+ # Warning: this could also be Fortran indexing operation..
+ return as_apply(target, *args, **kwargs)
+ else:
+ # Expression is a C/Python indexing operation
+ # (e.g. used in .pyf files)
+ assert paren == 'SQUARE'
+ return target[args]
+
+ # Fortran standard conforming identifier
+ m = re.match(r'\A\w[\w\d_]*\Z', r)
+ if m:
+ return as_symbol(r)
+
+ # fall-back to symbol
+ r = self.finalize_string(restore(r))
+ ewarn(
+ f'fromstring: treating {r!r} as symbol (original={self.original})')
+ return as_symbol(r)
diff --git a/numpy/f2py/tests/src/array_from_pyobj/wrapmodule.c b/numpy/f2py/tests/src/array_from_pyobj/wrapmodule.c
index fe21d4b9b..ea47e0555 100644
--- a/numpy/f2py/tests/src/array_from_pyobj/wrapmodule.c
+++ b/numpy/f2py/tests/src/array_from_pyobj/wrapmodule.c
@@ -9,7 +9,9 @@ extern "C" {
#endif
/*********************** See f2py2e/cfuncs.py: includes ***********************/
-#include "Python.h"
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
#include "fortranobject.h"
#include <math.h>
diff --git a/numpy/f2py/tests/test_callback.py b/numpy/f2py/tests/test_callback.py
index 2cb429ec2..5d2aab94d 100644
--- a/numpy/f2py/tests/test_callback.py
+++ b/numpy/f2py/tests/test_callback.py
@@ -5,7 +5,6 @@ import pytest
import threading
import traceback
import time
-import random
import numpy as np
from numpy.testing import assert_, assert_equal, IS_PYPY
@@ -107,9 +106,9 @@ cf2py intent(out) r
-----
Call-back functions::
- def fun(): return a
- Return objects:
- a : int
+ def fun(): return a
+ Return objects:
+ a : int
""")
assert_equal(self.module.t.__doc__, expected)
diff --git a/numpy/f2py/tests/test_crackfortran.py b/numpy/f2py/tests/test_crackfortran.py
index 140f42cbc..039e085b4 100644
--- a/numpy/f2py/tests/test_crackfortran.py
+++ b/numpy/f2py/tests/test_crackfortran.py
@@ -1,3 +1,4 @@
+import pytest
import numpy as np
from numpy.testing import assert_array_equal, assert_equal
from numpy.f2py.crackfortran import markinnerspaces
@@ -39,6 +40,7 @@ class TestNoSpace(util.F2PyTest):
class TestPublicPrivate():
+
def test_defaultPrivate(self, tmp_path):
f_path = tmp_path / "mod.f90"
with f_path.open('w') as ff:
@@ -165,3 +167,117 @@ class TestMarkinnerspaces():
def test_multiple_relevant_spaces(self):
assert_equal(markinnerspaces("a 'b c' 'd e'"), "a 'b@_@c' 'd@_@e'")
assert_equal(markinnerspaces(r'a "b c" "d e"'), r'a "b@_@c" "d@_@e"')
+
+
+class TestDimSpec(util.F2PyTest):
+ """This test suite tests various expressions that are used as dimension
+ specifications.
+
+ There exists two usage cases where analyzing dimensions
+ specifications are important.
+
+ In the first case, the size of output arrays must be defined based
+ on the inputs to a Fortran function. Because Fortran supports
+ arbitrary bases for indexing, for instance, `arr(lower:upper)`,
+ f2py has to evaluate an expression `upper - lower + 1` where
+ `lower` and `upper` are arbitrary expressions of input parameters.
+ The evaluation is performed in C, so f2py has to translate Fortran
+ expressions to valid C expressions (an alternative approach is
+ that a developer specifies the corresponding C expressions in a
+ .pyf file).
+
+ In the second case, when user provides an input array with a given
+ size but some hidden parameters used in dimensions specifications
+ need to be determined based on the input array size. This is a
+ harder problem because f2py has to solve the inverse problem: find
+ a parameter `p` such that `upper(p) - lower(p) + 1` equals to the
+ size of input array. In the case when this equation cannot be
+ solved (e.g. because the input array size is wrong), raise an
+ error before calling the Fortran function (that otherwise would
+ likely crash Python process when the size of input arrays is
+ wrong). f2py currently supports this case only when the equation
+ is linear with respect to unknown parameter.
+
+ """
+
+ suffix = '.f90'
+
+ code_template = textwrap.dedent("""
+ function get_arr_size_{count}(a, n) result (length)
+ integer, intent(in) :: n
+ integer, dimension({dimspec}), intent(out) :: a
+ integer length
+ length = size(a)
+ end function
+
+ subroutine get_inv_arr_size_{count}(a, n)
+ integer :: n
+ ! the value of n is computed in f2py wrapper
+ !f2py intent(out) n
+ integer, dimension({dimspec}), intent(in) :: a
+ if (a({first}).gt.0) then
+ print*, "a=", a
+ endif
+ end subroutine
+ """)
+
+ linear_dimspecs = ['n', '2*n', '2:n', 'n/2', '5 - n/2', '3*n:20',
+ 'n*(n+1):n*(n+5)']
+ nonlinear_dimspecs = ['2*n:3*n*n+2*n']
+ all_dimspecs = linear_dimspecs + nonlinear_dimspecs
+
+ code = ''
+ for count, dimspec in enumerate(all_dimspecs):
+ code += code_template.format(
+ count=count, dimspec=dimspec,
+ first=dimspec.split(':')[0] if ':' in dimspec else '1')
+
+ @pytest.mark.parametrize('dimspec', all_dimspecs)
+ def test_array_size(self, dimspec):
+
+ count = self.all_dimspecs.index(dimspec)
+ get_arr_size = getattr(self.module, f'get_arr_size_{count}')
+
+ for n in [1, 2, 3, 4, 5]:
+ sz, a = get_arr_size(n)
+ assert len(a) == sz
+
+ @pytest.mark.parametrize('dimspec', all_dimspecs)
+ def test_inv_array_size(self, dimspec):
+
+ count = self.all_dimspecs.index(dimspec)
+ get_arr_size = getattr(self.module, f'get_arr_size_{count}')
+ get_inv_arr_size = getattr(self.module, f'get_inv_arr_size_{count}')
+
+ for n in [1, 2, 3, 4, 5]:
+ sz, a = get_arr_size(n)
+ if dimspec in self.nonlinear_dimspecs:
+ # one must specify n as input, the call we'll ensure
+ # that a and n are compatible:
+ n1 = get_inv_arr_size(a, n)
+ else:
+ # in case of linear dependence, n can be determined
+ # from the shape of a:
+ n1 = get_inv_arr_size(a)
+ # n1 may be different from n (for instance, when `a` size
+ # is a function of some `n` fraction) but it must produce
+ # the same sized array
+ sz1, _ = get_arr_size(n1)
+ assert sz == sz1, (n, n1, sz, sz1)
+
+
+class TestModuleDeclaration():
+ def test_dependencies(self, tmp_path):
+ f_path = tmp_path / "mod.f90"
+ with f_path.open('w') as ff:
+ ff.write(textwrap.dedent("""\
+ module foo
+ type bar
+ character(len = 4) :: text
+ end type bar
+ type(bar), parameter :: abar = bar('abar')
+ end module foo
+ """))
+ mod = crackfortran.crackfortran([str(f_path)])
+ assert len(mod) == 1
+ assert mod[0]['vars']['abar']['='] == "bar('abar')"
diff --git a/numpy/f2py/tests/test_return_character.py b/numpy/f2py/tests/test_return_character.py
index 7d4ced914..2c999ed0b 100644
--- a/numpy/f2py/tests/test_return_character.py
+++ b/numpy/f2py/tests/test_return_character.py
@@ -80,7 +80,7 @@ cf2py intent(out) ts
end
"""
- @pytest.mark.xfail(IS_S390X, reason="calback returns ' '")
+ @pytest.mark.xfail(IS_S390X, reason="callback returns ' '")
@pytest.mark.parametrize('name', 't0,t1,t5,s0,s1,s5,ss'.split(','))
def test_all(self, name):
self.check_function(getattr(self.module, name), name)
@@ -139,7 +139,7 @@ module f90_return_char
end module f90_return_char
"""
- @pytest.mark.xfail(IS_S390X, reason="calback returns ' '")
+ @pytest.mark.xfail(IS_S390X, reason="callback returns ' '")
@pytest.mark.parametrize('name', 't0,t1,t5,ts,s0,s1,s5,ss'.split(','))
def test_all(self, name):
self.check_function(getattr(self.module.f90_return_char, name), name)
diff --git a/numpy/f2py/tests/test_symbolic.py b/numpy/f2py/tests/test_symbolic.py
new file mode 100644
index 000000000..52cabac53
--- /dev/null
+++ b/numpy/f2py/tests/test_symbolic.py
@@ -0,0 +1,462 @@
+from numpy.testing import assert_raises
+from numpy.f2py.symbolic import (
+ Expr, Op, ArithOp, Language,
+ as_symbol, as_number, as_string, as_array, as_complex,
+ as_terms, as_factors, eliminate_quotes, insert_quotes,
+ fromstring, as_expr, as_apply,
+ as_numer_denom, as_ternary, as_ref, as_deref,
+ normalize, as_eq, as_ne, as_lt, as_gt, as_le, as_ge
+ )
+from . import util
+
+
+class TestSymbolic(util.F2PyTest):
+
+ def test_eliminate_quotes(self):
+ def worker(s):
+ r, d = eliminate_quotes(s)
+ s1 = insert_quotes(r, d)
+ assert s1 == s
+
+ for kind in ['', 'mykind_']:
+ worker(kind + '"1234" // "ABCD"')
+ worker(kind + '"1234" // ' + kind + '"ABCD"')
+ worker(kind + '"1234" // \'ABCD\'')
+ worker(kind + '"1234" // ' + kind + '\'ABCD\'')
+ worker(kind + '"1\\"2\'AB\'34"')
+ worker('a = ' + kind + "'1\\'2\"AB\"34'")
+
+ def test_sanity(self):
+ x = as_symbol('x')
+ y = as_symbol('y')
+ z = as_symbol('z')
+
+ assert x.op == Op.SYMBOL
+ assert repr(x) == "Expr(Op.SYMBOL, 'x')"
+ assert x == x
+ assert x != y
+ assert hash(x) is not None
+
+ n = as_number(123)
+ m = as_number(456)
+ assert n.op == Op.INTEGER
+ assert repr(n) == "Expr(Op.INTEGER, (123, 4))"
+ assert n == n
+ assert n != m
+ assert hash(n) is not None
+
+ fn = as_number(12.3)
+ fm = as_number(45.6)
+ assert fn.op == Op.REAL
+ assert repr(fn) == "Expr(Op.REAL, (12.3, 4))"
+ assert fn == fn
+ assert fn != fm
+ assert hash(fn) is not None
+
+ c = as_complex(1, 2)
+ c2 = as_complex(3, 4)
+ assert c.op == Op.COMPLEX
+ assert repr(c) == ("Expr(Op.COMPLEX, (Expr(Op.INTEGER, (1, 4)),"
+ " Expr(Op.INTEGER, (2, 4))))")
+ assert c == c
+ assert c != c2
+ assert hash(c) is not None
+
+ s = as_string("'123'")
+ s2 = as_string('"ABC"')
+ assert s.op == Op.STRING
+ assert repr(s) == "Expr(Op.STRING, (\"'123'\", 1))", repr(s)
+ assert s == s
+ assert s != s2
+
+ a = as_array((n, m))
+ b = as_array((n,))
+ assert a.op == Op.ARRAY
+ assert repr(a) == ("Expr(Op.ARRAY, (Expr(Op.INTEGER, (123, 4)),"
+ " Expr(Op.INTEGER, (456, 4))))")
+ assert a == a
+ assert a != b
+
+ t = as_terms(x)
+ u = as_terms(y)
+ assert t.op == Op.TERMS
+ assert repr(t) == "Expr(Op.TERMS, {Expr(Op.SYMBOL, 'x'): 1})"
+ assert t == t
+ assert t != u
+ assert hash(t) is not None
+
+ v = as_factors(x)
+ w = as_factors(y)
+ assert v.op == Op.FACTORS
+ assert repr(v) == "Expr(Op.FACTORS, {Expr(Op.SYMBOL, 'x'): 1})"
+ assert v == v
+ assert w != v
+ assert hash(v) is not None
+
+ t = as_ternary(x, y, z)
+ u = as_ternary(x, z, y)
+ assert t.op == Op.TERNARY
+ assert t == t
+ assert t != u
+ assert hash(t) is not None
+
+ e = as_eq(x, y)
+ f = as_lt(x, y)
+ assert e.op == Op.RELATIONAL
+ assert e == e
+ assert e != f
+ assert hash(e) is not None
+
+ def test_tostring_fortran(self):
+ x = as_symbol('x')
+ y = as_symbol('y')
+ z = as_symbol('z')
+ n = as_number(123)
+ m = as_number(456)
+ a = as_array((n, m))
+ c = as_complex(n, m)
+
+ assert str(x) == 'x'
+ assert str(n) == '123'
+ assert str(a) == '[123, 456]'
+ assert str(c) == '(123, 456)'
+
+ assert str(Expr(Op.TERMS, {x: 1})) == 'x'
+ assert str(Expr(Op.TERMS, {x: 2})) == '2 * x'
+ assert str(Expr(Op.TERMS, {x: -1})) == '-x'
+ assert str(Expr(Op.TERMS, {x: -2})) == '-2 * x'
+ assert str(Expr(Op.TERMS, {x: 1, y: 1})) == 'x + y'
+ assert str(Expr(Op.TERMS, {x: -1, y: -1})) == '-x - y'
+ assert str(Expr(Op.TERMS, {x: 2, y: 3})) == '2 * x + 3 * y'
+ assert str(Expr(Op.TERMS, {x: -2, y: 3})) == '-2 * x + 3 * y'
+ assert str(Expr(Op.TERMS, {x: 2, y: -3})) == '2 * x - 3 * y'
+
+ assert str(Expr(Op.FACTORS, {x: 1})) == 'x'
+ assert str(Expr(Op.FACTORS, {x: 2})) == 'x ** 2'
+ assert str(Expr(Op.FACTORS, {x: -1})) == 'x ** -1'
+ assert str(Expr(Op.FACTORS, {x: -2})) == 'x ** -2'
+ assert str(Expr(Op.FACTORS, {x: 1, y: 1})) == 'x * y'
+ assert str(Expr(Op.FACTORS, {x: 2, y: 3})) == 'x ** 2 * y ** 3'
+
+ v = Expr(Op.FACTORS, {x: 2, Expr(Op.TERMS, {x: 1, y: 1}): 3})
+ assert str(v) == 'x ** 2 * (x + y) ** 3', str(v)
+ v = Expr(Op.FACTORS, {x: 2, Expr(Op.FACTORS, {x: 1, y: 1}): 3})
+ assert str(v) == 'x ** 2 * (x * y) ** 3', str(v)
+
+ assert str(Expr(Op.APPLY, ('f', (), {}))) == 'f()'
+ assert str(Expr(Op.APPLY, ('f', (x,), {}))) == 'f(x)'
+ assert str(Expr(Op.APPLY, ('f', (x, y), {}))) == 'f(x, y)'
+ assert str(Expr(Op.INDEXING, ('f', x))) == 'f[x]'
+
+ assert str(as_ternary(x, y, z)) == 'merge(y, z, x)'
+ assert str(as_eq(x, y)) == 'x .eq. y'
+ assert str(as_ne(x, y)) == 'x .ne. y'
+ assert str(as_lt(x, y)) == 'x .lt. y'
+ assert str(as_le(x, y)) == 'x .le. y'
+ assert str(as_gt(x, y)) == 'x .gt. y'
+ assert str(as_ge(x, y)) == 'x .ge. y'
+
+ def test_tostring_c(self):
+ language = Language.C
+ x = as_symbol('x')
+ y = as_symbol('y')
+ z = as_symbol('z')
+ n = as_number(123)
+
+ assert Expr(Op.FACTORS, {x: 2}).tostring(language=language) == 'x * x'
+ assert Expr(Op.FACTORS, {x + y: 2}).tostring(
+ language=language) == '(x + y) * (x + y)'
+ assert Expr(Op.FACTORS, {x: 12}).tostring(
+ language=language) == 'pow(x, 12)'
+
+ assert as_apply(ArithOp.DIV, x, y).tostring(
+ language=language) == 'x / y'
+ assert as_apply(ArithOp.DIV, x, x + y).tostring(
+ language=language) == 'x / (x + y)'
+ assert as_apply(ArithOp.DIV, x - y, x + y).tostring(
+ language=language) == '(x - y) / (x + y)'
+ assert (x + (x - y) / (x + y) + n).tostring(
+ language=language) == '123 + x + (x - y) / (x + y)'
+
+ assert as_ternary(x, y, z).tostring(language=language) == '(x ? y : z)'
+ assert as_eq(x, y).tostring(language=language) == 'x == y'
+ assert as_ne(x, y).tostring(language=language) == 'x != y'
+ assert as_lt(x, y).tostring(language=language) == 'x < y'
+ assert as_le(x, y).tostring(language=language) == 'x <= y'
+ assert as_gt(x, y).tostring(language=language) == 'x > y'
+ assert as_ge(x, y).tostring(language=language) == 'x >= y'
+
+ def test_operations(self):
+ x = as_symbol('x')
+ y = as_symbol('y')
+ z = as_symbol('z')
+
+ assert x + x == Expr(Op.TERMS, {x: 2})
+ assert x - x == Expr(Op.INTEGER, (0, 4))
+ assert x + y == Expr(Op.TERMS, {x: 1, y: 1})
+ assert x - y == Expr(Op.TERMS, {x: 1, y: -1})
+ assert x * x == Expr(Op.FACTORS, {x: 2})
+ assert x * y == Expr(Op.FACTORS, {x: 1, y: 1})
+
+ assert +x == x
+ assert -x == Expr(Op.TERMS, {x: -1}), repr(-x)
+ assert 2 * x == Expr(Op.TERMS, {x: 2})
+ assert 2 + x == Expr(Op.TERMS, {x: 1, as_number(1): 2})
+ assert 2 * x + 3 * y == Expr(Op.TERMS, {x: 2, y: 3})
+ assert (x + y) * 2 == Expr(Op.TERMS, {x: 2, y: 2})
+
+ assert x ** 2 == Expr(Op.FACTORS, {x: 2})
+ assert (x + y) ** 2 == Expr(Op.TERMS,
+ {Expr(Op.FACTORS, {x: 2}): 1,
+ Expr(Op.FACTORS, {y: 2}): 1,
+ Expr(Op.FACTORS, {x: 1, y: 1}): 2})
+ assert (x + y) * x == x ** 2 + x * y
+ assert (x + y) ** 2 == x ** 2 + 2 * x * y + y ** 2
+ assert (x + y) ** 2 + (x - y) ** 2 == 2 * x ** 2 + 2 * y ** 2
+ assert (x + y) * z == x * z + y * z
+ assert z * (x + y) == x * z + y * z
+
+ assert (x / 2) == as_apply(ArithOp.DIV, x, as_number(2))
+ assert (2 * x / 2) == x
+ assert (3 * x / 2) == as_apply(ArithOp.DIV, 3*x, as_number(2))
+ assert (4 * x / 2) == 2 * x
+ assert (5 * x / 2) == as_apply(ArithOp.DIV, 5*x, as_number(2))
+ assert (6 * x / 2) == 3 * x
+ assert ((3*5) * x / 6) == as_apply(ArithOp.DIV, 5*x, as_number(2))
+ assert (30*x**2*y**4 / (24*x**3*y**3)) == as_apply(ArithOp.DIV,
+ 5*y, 4*x)
+ assert ((15 * x / 6) / 5) == as_apply(
+ ArithOp.DIV, x, as_number(2)), ((15 * x / 6) / 5)
+ assert (x / (5 / x)) == as_apply(ArithOp.DIV, x**2, as_number(5))
+
+ assert (x / 2.0) == Expr(Op.TERMS, {x: 0.5})
+
+ s = as_string('"ABC"')
+ t = as_string('"123"')
+
+ assert s // t == Expr(Op.STRING, ('"ABC123"', 1))
+ assert s // x == Expr(Op.CONCAT, (s, x))
+ assert x // s == Expr(Op.CONCAT, (x, s))
+
+ c = as_complex(1., 2.)
+ assert -c == as_complex(-1., -2.)
+ assert c + c == as_expr((1+2j)*2)
+ assert c * c == as_expr((1+2j)**2)
+
+ def test_substitute(self):
+ x = as_symbol('x')
+ y = as_symbol('y')
+ z = as_symbol('z')
+ a = as_array((x, y))
+
+ assert x.substitute({x: y}) == y
+ assert (x + y).substitute({x: z}) == y + z
+ assert (x * y).substitute({x: z}) == y * z
+ assert (x ** 4).substitute({x: z}) == z ** 4
+ assert (x / y).substitute({x: z}) == z / y
+ assert x.substitute({x: y + z}) == y + z
+ assert a.substitute({x: y + z}) == as_array((y + z, y))
+
+ assert as_ternary(x, y, z).substitute(
+ {x: y + z}) == as_ternary(y + z, y, z)
+ assert as_eq(x, y).substitute(
+ {x: y + z}) == as_eq(y + z, y)
+
+ def test_fromstring(self):
+
+ x = as_symbol('x')
+ y = as_symbol('y')
+ z = as_symbol('z')
+ f = as_symbol('f')
+ s = as_string('"ABC"')
+ t = as_string('"123"')
+ a = as_array((x, y))
+
+ assert fromstring('x') == x
+ assert fromstring('+ x') == x
+ assert fromstring('- x') == -x
+ assert fromstring('x + y') == x + y
+ assert fromstring('x + 1') == x + 1
+ assert fromstring('x * y') == x * y
+ assert fromstring('x * 2') == x * 2
+ assert fromstring('x / y') == x / y
+ assert fromstring('x ** 2',
+ language=Language.Python) == x ** 2
+ assert fromstring('x ** 2 ** 3',
+ language=Language.Python) == x ** 2 ** 3
+ assert fromstring('(x + y) * z') == (x + y) * z
+
+ assert fromstring('f(x)') == f(x)
+ assert fromstring('f(x,y)') == f(x, y)
+ assert fromstring('f[x]') == f[x]
+ assert fromstring('f[x][y]') == f[x][y]
+
+ assert fromstring('"ABC"') == s
+ assert normalize(fromstring('"ABC" // "123" ',
+ language=Language.Fortran)) == s // t
+ assert fromstring('f("ABC")') == f(s)
+ assert fromstring('MYSTRKIND_"ABC"') == as_string('"ABC"', 'MYSTRKIND')
+
+ assert fromstring('(/x, y/)') == a, fromstring('(/x, y/)')
+ assert fromstring('f((/x, y/))') == f(a)
+ assert fromstring('(/(x+y)*z/)') == as_array(((x+y)*z,))
+
+ assert fromstring('123') == as_number(123)
+ assert fromstring('123_2') == as_number(123, 2)
+ assert fromstring('123_myintkind') == as_number(123, 'myintkind')
+
+ assert fromstring('123.0') == as_number(123.0, 4)
+ assert fromstring('123.0_4') == as_number(123.0, 4)
+ assert fromstring('123.0_8') == as_number(123.0, 8)
+ assert fromstring('123.0e0') == as_number(123.0, 4)
+ assert fromstring('123.0d0') == as_number(123.0, 8)
+ assert fromstring('123d0') == as_number(123.0, 8)
+ assert fromstring('123e-0') == as_number(123.0, 4)
+ assert fromstring('123d+0') == as_number(123.0, 8)
+ assert fromstring('123.0_myrealkind') == as_number(123.0, 'myrealkind')
+ assert fromstring('3E4') == as_number(30000.0, 4)
+
+ assert fromstring('(1, 2)') == as_complex(1, 2)
+ assert fromstring('(1e2, PI)') == as_complex(
+ as_number(100.0), as_symbol('PI'))
+
+ assert fromstring('[1, 2]') == as_array((as_number(1), as_number(2)))
+
+ assert fromstring('POINT(x, y=1)') == as_apply(
+ as_symbol('POINT'), x, y=as_number(1))
+ assert (fromstring('PERSON(name="John", age=50, shape=(/34, 23/))')
+ == as_apply(as_symbol('PERSON'),
+ name=as_string('"John"'),
+ age=as_number(50),
+ shape=as_array((as_number(34), as_number(23)))))
+
+ assert fromstring('x?y:z') == as_ternary(x, y, z)
+
+ assert fromstring('*x') == as_deref(x)
+ assert fromstring('**x') == as_deref(as_deref(x))
+ assert fromstring('&x') == as_ref(x)
+ assert fromstring('(*x) * (*y)') == as_deref(x) * as_deref(y)
+ assert fromstring('(*x) * *y') == as_deref(x) * as_deref(y)
+ assert fromstring('*x * *y') == as_deref(x) * as_deref(y)
+ assert fromstring('*x**y') == as_deref(x) * as_deref(y)
+
+ assert fromstring('x == y') == as_eq(x, y)
+ assert fromstring('x != y') == as_ne(x, y)
+ assert fromstring('x < y') == as_lt(x, y)
+ assert fromstring('x > y') == as_gt(x, y)
+ assert fromstring('x <= y') == as_le(x, y)
+ assert fromstring('x >= y') == as_ge(x, y)
+
+ assert fromstring('x .eq. y', language=Language.Fortran) == as_eq(x, y)
+ assert fromstring('x .ne. y', language=Language.Fortran) == as_ne(x, y)
+ assert fromstring('x .lt. y', language=Language.Fortran) == as_lt(x, y)
+ assert fromstring('x .gt. y', language=Language.Fortran) == as_gt(x, y)
+ assert fromstring('x .le. y', language=Language.Fortran) == as_le(x, y)
+ assert fromstring('x .ge. y', language=Language.Fortran) == as_ge(x, y)
+
+ def test_traverse(self):
+ x = as_symbol('x')
+ y = as_symbol('y')
+ z = as_symbol('z')
+ f = as_symbol('f')
+
+ # Use traverse to substitute a symbol
+ def replace_visit(s, r=z):
+ if s == x:
+ return r
+
+ assert x.traverse(replace_visit) == z
+ assert y.traverse(replace_visit) == y
+ assert z.traverse(replace_visit) == z
+ assert (f(y)).traverse(replace_visit) == f(y)
+ assert (f(x)).traverse(replace_visit) == f(z)
+ assert (f[y]).traverse(replace_visit) == f[y]
+ assert (f[z]).traverse(replace_visit) == f[z]
+ assert (x + y + z).traverse(replace_visit) == (2 * z + y)
+ assert (x + f(y, x - z)).traverse(
+ replace_visit) == (z + f(y, as_number(0)))
+ assert as_eq(x, y).traverse(replace_visit) == as_eq(z, y)
+
+ # Use traverse to collect symbols, method 1
+ function_symbols = set()
+ symbols = set()
+
+ def collect_symbols(s):
+ if s.op is Op.APPLY:
+ oper = s.data[0]
+ function_symbols.add(oper)
+ if oper in symbols:
+ symbols.remove(oper)
+ elif s.op is Op.SYMBOL and s not in function_symbols:
+ symbols.add(s)
+
+ (x + f(y, x - z)).traverse(collect_symbols)
+ assert function_symbols == {f}
+ assert symbols == {x, y, z}
+
+ # Use traverse to collect symbols, method 2
+ def collect_symbols2(expr, symbols):
+ if expr.op is Op.SYMBOL:
+ symbols.add(expr)
+
+ symbols = set()
+ (x + f(y, x - z)).traverse(collect_symbols2, symbols)
+ assert symbols == {x, y, z, f}
+
+ # Use traverse to partially collect symbols
+ def collect_symbols3(expr, symbols):
+ if expr.op is Op.APPLY:
+ # skip traversing function calls
+ return expr
+ if expr.op is Op.SYMBOL:
+ symbols.add(expr)
+
+ symbols = set()
+ (x + f(y, x - z)).traverse(collect_symbols3, symbols)
+ assert symbols == {x}
+
+ def test_linear_solve(self):
+ x = as_symbol('x')
+ y = as_symbol('y')
+ z = as_symbol('z')
+
+ assert x.linear_solve(x) == (as_number(1), as_number(0))
+ assert (x+1).linear_solve(x) == (as_number(1), as_number(1))
+ assert (2*x).linear_solve(x) == (as_number(2), as_number(0))
+ assert (2*x+3).linear_solve(x) == (as_number(2), as_number(3))
+ assert as_number(3).linear_solve(x) == (as_number(0), as_number(3))
+ assert y.linear_solve(x) == (as_number(0), y)
+ assert (y*z).linear_solve(x) == (as_number(0), y * z)
+
+ assert (x+y).linear_solve(x) == (as_number(1), y)
+ assert (z*x+y).linear_solve(x) == (z, y)
+ assert ((z+y)*x+y).linear_solve(x) == (z + y, y)
+ assert (z*y*x+y).linear_solve(x) == (z * y, y)
+
+ assert_raises(RuntimeError, lambda: (x*x).linear_solve(x))
+
+ def test_as_numer_denom(self):
+ x = as_symbol('x')
+ y = as_symbol('y')
+ n = as_number(123)
+
+ assert as_numer_denom(x) == (x, as_number(1))
+ assert as_numer_denom(x / n) == (x, n)
+ assert as_numer_denom(n / x) == (n, x)
+ assert as_numer_denom(x / y) == (x, y)
+ assert as_numer_denom(x * y) == (x * y, as_number(1))
+ assert as_numer_denom(n + x / y) == (x + n * y, y)
+ assert as_numer_denom(n + x / (y - x / n)) == (y * n ** 2, y * n - x)
+
+ def test_polynomial_atoms(self):
+ x = as_symbol('x')
+ y = as_symbol('y')
+ n = as_number(123)
+
+ assert x.polynomial_atoms() == {x}
+ assert n.polynomial_atoms() == set()
+ assert (y[x]).polynomial_atoms() == {y[x]}
+ assert (y(x)).polynomial_atoms() == {y(x)}
+ assert (y(x) + x).polynomial_atoms() == {y(x), x}
+ assert (y(x) * x[y]).polynomial_atoms() == {y(x), x[y]}
+ assert (y(x) ** x).polynomial_atoms() == {y(x)}
diff --git a/numpy/f2py/tests/util.py b/numpy/f2py/tests/util.py
index eace3c9fc..1a6805e75 100644
--- a/numpy/f2py/tests/util.py
+++ b/numpy/f2py/tests/util.py
@@ -242,9 +242,6 @@ def build_module_distutils(source_files, config_code, module_name, **kw):
Build a module via distutils and import it.
"""
- from numpy.distutils.misc_util import Configuration
- from numpy.distutils.core import setup
-
d = get_module_dir()
# Copy files