diff options
Diffstat (limited to 'numpy/f2py')
41 files changed, 282 insertions, 399 deletions
diff --git a/numpy/f2py/__init__.py b/numpy/f2py/__init__.py index 42e3632fd..949bac0ff 100644 --- a/numpy/f2py/__init__.py +++ b/numpy/f2py/__init__.py @@ -1,17 +1,13 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """Fortran to Python Interface Generator. """ -from __future__ import division, absolute_import, print_function - __all__ = ['run_main', 'compile', 'f2py_testing'] import sys import subprocess import os -import numpy as np - from . import f2py2e from . import f2py_testing from . import diagnose @@ -89,7 +85,7 @@ def compile(source, args = ['-c', '-m', modulename, f.name] - if isinstance(extra_args, np.compat.basestring): + if isinstance(extra_args, str): is_posix = (os.name == 'posix') extra_args = shlex.split(extra_args, posix=is_posix) diff --git a/numpy/f2py/__main__.py b/numpy/f2py/__main__.py index 708f7f362..c6115070e 100644 --- a/numpy/f2py/__main__.py +++ b/numpy/f2py/__main__.py @@ -1,6 +1,4 @@ # See http://cens.ioc.ee/projects/f2py2e/ -from __future__ import division, print_function - from numpy.f2py.f2py2e import main main() diff --git a/numpy/f2py/__version__.py b/numpy/f2py/__version__.py index 49a2199bf..104c2e1a8 100644 --- a/numpy/f2py/__version__.py +++ b/numpy/f2py/__version__.py @@ -1,5 +1,3 @@ -from __future__ import division, absolute_import, print_function - major = 2 try: diff --git a/numpy/f2py/auxfuncs.py b/numpy/f2py/auxfuncs.py index 404bdbd2d..80b150655 100644 --- a/numpy/f2py/auxfuncs.py +++ b/numpy/f2py/auxfuncs.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """ Auxiliary functions for f2py2e. @@ -14,8 +14,6 @@ $Date: 2005/07/24 19:01:55 $ Pearu Peterson """ -from __future__ import division, absolute_import, print_function - import pprint import sys import types @@ -552,7 +550,7 @@ class F2PYError(Exception): pass -class throw_error(object): +class throw_error: def __init__(self, mess): self.mess = mess diff --git a/numpy/f2py/capi_maps.py b/numpy/f2py/capi_maps.py index c41dd77c6..fabbfc4c2 100644 --- a/numpy/f2py/capi_maps.py +++ b/numpy/f2py/capi_maps.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """ Copyright 1999,2000 Pearu Peterson all rights reserved, @@ -11,8 +11,6 @@ $Date: 2005/05/06 10:57:33 $ Pearu Peterson """ -from __future__ import division, absolute_import, print_function - __version__ = "$Revision: 1.60 $"[10:-1] from . import __version__ @@ -21,11 +19,10 @@ f2py_version = __version__.version import copy import re import os -import sys from .crackfortran import markoutercomma from . import cb_rules -# The eviroment provided by auxfuncs.py is needed for some calls to eval. +# The environment provided by auxfuncs.py is needed for some calls to eval. # 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 * @@ -79,7 +76,7 @@ c2capi_map = {'double': 'NPY_DOUBLE', 'complex_long_double': 'NPY_CDOUBLE', # forced casting 'string': 'NPY_STRING'} -# These new maps aren't used anyhere yet, but should be by default +# These new maps aren't used anywhere yet, but should be by default # unless building numeric or numarray extensions. if using_newcore: c2capi_map = {'double': 'NPY_DOUBLE', @@ -149,11 +146,7 @@ c2buildvalue_map = {'double': 'd', 'complex_float': 'N', 'complex_double': 'N', 'complex_long_double': 'N', - 'string': 'z'} - -if sys.version_info[0] >= 3: - # Bytes, not Unicode strings - c2buildvalue_map['string'] = 'y' + 'string': 'y'} if using_newcore: # c2buildvalue_map=??? @@ -179,17 +172,29 @@ f2cmap_all = {'real': {'': 'float', '4': 'float', '8': 'double', 'character': {'': 'string'} } -if os.path.isfile('.f2py_f2cmap'): +f2cmap_default = copy.deepcopy(f2cmap_all) + + +def load_f2cmap_file(f2cmap_file): + global f2cmap_all + + f2cmap_all = copy.deepcopy(f2cmap_default) + + if f2cmap_file is None: + # Default value + f2cmap_file = '.f2py_f2cmap' + if not os.path.isfile(f2cmap_file): + return + # User defined additions to f2cmap_all. - # .f2py_f2cmap 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. try: - outmess('Reading .f2py_f2cmap ...\n') - f = open('.f2py_f2cmap', 'r') - d = eval(f.read(), {}, {}) - f.close() + 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()): d1[k1.lower()] = d1[k1] @@ -208,10 +213,10 @@ if os.path.isfile('.f2py_f2cmap'): else: errmess("\tIgnoring map {'%s':{'%s':'%s'}}: '%s' must be in %s\n" % ( k, k1, d[k][k1], d[k][k1], list(c2py_map.keys()))) - outmess('Successfully applied user defined changes from .f2py_f2cmap\n') + outmess('Successfully applied user defined f2cmap changes\n') except Exception as msg: errmess( - 'Failed to apply user defined changes from .f2py_f2cmap: %s. Skipping.\n' % (msg)) + 'Failed to apply user defined f2cmap changes: %s. Skipping.\n' % (msg)) cformat_map = {'double': '%g', 'float': '%g', @@ -313,7 +318,6 @@ def getstrlength(var): def getarrdims(a, var, verbose=0): - global depargs ret = {} if isstring(var) and not isarray(var): ret['dims'] = getstrlength(var) @@ -509,7 +513,6 @@ def sign2map(a, var): varrfromat intent """ - global lcb_map, cb_map out_a = a if isintent_out(var): for k in var['intent']: diff --git a/numpy/f2py/cb_rules.py b/numpy/f2py/cb_rules.py index 183d7c2f9..87887c152 100644 --- a/numpy/f2py/cb_rules.py +++ b/numpy/f2py/cb_rules.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """ Build call-back mechanism for f2py2e. @@ -13,8 +13,6 @@ $Date: 2005/07/20 11:27:58 $ Pearu Peterson """ -from __future__ import division, absolute_import, print_function - from . import __version__ from .auxfuncs import ( applyrules, debugcapi, dictappend, errmess, getargs, hasnote, isarray, @@ -438,7 +436,6 @@ cb_map = {} def buildcallbacks(m): - global cb_map cb_map[m['name']] = [] for bi in m['body']: if bi['block'] == 'interface': @@ -450,7 +447,6 @@ def buildcallbacks(m): def buildcallback(rout, um): - global cb_map from . import capi_maps outmess('\tConstructing call-back function "cb_%s_in_%s"\n' % diff --git a/numpy/f2py/cfuncs.py b/numpy/f2py/cfuncs.py index ccb7b3a32..f1ac214d4 100644 --- a/numpy/f2py/cfuncs.py +++ b/numpy/f2py/cfuncs.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """ C declarations, CPP macros, and C functions for f2py2e. @@ -14,8 +14,6 @@ $Date: 2005/05/06 11:42:34 $ Pearu Peterson """ -from __future__ import division, absolute_import, print_function - import sys import copy @@ -542,7 +540,7 @@ cppmacros[ 'ARRSIZE'] = '#define ARRSIZE(dims,rank) (_PyArray_multiply_list(dims,rank))' cppmacros['OLDPYNUM'] = """\ #ifdef OLDPYNUM -#error You need to install NumPy version 13 or higher. See https://scipy.org/install.html +#error You need to install NumPy version 0.13 or higher. See https://scipy.org/install.html #endif """ ################# C functions ############### @@ -646,7 +644,6 @@ fprintf(stderr,\"string_from_pyobj(str='%s',len=%d,inistr='%s',obj=%p)\\n\",(cha tmp = obj; Py_INCREF(tmp); } -#if PY_VERSION_HEX >= 0x03000000 else if (PyUnicode_Check(obj)) { tmp = PyUnicode_AsASCIIString(obj); } @@ -661,11 +658,6 @@ fprintf(stderr,\"string_from_pyobj(str='%s',len=%d,inistr='%s',obj=%p)\\n\",(cha tmp = NULL; } } -#else - else { - tmp = PyObject_Str(obj); - } -#endif if (tmp == NULL) goto capi_fail; if (*len == -1) *len = PyString_GET_SIZE(tmp); @@ -1041,6 +1033,8 @@ cfuncs[ 'try_pyarr_from_complex_double'] = 'static int try_pyarr_from_complex_double(PyObject* obj,complex_double* v) {\n TRYCOMPLEXPYARRAYTEMPLATE(double,\'D\');\n}\n' needs['create_cb_arglist'] = ['CFUNCSMESS', 'PRINTPYOBJERR', 'MINMAX'] + +# create the list of arguments to be used when calling back to python cfuncs['create_cb_arglist'] = """\ static int create_cb_arglist(PyObject* fun,PyTupleObject* xa,const int maxnofargs,const int nofoptargs,int *nofargs,PyTupleObject **args,const char *errmess) { PyObject *tmp = NULL; @@ -1066,6 +1060,10 @@ static int create_cb_arglist(PyObject* fun,PyTupleObject* xa,const int maxnofarg tmp_fun = fun; /* built-in function */ Py_INCREF(tmp_fun); tot = maxnofargs; + if (PyCFunction_Check(fun)) { + /* In case the function has a co_argcount (like on PyPy) */ + di = 0; + } if (xa != NULL) tot += PyTuple_Size((PyObject *)xa); } @@ -1094,13 +1092,8 @@ if (tmp_fun==NULL) { fprintf(stderr,\"Call-back argument must be function|instance|instance.__call__|f2py-function but got %s.\\n\",(fun==NULL?\"NULL\":Py_TYPE(fun)->tp_name)); goto capi_fail; } -#if PY_VERSION_HEX >= 0x03000000 if (PyObject_HasAttrString(tmp_fun,\"__code__\")) { if (PyObject_HasAttrString(tmp = PyObject_GetAttrString(tmp_fun,\"__code__\"),\"co_argcount\")) { -#else - if (PyObject_HasAttrString(tmp_fun,\"func_code\")) { - if (PyObject_HasAttrString(tmp = PyObject_GetAttrString(tmp_fun,\"func_code\"),\"co_argcount\")) { -#endif PyObject *tmp_argcount = PyObject_GetAttrString(tmp,\"co_argcount\"); Py_DECREF(tmp); if (tmp_argcount == NULL) { @@ -1111,13 +1104,8 @@ goto capi_fail; } } /* Get the number of optional arguments */ -#if PY_VERSION_HEX >= 0x03000000 if (PyObject_HasAttrString(tmp_fun,\"__defaults__\")) { if (PyTuple_Check(tmp = PyObject_GetAttrString(tmp_fun,\"__defaults__\"))) -#else - if (PyObject_HasAttrString(tmp_fun,\"func_defaults\")) { - if (PyTuple_Check(tmp = PyObject_GetAttrString(tmp_fun,\"func_defaults\"))) -#endif opt = PyTuple_Size(tmp); Py_XDECREF(tmp); } @@ -1174,7 +1162,7 @@ def buildcfuncs(): ############ Auxiliary functions for sorting needs ################### def append_needs(need, flag=1): - global outneeds, needs + # This function modifies the contents of the global `outneeds` dict. if isinstance(need, list): for n in need: append_needs(n, flag) @@ -1241,7 +1229,7 @@ def append_needs(need, flag=1): def get_needs(): - global outneeds, needs + # This function modifies the contents of the global `outneeds` dict. res = {} for n in outneeds.keys(): out = [] diff --git a/numpy/f2py/common_rules.py b/numpy/f2py/common_rules.py index f61d8810a..90483e55b 100644 --- a/numpy/f2py/common_rules.py +++ b/numpy/f2py/common_rules.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """ Build common block mechanism for f2py2e. @@ -13,8 +13,6 @@ $Date: 2005/05/06 10:57:33 $ Pearu Peterson """ -from __future__ import division, absolute_import, print_function - __version__ = "$Revision: 1.19 $"[10:-1] from . import __version__ diff --git a/numpy/f2py/crackfortran.py b/numpy/f2py/crackfortran.py index 2aaf5d7c6..3d2f97a56 100755 --- a/numpy/f2py/crackfortran.py +++ b/numpy/f2py/crackfortran.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """ crackfortran --- read fortran (77,90) code and extract declaration information. @@ -138,8 +138,6 @@ TODO: The above may be solved by creating appropriate preprocessor program, for example. """ -from __future__ import division, absolute_import, print_function - import sys import string import fileinput @@ -150,7 +148,7 @@ import platform from . import __version__ -# The eviroment provided by auxfuncs.py is needed for some calls to eval. +# The environment provided by auxfuncs.py is needed for some calls to eval. # 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 * @@ -558,7 +556,8 @@ groupbegins90 = groupbegins77 + \ r'|module(?!\s*procedure)|python\s*module|interface|type(?!\s*\()' beginpattern90 = re.compile( beforethisafter % ('', groupbegins90, groupbegins90, '.*'), re.I), 'begin' -groupends = r'end|endprogram|endblockdata|endmodule|endpythonmodule|endinterface' +groupends = (r'end|endprogram|endblockdata|endmodule|endpythonmodule|' + r'endinterface|endsubroutine|endfunction') endpattern = re.compile( beforethisafter % ('', groupends, groupends, r'[\w\s]*'), re.I), 'end' # endifs='end\s*(if|do|where|select|while|forall)' @@ -580,8 +579,8 @@ publicpattern = re.compile( beforethisafter % ('', 'public', 'public', '.*'), re.I), 'public' privatepattern = re.compile( beforethisafter % ('', 'private', 'private', '.*'), re.I), 'private' -intrisicpattern = re.compile( - beforethisafter % ('', 'intrisic', 'intrisic', '.*'), re.I), 'intrisic' +intrinsicpattern = re.compile( + beforethisafter % ('', 'intrinsic', 'intrinsic', '.*'), re.I), 'intrinsic' intentpattern = re.compile(beforethisafter % ( '', 'intent|depend|note|check', 'intent|depend|note|check', r'\s*\(.*?\).*'), re.I), 'intent' parameterpattern = re.compile( @@ -706,7 +705,7 @@ def crackline(line, reset=0): for pat in [dimensionpattern, externalpattern, intentpattern, optionalpattern, requiredpattern, parameterpattern, datapattern, publicpattern, privatepattern, - intrisicpattern, + intrinsicpattern, endifpattern, endpattern, formatpattern, beginpattern, functionpattern, subroutinepattern, @@ -1098,7 +1097,7 @@ def analyzeline(m, case, line): last_name = updatevars(typespec, selector, attr, edecl) if last_name is not None: previous_context = ('variable', last_name, groupcounter) - elif case in ['dimension', 'intent', 'optional', 'required', 'external', 'public', 'private', 'intrisic']: + elif case in ['dimension', 'intent', 'optional', 'required', 'external', 'public', 'private', 'intrinsic']: edecl = groupcache[groupcounter]['vars'] ll = m.group('after').strip() i = ll.find('::') @@ -1158,7 +1157,7 @@ def analyzeline(m, case, line): else: errmess('analyzeline: intent(callback) %s is already' ' in argument list' % (k)) - if case in ['optional', 'required', 'public', 'external', 'private', 'intrisic']: + if case in ['optional', 'required', 'public', 'external', 'private', 'intrinsic']: ap = case if 'attrspec' in edecl[k]: edecl[k]['attrspec'].append(ap) @@ -1750,10 +1749,12 @@ def setattrspec(decl, attr, force=0): decl['attrspec'].append(attr) elif attr == 'automatic' and 'static' not in decl['attrspec']: decl['attrspec'].append(attr) - elif attr == 'public' and 'private' not in decl['attrspec']: - decl['attrspec'].append(attr) - elif attr == 'private' and 'public' not in decl['attrspec']: - decl['attrspec'].append(attr) + elif attr == 'public': + if 'private' not in decl['attrspec']: + decl['attrspec'].append(attr) + elif attr == 'private': + if 'public' not in decl['attrspec']: + decl['attrspec'].append(attr) else: decl['attrspec'].append(attr) return decl @@ -3114,11 +3115,12 @@ def true_intent_list(var): ret = [] for intent in lst: try: - c = eval('isintent_%s(var)' % intent) - except NameError: - c = 0 - if c: - ret.append(intent) + f = globals()['isintent_%s' % intent] + except KeyError: + pass + else: + if f(var): + ret.append(intent) return ret diff --git a/numpy/f2py/diagnose.py b/numpy/f2py/diagnose.py index 0241fed12..21ee399f0 100644 --- a/numpy/f2py/diagnose.py +++ b/numpy/f2py/diagnose.py @@ -1,6 +1,4 @@ -#!/usr/bin/env python -from __future__ import division, absolute_import, print_function - +#!/usr/bin/env python3 import os import sys import tempfile diff --git a/numpy/f2py/f2py2e.py b/numpy/f2py/f2py2e.py index 110337f92..71a049e41 100755 --- a/numpy/f2py/f2py2e.py +++ b/numpy/f2py/f2py2e.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """ f2py2e - Fortran to Python C/API generator. 2nd Edition. @@ -14,8 +14,6 @@ $Date: 2005/05/06 08:31:19 $ Pearu Peterson """ -from __future__ import division, absolute_import, print_function - import sys import os import pprint @@ -28,6 +26,7 @@ from . import auxfuncs from . import cfuncs from . import f90mod_rules from . import __version__ +from . import capi_maps f2py_version = __version__.version errmess = sys.stderr.write @@ -118,6 +117,9 @@ Options: --link-<resource> switch below. [..] is optional list of resources names. E.g. try 'f2py --help-link lapack_opt'. + --f2cmap <filename> Load Fortran-to-Python KIND specification from the given + file. Default: .f2py_f2cmap in current directory. + --quiet Run quietly. --verbose Run with extra verbosity. -v Print f2py version ID and exit. @@ -167,7 +169,7 @@ Extra options (only effective with -c): Version: %s numpy Version: %s -Requires: Python 2.3 or higher. +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/""" % (f2py_version, numpy_version) @@ -175,7 +177,7 @@ http://cens.ioc.ee/projects/f2py2e/""" % (f2py_version, numpy_version) def scaninputline(inputline): files, skipfuncs, onlyfuncs, debug = [], [], [], [] - f, f2, f3, f5, f6, f7, f8, f9 = 1, 0, 0, 0, 0, 0, 0, 0 + f, f2, f3, f5, f6, f7, f8, f9, f10 = 1, 0, 0, 0, 0, 0, 0, 0, 0 verbose = 1 dolc = -1 dolatexdoc = 0 @@ -226,6 +228,8 @@ def scaninputline(inputline): f8 = 1 elif l == '--f2py-wrapper-output': f9 = 1 + elif l == '--f2cmap': + f10 = 1 elif l == '--overwrite-signature': options['h-overwrite'] = 1 elif l == '-h': @@ -267,6 +271,9 @@ def scaninputline(inputline): elif f9: f9 = 0 options["f2py_wrapper_output"] = l + elif f10: + f10 = 0 + options["f2cmap_file"] = l elif f == 1: try: with open(l): @@ -312,6 +319,7 @@ def scaninputline(inputline): options['wrapfuncs'] = wrapfuncs options['buildpath'] = buildpath options['include_paths'] = include_paths + options.setdefault('f2cmap_file', None) return files, options @@ -422,6 +430,7 @@ def run_main(comline_list): fobjcsrc = os.path.join(f2pydir, 'src', 'fortranobject.c') files, options = scaninputline(comline_list) auxfuncs.options = options + capi_maps.load_f2cmap_file(options['f2cmap_file']) postlist = callcrackfortran(files, options) isusedby = {} for i in range(len(postlist)): @@ -574,7 +583,7 @@ def run_compile(): modulename = 'untitled' sources = sys.argv[1:] - for optname in ['--include_paths', '--include-paths']: + for optname in ['--include_paths', '--include-paths', '--f2cmap']: if optname in sys.argv: i = sys.argv.index(optname) f2py_flags.extend(sys.argv[i:i + 2]) diff --git a/numpy/f2py/f2py_testing.py b/numpy/f2py/f2py_testing.py index f5d5fa63d..1f109e67a 100644 --- a/numpy/f2py/f2py_testing.py +++ b/numpy/f2py/f2py_testing.py @@ -1,5 +1,3 @@ -from __future__ import division, absolute_import, print_function - import sys import re diff --git a/numpy/f2py/f90mod_rules.py b/numpy/f2py/f90mod_rules.py index 85eae8047..122fa8939 100644 --- a/numpy/f2py/f90mod_rules.py +++ b/numpy/f2py/f90mod_rules.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """ Build F90 module support for f2py2e. @@ -13,8 +13,6 @@ $Date: 2005/02/03 19:30:23 $ Pearu Peterson """ -from __future__ import division, absolute_import, print_function - __version__ = "$Revision: 1.27 $"[10:-1] f2py_version = 'See `f2py -v`' @@ -25,7 +23,7 @@ from . import capi_maps from . import func2subr from .crackfortran import undo_rmbadname, undo_rmbadname1 -# The eviroment provided by auxfuncs.py is needed for some calls to eval. +# The environment provided by auxfuncs.py is needed for some calls to eval. # 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 * @@ -87,7 +85,6 @@ fgetdims2_sa = """\ def buildhooks(pymod): - global fgetdims1, fgetdims2 from . import rules ret = {'f90modhooks': [], 'initf90modhooks': [], 'body': [], 'need': ['F_FUNC', 'arrayobject.h'], @@ -180,7 +177,7 @@ def buildhooks(pymod): (m['name'], undo_rmbadname1(n))) fadd('integer flag\n') fhooks[0] = fhooks[0] + fgetdims1 - dms = eval('range(1,%s+1)' % (dm['rank'])) + dms = range(1, int(dm['rank']) + 1) fadd(' allocate(d(%s))\n' % (','.join(['s(%s)' % i for i in dms]))) fhooks[0] = fhooks[0] + use_fgetdims2 diff --git a/numpy/f2py/func2subr.py b/numpy/f2py/func2subr.py index 6010d5a23..e9976f43c 100644 --- a/numpy/f2py/func2subr.py +++ b/numpy/f2py/func2subr.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """ Rules for building C/API module with f2py2e. @@ -13,8 +13,6 @@ $Date: 2004/11/26 11:13:06 $ Pearu Peterson """ -from __future__ import division, absolute_import, print_function - __version__ = "$Revision: 1.16 $"[10:-1] f2py_version = 'See `f2py -v`' diff --git a/numpy/f2py/rules.py b/numpy/f2py/rules.py index f2f713bde..6750bf705 100755 --- a/numpy/f2py/rules.py +++ b/numpy/f2py/rules.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """ Rules for building C/API module with f2py2e. @@ -50,8 +50,6 @@ $Date: 2005/08/30 08:58:42 $ Pearu Peterson """ -from __future__ import division, absolute_import, print_function - __version__ = "$Revision: 1.129 $"[10:-1] from . import __version__ @@ -180,7 +178,6 @@ static PyMethodDef f2py_module_methods[] = { \t{NULL,NULL} }; -#if PY_VERSION_HEX >= 0x03000000 static struct PyModuleDef moduledef = { \tPyModuleDef_HEAD_INIT, \t"#modulename#", @@ -192,35 +189,20 @@ static struct PyModuleDef moduledef = { \tNULL, \tNULL }; -#endif -#if PY_VERSION_HEX >= 0x03000000 -#define RETVAL m PyMODINIT_FUNC PyInit_#modulename#(void) { -#else -#define RETVAL -PyMODINIT_FUNC init#modulename#(void) { -#endif \tint i; \tPyObject *m,*d, *s, *tmp; -#if PY_VERSION_HEX >= 0x03000000 \tm = #modulename#_module = PyModule_Create(&moduledef); -#else -\tm = #modulename#_module = Py_InitModule(\"#modulename#\", f2py_module_methods); -#endif \tPy_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 RETVAL;} +\t\t{PyErr_SetString(PyExc_ImportError, \"can't initialize module #modulename# (failed to import numpy)\"); return m;} \td = PyModule_GetDict(m); \ts = PyString_FromString(\"$R""" + """evision: $\"); \tPyDict_SetItemString(d, \"__version__\", s); \tPy_DECREF(s); -#if PY_VERSION_HEX >= 0x03000000 \ts = PyUnicode_FromString( -#else -\ts = PyString_FromString( -#endif \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); @@ -245,7 +227,7 @@ PyMODINIT_FUNC init#modulename#(void) { \tif (! PyErr_Occurred()) \t\ton_exit(f2py_report_on_exit,(void*)\"#modulename#\"); #endif -\treturn RETVAL; +\treturn m; } #ifdef __cplusplus } @@ -294,7 +276,7 @@ static PyObject *#apiname#(const PyObject *capi_self, f2py_start_clock(); #endif \tif (!PyArg_ParseTupleAndKeywords(capi_args,capi_keywds,\\ -\t\t\"#argformat##keyformat##xaformat#:#pyname#\",\\ +\t\t\"#argformat#|#keyformat##xaformat#:#pyname#\",\\ \t\tcapi_kwlist#args_capi##keys_capi##keys_xa#))\n\t\treturn NULL; #frompyobj# /*end of frompyobj*/ @@ -448,11 +430,7 @@ rout_rules = [ tmp = F2PyCapsule_FromVoidPtr((void*)#F_FUNC#(#name_lower#,#NAME#),NULL); PyObject_SetAttrString(o,"_cpointer", tmp); Py_DECREF(tmp); -#if PY_VERSION_HEX >= 0x03000000 s = PyUnicode_FromString("#name#"); -#else - s = PyString_FromString("#name#"); -#endif PyObject_SetAttrString(o,"__name__", s); Py_DECREF(s); } @@ -490,11 +468,7 @@ rout_rules = [ tmp = F2PyCapsule_FromVoidPtr((void*)#F_FUNC#(#name_lower#,#NAME#),NULL); PyObject_SetAttrString(o,"_cpointer", tmp); Py_DECREF(tmp); -#if PY_VERSION_HEX >= 0x03000000 s = PyUnicode_FromString("#name#"); -#else - s = PyString_FromString("#name#"); -#endif PyObject_SetAttrString(o,"__name__", s); Py_DECREF(s); } @@ -1064,8 +1038,10 @@ if (#varname#_capi==Py_None) { '\tcapi_#varname#_tmp = array_from_pyobj(#atype#,#varname#_Dims,#varname#_Rank,capi_#varname#_intent,#varname#_capi);'}, """\ \tif (capi_#varname#_tmp == NULL) { -\t\tif (!PyErr_Occurred()) -\t\t\tPyErr_SetString(#modulename#_error,\"failed in converting #nth# `#varname#\' of #pyname# to C/Fortran array\" ); +\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)); """, @@ -1081,8 +1057,10 @@ if (#varname#_capi==Py_None) { \t\t\twhile ((_i = nextforcomb())) \t\t\t\t#varname#[capi_i++] = #init#; /* fortran way */ \t\t} else { -\t\t\tif (!PyErr_Occurred()) -\t\t\t\tPyErr_SetString(#modulename#_error,\"Initialization of #nth# #varname# failed (initforcomb).\"); +\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} @@ -1179,7 +1157,6 @@ def buildmodule(m, um): """ Return """ - global f2py_version, options outmess('\tBuilding module "%s"...\n' % (m['name'])) ret = {} mod_rules = defmod_rules[:] @@ -1467,16 +1444,6 @@ def buildapi(rout): ['\\begin{description}'] + rd[k][1:] +\ ['\\end{description}'] - # Workaround for Python 2.6, 2.6.1 bug: https://bugs.python.org/issue4720 - if rd['keyformat'] or rd['xaformat']: - argformat = rd['argformat'] - if isinstance(argformat, list): - argformat.append('|') - else: - assert isinstance(argformat, str), repr( - (argformat, type(argformat))) - rd['argformat'] += '|' - ar = applyrules(routine_rules, rd) if ismoduleroutine(rout): outmess('\t\t\t %s\n' % (ar['docshort'])) diff --git a/numpy/f2py/setup.py b/numpy/f2py/setup.py index a8c1401aa..6314c5af3 100644 --- a/numpy/f2py/setup.py +++ b/numpy/f2py/setup.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """ setup.py for installing F2PY @@ -16,8 +16,6 @@ $Date: 2005/01/30 17:22:14 $ Pearu Peterson """ -from __future__ import division, print_function - from numpy.distutils.core import setup from numpy.distutils.misc_util import Configuration diff --git a/numpy/f2py/src/fortranobject.c b/numpy/f2py/src/fortranobject.c index 8aa55555d..b3a04bcf0 100644 --- a/numpy/f2py/src/fortranobject.c +++ b/numpy/f2py/src/fortranobject.c @@ -115,14 +115,6 @@ fortran_dealloc(PyFortranObject *fp) { } -#if PY_VERSION_HEX >= 0x03000000 -#else -static PyMethodDef fortran_methods[] = { - {NULL, NULL} /* sentinel */ -}; -#endif - - /* 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) @@ -242,11 +234,7 @@ fortran_doc(FortranDataDef def) size--; /* p now points one beyond the last character of the string in buf */ -#if PY_VERSION_HEX >= 0x03000000 s = PyUnicode_FromStringAndSize(buf, p - buf); -#else - s = PyString_FromStringAndSize(buf, p - buf); -#endif PyMem_Free(buf); return s; @@ -272,8 +260,11 @@ static PyObject * fortran_getattr(PyFortranObject *fp, char *name) { int i,j,k,flag; if (fp->dict != NULL) { - PyObject *v = PyDict_GetItemString(fp->dict, name); - if (v != NULL) { + PyObject *v = _PyDict_GetItemStringWithError(fp->dict, name); + if (v == NULL && PyErr_Occurred()) { + return NULL; + } + else if (v != NULL) { Py_INCREF(v); return v; } @@ -306,7 +297,6 @@ fortran_getattr(PyFortranObject *fp, char *name) { return fp->dict; } if (strcmp(name,"__doc__")==0) { -#if PY_VERSION_HEX >= 0x03000000 PyObject *s = PyUnicode_FromString(""), *s2, *s3; for (i=0;i<fp->len;i++) { s2 = fortran_doc(fp->defs[i]); @@ -315,11 +305,6 @@ fortran_getattr(PyFortranObject *fp, char *name) { Py_DECREF(s); s = s3; } -#else - PyObject *s = PyString_FromString(""); - for (i=0;i<fp->len;i++) - PyString_ConcatAndDel(&s,fortran_doc(fp->defs[i])); -#endif if (PyDict_SetItemString(fp->dict, name, s)) return NULL; return s; @@ -330,17 +315,11 @@ fortran_getattr(PyFortranObject *fp, char *name) { return NULL; return cobj; } -#if PY_VERSION_HEX >= 0x03000000 - if (1) { - PyObject *str, *ret; - str = PyUnicode_FromString(name); - ret = PyObject_GenericGetAttr((PyObject *)fp, str); - Py_DECREF(str); - return ret; - } -#else - return Py_FindMethod(fortran_methods, (PyObject *)fp, name); -#endif + PyObject *str, *ret; + str = PyUnicode_FromString(name); + ret = PyObject_GenericGetAttr((PyObject *)fp, str); + Py_DECREF(str); + return ret; } static int @@ -434,48 +413,26 @@ fortran_repr(PyFortranObject *fp) PyObject *name = NULL, *repr = NULL; name = PyObject_GetAttrString((PyObject *)fp, "__name__"); PyErr_Clear(); -#if PY_VERSION_HEX >= 0x03000000 if (name != NULL && PyUnicode_Check(name)) { repr = PyUnicode_FromFormat("<fortran %U>", name); } else { repr = PyUnicode_FromString("<fortran object>"); } -#else - if (name != NULL && PyString_Check(name)) { - repr = PyString_FromFormat("<fortran %s>", PyString_AsString(name)); - } - else { - repr = PyString_FromString("<fortran object>"); - } -#endif Py_XDECREF(name); return repr; } PyTypeObject PyFortran_Type = { -#if PY_VERSION_HEX >= 0x03000000 PyVarObject_HEAD_INIT(NULL, 0) -#else - PyObject_HEAD_INIT(0) - 0, /*ob_size*/ -#endif - "fortran", /*tp_name*/ - sizeof(PyFortranObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - /* methods */ - (destructor)fortran_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - (getattrfunc)fortran_getattr, /*tp_getattr*/ - (setattrfunc)fortran_setattr, /*tp_setattr*/ - 0, /*tp_compare/tp_reserved*/ - (reprfunc)fortran_repr, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash*/ - (ternaryfunc)fortran_call, /*tp_call*/ + .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 *******************************/ @@ -626,7 +583,7 @@ count_negative_dimensions(const int rank, } #ifdef DEBUG_COPY_ND_ARRAY -void dump_dims(int rank, npy_intp* dims) { +void dump_dims(int rank, npy_intp const* dims) { int i; printf("["); for(i=0;i<rank;++i) { @@ -839,9 +796,10 @@ PyArrayObject* array_from_pyobj(const int type_num, if ((intent & F2PY_INTENT_INOUT) || (intent & F2PY_INTENT_INPLACE) || (intent & F2PY_INTENT_CACHE)) { - PyErr_SetString(PyExc_TypeError, - "failed to initialize intent(inout|inplace|cache) " - "array, input not an array"); + PyErr_Format(PyExc_TypeError, + "failed to initialize intent(inout|inplace|cache) " + "array, input '%s' object is not an array", + Py_TYPE(obj)->tp_name); return NULL; } @@ -1052,8 +1010,6 @@ int copy_ND_array(const PyArrayObject *arr, PyArrayObject *out) /* Compatibility functions for Python >= 3.0 */ /*********************************************/ -#if PY_VERSION_HEX >= 0x03000000 - PyObject * F2PyCapsule_FromVoidPtr(void *ptr, void (*dtor)(PyObject *)) { @@ -1080,29 +1036,6 @@ F2PyCapsule_Check(PyObject *ptr) return PyCapsule_CheckExact(ptr); } -#else - -PyObject * -F2PyCapsule_FromVoidPtr(void *ptr, void (*dtor)(void *)) -{ - return PyCObject_FromVoidPtr(ptr, dtor); -} - -void * -F2PyCapsule_AsVoidPtr(PyObject *ptr) -{ - return PyCObject_AsVoidPtr(ptr); -} - -int -F2PyCapsule_Check(PyObject *ptr) -{ - return PyCObject_Check(ptr); -} - -#endif - - #ifdef __cplusplus } #endif diff --git a/numpy/f2py/src/fortranobject.h b/numpy/f2py/src/fortranobject.h index 5d0dcf676..5c382ab7b 100644 --- a/numpy/f2py/src/fortranobject.h +++ b/numpy/f2py/src/fortranobject.h @@ -11,30 +11,7 @@ extern "C" { #endif #define PY_ARRAY_UNIQUE_SYMBOL _npy_f2py_ARRAY_API #include "numpy/arrayobject.h" - -/* - * Python 3 support macros - */ -#if PY_VERSION_HEX >= 0x03000000 -#define PyString_Check PyBytes_Check -#define PyString_GET_SIZE PyBytes_GET_SIZE -#define PyString_AS_STRING PyBytes_AS_STRING -#define PyString_FromString PyBytes_FromString -#define PyUString_FromStringAndSize PyUnicode_FromStringAndSize -#define PyString_ConcatAndDel PyBytes_ConcatAndDel -#define PyString_AsString PyBytes_AsString - -#define PyInt_Check PyLong_Check -#define PyInt_FromLong PyLong_FromLong -#define PyInt_AS_LONG PyLong_AsLong -#define PyInt_AsLong PyLong_AsLong - -#define PyNumber_Int PyNumber_Long - -#else - -#define PyUString_FromStringAndSize PyString_FromStringAndSize -#endif +#include "numpy/npy_3kcompat.h" #ifdef F2PY_REPORT_ATEXIT @@ -105,20 +82,10 @@ typedef struct { extern PyObject * PyFortranObject_New(FortranDataDef* defs, f2py_void_func init); extern PyObject * PyFortranObject_NewAsAttr(FortranDataDef* defs); -#if PY_VERSION_HEX >= 0x03000000 - PyObject * F2PyCapsule_FromVoidPtr(void *ptr, void (*dtor)(PyObject *)); void * F2PyCapsule_AsVoidPtr(PyObject *obj); int F2PyCapsule_Check(PyObject *ptr); -#else - -PyObject * F2PyCapsule_FromVoidPtr(void *ptr, void (*dtor)(void *)); -void * F2PyCapsule_AsVoidPtr(PyObject *ptr); -int F2PyCapsule_Check(PyObject *ptr); - -#endif - #define ISCONTIGUOUS(m) (PyArray_FLAGS(m) & NPY_ARRAY_C_CONTIGUOUS) #define F2PY_INTENT_IN 1 #define F2PY_INTENT_INOUT 2 diff --git a/numpy/f2py/tests/src/array_from_pyobj/wrapmodule.c b/numpy/f2py/tests/src/array_from_pyobj/wrapmodule.c index 978db4e69..83c0da2cf 100644 --- a/numpy/f2py/tests/src/array_from_pyobj/wrapmodule.c +++ b/numpy/f2py/tests/src/array_from_pyobj/wrapmodule.c @@ -129,7 +129,6 @@ static PyMethodDef f2py_module_methods[] = { {NULL,NULL} }; -#if PY_VERSION_HEX >= 0x03000000 static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "test_array_from_pyobj_ext", @@ -141,21 +140,10 @@ static struct PyModuleDef moduledef = { NULL, NULL }; -#endif -#if PY_VERSION_HEX >= 0x03000000 -#define RETVAL m PyMODINIT_FUNC PyInit_test_array_from_pyobj_ext(void) { -#else -#define RETVAL -PyMODINIT_FUNC inittest_array_from_pyobj_ext(void) { -#endif PyObject *m,*d, *s; -#if PY_VERSION_HEX >= 0x03000000 m = wrap_module = PyModule_Create(&moduledef); -#else - m = wrap_module = Py_InitModule("test_array_from_pyobj_ext", f2py_module_methods); -#endif Py_TYPE(&PyFortran_Type) = &PyType_Type; import_array(); if (PyErr_Occurred()) @@ -238,7 +226,7 @@ PyMODINIT_FUNC inittest_array_from_pyobj_ext(void) { on_exit(f2py_report_on_exit,(void*)"array_from_pyobj.wrap.call"); #endif - return RETVAL; + return m; } #ifdef __cplusplus } diff --git a/numpy/f2py/tests/test_array_from_pyobj.py b/numpy/f2py/tests/test_array_from_pyobj.py index a80090185..b719f2495 100644 --- a/numpy/f2py/tests/test_array_from_pyobj.py +++ b/numpy/f2py/tests/test_array_from_pyobj.py @@ -1,5 +1,3 @@ -from __future__ import division, absolute_import, print_function - import os import sys import copy @@ -57,7 +55,7 @@ def flags2names(flags): return info -class Intent(object): +class Intent: def __init__(self, intent_list=[]): self.intent_list = intent_list[:] @@ -131,7 +129,7 @@ if ((intp().dtype.itemsize != 4 or clongdouble().dtype.alignment <= 8) and _cast_dict['CDOUBLE'] = _cast_dict['DOUBLE'] + ['CFLOAT', 'CDOUBLE'] -class Type(object): +class Type: _type_cache = {} def __new__(cls, name): @@ -192,7 +190,7 @@ class Type(object): return types -class Array(object): +class Array: def __init__(self, typ, dims, intent, obj): self.type = typ @@ -293,7 +291,7 @@ class Array(object): return obj_attr[0] == self.arr_attr[0] -class TestIntent(object): +class TestIntent: def test_in_out(self): assert_equal(str(intent.in_.out), 'intent(in,out)') @@ -304,7 +302,7 @@ class TestIntent(object): assert_(not intent.in_.is_intent('c')) -class TestSharedMemory(object): +class TestSharedMemory: num2seq = [1, 2] num23seq = [[1, 2, 3], [4, 5, 6]] diff --git a/numpy/f2py/tests/test_assumed_shape.py b/numpy/f2py/tests/test_assumed_shape.py index 460afd68d..dfc252660 100644 --- a/numpy/f2py/tests/test_assumed_shape.py +++ b/numpy/f2py/tests/test_assumed_shape.py @@ -1,7 +1,6 @@ -from __future__ import division, absolute_import, print_function - import os import pytest +import tempfile from numpy.testing import assert_ from . import util @@ -16,6 +15,7 @@ class TestAssumedShapeSumExample(util.F2PyTest): _path('src', 'assumed_shape', 'foo_use.f90'), _path('src', 'assumed_shape', 'precision.f90'), _path('src', 'assumed_shape', 'foo_mod.f90'), + _path('src', 'assumed_shape', '.f2py_f2cmap'), ] @pytest.mark.slow @@ -31,3 +31,23 @@ class TestAssumedShapeSumExample(util.F2PyTest): assert_(r == 3, repr(r)) r = self.module.mod.fsum([1, 2]) assert_(r == 3, repr(r)) + + +class TestF2cmapOption(TestAssumedShapeSumExample): + def setup(self): + # Use a custom file name for .f2py_f2cmap + self.sources = list(self.sources) + f2cmap_src = self.sources.pop(-1) + + self.f2cmap_file = tempfile.NamedTemporaryFile(delete=False) + with open(f2cmap_src, 'rb') as f: + self.f2cmap_file.write(f.read()) + self.f2cmap_file.close() + + self.sources.append(self.f2cmap_file.name) + self.options = ["--f2cmap", self.f2cmap_file.name] + + super(TestF2cmapOption, self).setup() + + def teardown(self): + os.unlink(self.f2cmap_file.name) diff --git a/numpy/f2py/tests/test_block_docstring.py b/numpy/f2py/tests/test_block_docstring.py index 4f1678980..e431f5ba6 100644 --- a/numpy/f2py/tests/test_block_docstring.py +++ b/numpy/f2py/tests/test_block_docstring.py @@ -1,5 +1,3 @@ -from __future__ import division, absolute_import, print_function - import sys import pytest from . import util @@ -18,7 +16,8 @@ class TestBlockDocString(util.F2PyTest): @pytest.mark.skipif(sys.platform=='win32', reason='Fails with MinGW64 Gfortran (Issue #9673)') - @pytest.mark.xfail(IS_PYPY, reason="PyPy does not modify tp_doc") + @pytest.mark.xfail(IS_PYPY, + reason="PyPy cannot modify tp_doc after PyType_Ready") def test_block_docstring(self): expected = "'i'-array(2,3)\n" assert_equal(self.module.block.__doc__, expected) diff --git a/numpy/f2py/tests/test_callback.py b/numpy/f2py/tests/test_callback.py index 21c29ba5f..4e29ab9fc 100644 --- a/numpy/f2py/tests/test_callback.py +++ b/numpy/f2py/tests/test_callback.py @@ -1,12 +1,10 @@ -from __future__ import division, absolute_import, print_function - import math import textwrap import sys import pytest import numpy as np -from numpy.testing import assert_, assert_equal +from numpy.testing import assert_, assert_equal, IS_PYPY from . import util @@ -61,12 +59,12 @@ cf2py intent(out) a end """ - @pytest.mark.slow @pytest.mark.parametrize('name', 't,t2'.split(',')) def test_all(self, name): self.check_function(name) - @pytest.mark.slow + @pytest.mark.xfail(IS_PYPY, + reason="PyPy cannot modify tp_doc after PyType_Ready") def test_docstring(self): expected = textwrap.dedent("""\ a = t(fun,[fun_extra_args]) @@ -118,7 +116,7 @@ cf2py intent(out) a r = t(self.module.func0._cpointer) assert_(r == 11, repr(r)) - class A(object): + class A: def __call__(self): return 7 diff --git a/numpy/f2py/tests/test_common.py b/numpy/f2py/tests/test_common.py index dcb01b0ec..e4bf35504 100644 --- a/numpy/f2py/tests/test_common.py +++ b/numpy/f2py/tests/test_common.py @@ -1,5 +1,3 @@ -from __future__ import division, absolute_import, print_function - import os import sys import pytest diff --git a/numpy/f2py/tests/test_compile_function.py b/numpy/f2py/tests/test_compile_function.py index 40ea7997f..f76fd6448 100644 --- a/numpy/f2py/tests/test_compile_function.py +++ b/numpy/f2py/tests/test_compile_function.py @@ -1,8 +1,6 @@ """See https://github.com/numpy/numpy/pull/11937. """ -from __future__ import division, absolute_import, print_function - import sys import os import uuid @@ -16,8 +14,6 @@ from . import util def setup_module(): - if sys.platform == 'win32' and sys.version_info[0] < 3: - pytest.skip('Fails with MinGW64 Gfortran (Issue #9673)') if not util.has_c_compiler(): pytest.skip("Needs C compiler") if not util.has_f77_compiler(): diff --git a/numpy/f2py/tests/test_crackfortran.py b/numpy/f2py/tests/test_crackfortran.py new file mode 100644 index 000000000..735804024 --- /dev/null +++ b/numpy/f2py/tests/test_crackfortran.py @@ -0,0 +1,88 @@ +import numpy as np +from numpy.testing import assert_array_equal +from . import util +from numpy.f2py import crackfortran +import tempfile +import textwrap + + +class TestNoSpace(util.F2PyTest): + # issue gh-15035: add handling for endsubroutine, endfunction with no space + # between "end" and the block name + code = """ + subroutine subb(k) + real(8), intent(inout) :: k(:) + k=k+1 + endsubroutine + + subroutine subc(w,k) + real(8), intent(in) :: w(:) + real(8), intent(out) :: k(size(w)) + k=w+1 + endsubroutine + + function t0(value) + character value + character t0 + t0 = value + endfunction + """ + + def test_module(self): + k = np.array([1, 2, 3], dtype=np.float64) + w = np.array([1, 2, 3], dtype=np.float64) + self.module.subb(k) + assert_array_equal(k, w + 1) + self.module.subc([w, k]) + assert_array_equal(k, w + 1) + assert self.module.t0(23) == b'2' + +class TestPublicPrivate(): + def test_defaultPrivate(self, tmp_path): + f_path = tmp_path / "mod.f90" + with f_path.open('w') as ff: + ff.write(textwrap.dedent("""\ + module foo + private + integer :: a + public :: setA + integer :: b + contains + subroutine setA(v) + integer, intent(in) :: v + a = v + end subroutine setA + end module foo + """)) + mod = crackfortran.crackfortran([str(f_path)]) + assert len(mod) == 1 + mod = mod[0] + assert 'private' in mod['vars']['a']['attrspec'] + assert 'public' not in mod['vars']['a']['attrspec'] + assert 'private' in mod['vars']['b']['attrspec'] + assert 'public' not in mod['vars']['b']['attrspec'] + assert 'private' not in mod['vars']['seta']['attrspec'] + assert 'public' in mod['vars']['seta']['attrspec'] + + def test_defaultPublic(self, tmp_path): + f_path = tmp_path / "mod.f90" + with f_path.open('w') as ff: + ff.write(textwrap.dedent("""\ + module foo + public + integer, private :: a + public :: setA + contains + subroutine setA(v) + integer, intent(in) :: v + a = v + end subroutine setA + end module foo + """)) + mod = crackfortran.crackfortran([str(f_path)]) + assert len(mod) == 1 + mod = mod[0] + assert 'private' in mod['vars']['a']['attrspec'] + assert 'public' not in mod['vars']['a']['attrspec'] + assert 'private' not in mod['vars']['seta']['attrspec'] + assert 'public' in mod['vars']['seta']['attrspec'] diff --git a/numpy/f2py/tests/test_kind.py b/numpy/f2py/tests/test_kind.py index 1f7762a80..a7e2b28ed 100644 --- a/numpy/f2py/tests/test_kind.py +++ b/numpy/f2py/tests/test_kind.py @@ -1,5 +1,3 @@ -from __future__ import division, absolute_import, print_function - import os import pytest diff --git a/numpy/f2py/tests/test_mixed.py b/numpy/f2py/tests/test_mixed.py index 0337538ff..04266ca5b 100644 --- a/numpy/f2py/tests/test_mixed.py +++ b/numpy/f2py/tests/test_mixed.py @@ -1,10 +1,8 @@ -from __future__ import division, absolute_import, print_function - import os import textwrap import pytest -from numpy.testing import assert_, assert_equal +from numpy.testing import assert_, assert_equal, IS_PYPY from . import util @@ -17,13 +15,13 @@ class TestMixed(util.F2PyTest): _path('src', 'mixed', 'foo_fixed.f90'), _path('src', 'mixed', 'foo_free.f90')] - @pytest.mark.slow def test_all(self): assert_(self.module.bar11() == 11) assert_(self.module.foo_fixed.bar12() == 12) assert_(self.module.foo_free.bar13() == 13) - @pytest.mark.slow + @pytest.mark.xfail(IS_PYPY, + reason="PyPy cannot modify tp_doc after PyType_Ready") def test_docstring(self): expected = textwrap.dedent("""\ a = bar11() diff --git a/numpy/f2py/tests/test_parameter.py b/numpy/f2py/tests/test_parameter.py index 6a378687a..b61827169 100644 --- a/numpy/f2py/tests/test_parameter.py +++ b/numpy/f2py/tests/test_parameter.py @@ -1,5 +1,3 @@ -from __future__ import division, absolute_import, print_function - import os import pytest diff --git a/numpy/f2py/tests/test_quoted_character.py b/numpy/f2py/tests/test_quoted_character.py index c9a1c36f5..20c77666c 100644 --- a/numpy/f2py/tests/test_quoted_character.py +++ b/numpy/f2py/tests/test_quoted_character.py @@ -1,10 +1,7 @@ """See https://github.com/numpy/numpy/pull/10676. """ -from __future__ import division, absolute_import, print_function - import sys -from importlib import import_module import pytest from numpy.testing import assert_equal diff --git a/numpy/f2py/tests/test_regression.py b/numpy/f2py/tests/test_regression.py index 3adae635d..67e00f1f7 100644 --- a/numpy/f2py/tests/test_regression.py +++ b/numpy/f2py/tests/test_regression.py @@ -1,5 +1,3 @@ -from __future__ import division, absolute_import, print_function - import os import pytest diff --git a/numpy/f2py/tests/test_return_character.py b/numpy/f2py/tests/test_return_character.py index fc3a58d36..429e69bb4 100644 --- a/numpy/f2py/tests/test_return_character.py +++ b/numpy/f2py/tests/test_return_character.py @@ -1,16 +1,15 @@ -from __future__ import division, absolute_import, print_function - import pytest from numpy import array from numpy.testing import assert_ from . import util +import platform +IS_S390X = platform.machine() == 's390x' class TestReturnCharacter(util.F2PyTest): - def check_function(self, t): - tname = t.__doc__.split()[0] + def check_function(self, t, tname): if tname in ['t0', 't1', 's0', 's1']: assert_(t(23) == b'2') r = t('ab') @@ -81,10 +80,10 @@ cf2py intent(out) ts end """ - @pytest.mark.slow + @pytest.mark.xfail(IS_S390X, reason="calback 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)) + self.check_function(getattr(self.module, name), name) class TestF90ReturnCharacter(TestReturnCharacter): @@ -140,7 +139,7 @@ module f90_return_char end module f90_return_char """ - @pytest.mark.slow + @pytest.mark.xfail(IS_S390X, reason="calback 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)) + self.check_function(getattr(self.module.f90_return_char, name), name) diff --git a/numpy/f2py/tests/test_return_complex.py b/numpy/f2py/tests/test_return_complex.py index 43c884dfb..3d2e2b94f 100644 --- a/numpy/f2py/tests/test_return_complex.py +++ b/numpy/f2py/tests/test_return_complex.py @@ -1,24 +1,20 @@ -from __future__ import division, absolute_import, print_function - import pytest from numpy import array -from numpy.compat import long from numpy.testing import assert_, assert_raises from . import util class TestReturnComplex(util.F2PyTest): - def check_function(self, t): - tname = t.__doc__.split()[0] + def check_function(self, t, tname): if tname in ['t0', 't8', 's0', 's8']: err = 1e-5 else: err = 0.0 assert_(abs(t(234j) - 234.0j) <= err) assert_(abs(t(234.6) - 234.6) <= err) - assert_(abs(t(long(234)) - 234.0) <= err) + assert_(abs(t(234) - 234.0) <= err) assert_(abs(t(234.6 + 3j) - (234.6 + 3j)) <= err) #assert_( abs(t('234')-234.)<=err) #assert_( abs(t('234.6')-234.6)<=err) @@ -104,10 +100,9 @@ cf2py intent(out) td end """ - @pytest.mark.slow @pytest.mark.parametrize('name', 't0,t8,t16,td,s0,s8,s16,sd'.split(',')) def test_all(self, name): - self.check_function(getattr(self.module, name)) + self.check_function(getattr(self.module, name), name) class TestF90ReturnComplex(TestReturnComplex): @@ -163,7 +158,6 @@ module f90_return_complex end module f90_return_complex """ - @pytest.mark.slow @pytest.mark.parametrize('name', 't0,t8,t16,td,s0,s8,s16,sd'.split(',')) def test_all(self, name): - self.check_function(getattr(self.module.f90_return_complex, name)) + self.check_function(getattr(self.module.f90_return_complex, name), name) diff --git a/numpy/f2py/tests/test_return_integer.py b/numpy/f2py/tests/test_return_integer.py index 22f4acfdf..0a8121dc1 100644 --- a/numpy/f2py/tests/test_return_integer.py +++ b/numpy/f2py/tests/test_return_integer.py @@ -1,19 +1,15 @@ -from __future__ import division, absolute_import, print_function - import pytest from numpy import array -from numpy.compat import long from numpy.testing import assert_, assert_raises from . import util class TestReturnInteger(util.F2PyTest): - def check_function(self, t): + def check_function(self, t, tname): assert_(t(123) == 123, repr(t(123))) assert_(t(123.6) == 123) - assert_(t(long(123)) == 123) assert_(t('123') == 123) assert_(t(-123) == -123) assert_(t([123]) == 123) @@ -38,7 +34,7 @@ class TestReturnInteger(util.F2PyTest): assert_raises(Exception, t, t) assert_raises(Exception, t, {}) - if t.__doc__.split()[0] in ['t8', 's8']: + if tname in ['t8', 's8']: assert_raises(OverflowError, t, 100000000000000000000000) assert_raises(OverflowError, t, 10000000011111111111111.23) @@ -103,11 +99,10 @@ cf2py intent(out) t8 end """ - @pytest.mark.slow @pytest.mark.parametrize('name', 't0,t1,t2,t4,t8,s0,s1,s2,s4,s8'.split(',')) def test_all(self, name): - self.check_function(getattr(self.module, name)) + self.check_function(getattr(self.module, name), name) class TestF90ReturnInteger(TestReturnInteger): @@ -174,8 +169,7 @@ module f90_return_integer end module f90_return_integer """ - @pytest.mark.slow @pytest.mark.parametrize('name', 't0,t1,t2,t4,t8,s0,s1,s2,s4,s8'.split(',')) def test_all(self, name): - self.check_function(getattr(self.module.f90_return_integer, name)) + self.check_function(getattr(self.module.f90_return_integer, name), name) diff --git a/numpy/f2py/tests/test_return_logical.py b/numpy/f2py/tests/test_return_logical.py index 96f215a91..9db939c7e 100644 --- a/numpy/f2py/tests/test_return_logical.py +++ b/numpy/f2py/tests/test_return_logical.py @@ -1,9 +1,6 @@ -from __future__ import division, absolute_import, print_function - import pytest from numpy import array -from numpy.compat import long from numpy.testing import assert_, assert_raises from . import util @@ -20,7 +17,6 @@ class TestReturnLogical(util.F2PyTest): assert_(t(1j) == 1) assert_(t(234) == 1) assert_(t(234.6) == 1) - assert_(t(long(234)) == 1) assert_(t(234.6 + 3j) == 1) assert_(t('234') == 1) assert_(t('aaa') == 1) diff --git a/numpy/f2py/tests/test_return_real.py b/numpy/f2py/tests/test_return_real.py index 315cfe49b..8e5022a8e 100644 --- a/numpy/f2py/tests/test_return_real.py +++ b/numpy/f2py/tests/test_return_real.py @@ -1,24 +1,20 @@ -from __future__ import division, absolute_import, print_function - import platform import pytest from numpy import array -from numpy.compat import long from numpy.testing import assert_, assert_raises from . import util class TestReturnReal(util.F2PyTest): - def check_function(self, t): - if t.__doc__.split()[0] in ['t0', 't4', 's0', 's4']: + def check_function(self, t, tname): + if tname in ['t0', 't4', 's0', 's4']: err = 1e-5 else: err = 0.0 assert_(abs(t(234) - 234.0) <= err) assert_(abs(t(234.6) - 234.6) <= err) - assert_(abs(t(long(234)) - 234.0) <= err) assert_(abs(t('234') - 234) <= err) assert_(abs(t('234.6') - 234.6) <= err) assert_(abs(t(-234) + 234) <= err) @@ -34,7 +30,7 @@ class TestReturnReal(util.F2PyTest): assert_(abs(t(array([234], 'B')) - 234.) <= err) assert_(abs(t(array([234], 'f')) - 234.) <= err) assert_(abs(t(array([234], 'd')) - 234.) <= err) - if t.__doc__.split()[0] in ['t0', 't4', 's0', 's4']: + if tname in ['t0', 't4', 's0', 's4']: assert_(t(1e200) == t(1e300)) # inf #assert_raises(ValueError, t, array([234], 'S1')) @@ -90,10 +86,9 @@ end interface end python module c_ext_return_real """ - @pytest.mark.slow @pytest.mark.parametrize('name', 't4,t8,s4,s8'.split(',')) def test_all(self, name): - self.check_function(getattr(self.module, name)) + self.check_function(getattr(self.module, name), name) class TestF77ReturnReal(TestReturnReal): @@ -145,10 +140,9 @@ cf2py intent(out) td end """ - @pytest.mark.slow @pytest.mark.parametrize('name', 't0,t4,t8,td,s0,s4,s8,sd'.split(',')) def test_all(self, name): - self.check_function(getattr(self.module, name)) + self.check_function(getattr(self.module, name), name) class TestF90ReturnReal(TestReturnReal): @@ -204,7 +198,6 @@ module f90_return_real end module f90_return_real """ - @pytest.mark.slow @pytest.mark.parametrize('name', 't0,t4,t8,td,s0,s4,s8,sd'.split(',')) def test_all(self, name): - self.check_function(getattr(self.module.f90_return_real, name)) + self.check_function(getattr(self.module.f90_return_real, name), name) diff --git a/numpy/f2py/tests/test_semicolon_split.py b/numpy/f2py/tests/test_semicolon_split.py index bcd18c893..d8b4bf222 100644 --- a/numpy/f2py/tests/test_semicolon_split.py +++ b/numpy/f2py/tests/test_semicolon_split.py @@ -1,5 +1,3 @@ -from __future__ import division, absolute_import, print_function - import platform import pytest diff --git a/numpy/f2py/tests/test_size.py b/numpy/f2py/tests/test_size.py index e2af61804..b609fa77f 100644 --- a/numpy/f2py/tests/test_size.py +++ b/numpy/f2py/tests/test_size.py @@ -1,5 +1,3 @@ -from __future__ import division, absolute_import, print_function - import os import pytest diff --git a/numpy/f2py/tests/test_string.py b/numpy/f2py/tests/test_string.py index 0493c99cf..e3ec96af9 100644 --- a/numpy/f2py/tests/test_string.py +++ b/numpy/f2py/tests/test_string.py @@ -1,5 +1,3 @@ -from __future__ import division, absolute_import, print_function - import os import pytest diff --git a/numpy/f2py/tests/util.py b/numpy/f2py/tests/util.py index 77cb612d0..c5b06697d 100644 --- a/numpy/f2py/tests/util.py +++ b/numpy/f2py/tests/util.py @@ -5,8 +5,6 @@ Utility functions for - detecting if compilers are present """ -from __future__ import division, absolute_import, print_function - import os import sys import subprocess @@ -21,10 +19,7 @@ from numpy.compat import asbytes, asstr from numpy.testing import temppath from importlib import import_module -try: - from hashlib import md5 -except ImportError: - from md5 import new as md5 # noqa: F401 +from hashlib import md5 # # Maintaining a temporary module directory @@ -107,6 +102,7 @@ def build_module(source_files, options=[], skip=[], only=[], module_name=None): # Copy files dst_sources = [] + f2py_sources = [] for fn in source_files: if not os.path.isfile(fn): raise RuntimeError("%s is not a file" % fn) @@ -114,16 +110,14 @@ def build_module(source_files, options=[], skip=[], only=[], module_name=None): shutil.copyfile(fn, dst) dst_sources.append(dst) - fn = os.path.join(os.path.dirname(fn), '.f2py_f2cmap') - if os.path.isfile(fn): - dst = os.path.join(d, os.path.basename(fn)) - if not os.path.isfile(dst): - shutil.copyfile(fn, dst) + base, ext = os.path.splitext(dst) + if ext in ('.f90', '.f', '.c', '.pyf'): + f2py_sources.append(dst) # Prepare options if module_name is None: module_name = get_temp_module_name() - f2py_opts = ['-c', '-m', module_name] + options + dst_sources + f2py_opts = ['-c', '-m', module_name] + options + f2py_sources if skip: f2py_opts += ['skip:'] + skip if only: @@ -205,14 +199,20 @@ def _get_compiler_status(): """) code = code % dict(syspath=repr(sys.path)) - with temppath(suffix='.py') as script: + tmpdir = tempfile.mkdtemp() + try: + script = os.path.join(tmpdir, 'setup.py') + with open(script, 'w') as f: f.write(code) - cmd = [sys.executable, script, 'config'] + cmd = [sys.executable, 'setup.py', 'config'] p = subprocess.Popen(cmd, stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) + stderr=subprocess.STDOUT, + cwd=tmpdir) out, err = p.communicate() + finally: + shutil.rmtree(tmpdir) m = re.search(br'COMPILERS:(\d+),(\d+),(\d+)', out) if m: @@ -279,9 +279,8 @@ def build_module_distutils(source_files, config_code, module_name, **kw): script = os.path.join(d, get_temp_module_name() + '.py') dst_sources.append(script) - f = open(script, 'wb') - f.write(asbytes(code)) - f.close() + with open(script, 'wb') as f: + f.write(asbytes(code)) # Build cwd = os.getcwd() @@ -310,7 +309,7 @@ def build_module_distutils(source_files, config_code, module_name, **kw): # -class F2PyTest(object): +class F2PyTest: code = None sources = None options = [] diff --git a/numpy/f2py/use_rules.py b/numpy/f2py/use_rules.py index 6f44f1634..f1b71e83c 100644 --- a/numpy/f2py/use_rules.py +++ b/numpy/f2py/use_rules.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """ Build 'use others module data' mechanism for f2py2e. @@ -15,8 +15,6 @@ $Date: 2000/09/10 12:35:43 $ Pearu Peterson """ -from __future__ import division, absolute_import, print_function - __version__ = "$Revision: 1.3 $"[10:-1] f2py_version = 'See `f2py -v`' |