From 26a2f584dc79cb0ef02ca41f4785152b8041c71b Mon Sep 17 00:00:00 2001 From: Pearu Peterson Date: Mon, 18 Jan 2021 15:19:46 +0200 Subject: BUG: Fix detecting Fortran 90+ source format. --- numpy/distutils/fcompiler/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numpy/distutils/fcompiler/__init__.py b/numpy/distutils/fcompiler/__init__.py index 4730a5a09..812461538 100644 --- a/numpy/distutils/fcompiler/__init__.py +++ b/numpy/distutils/fcompiler/__init__.py @@ -976,7 +976,7 @@ def is_free_format(file): with open(file, encoding='latin1') as f: line = f.readline() n = 10000 # the number of non-comment lines to scan for hints - if _has_f_header(line): + if _has_f_header(line) or _has_fix_header(line): n = 0 elif _has_f90_header(line): n = 0 -- cgit v1.2.1 From a2f6fbb5b068a4e589bd95b8774d3624062c0995 Mon Sep 17 00:00:00 2001 From: Pearu Peterson Date: Mon, 18 Jan 2021 15:22:54 +0200 Subject: BUG: subroutines using assumed shape arrays must be treated as F90 codes. Don't split inline comments. --- numpy/f2py/rules.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/numpy/f2py/rules.py b/numpy/f2py/rules.py index f1490527e..12ed1f1ca 100755 --- a/numpy/f2py/rules.py +++ b/numpy/f2py/rules.py @@ -1186,7 +1186,7 @@ def buildmodule(m, um): for nb in nb_list: api, wrap = buildapi(nb) if wrap: - if ismoduleroutine(nb): + if ismoduleroutine(nb) or issubroutine_wrap(nb): funcwrappers2.append(wrap) else: funcwrappers.append(wrap) @@ -1310,7 +1310,11 @@ def buildmodule(m, um): '! It contains Fortran 90 wrappers to fortran functions.\n') lines = [] for l in ('\n\n'.join(funcwrappers2) + '\n').split('\n'): - if len(l) > 72 and l[0] == ' ': + i = l.find('!') + if i >= 0 and i < 72: + # don't split comment lines + lines.append(l + '\n') + elif len(l) > 72 and l[0] == ' ': lines.append(l[:72] + '&\n &') l = l[72:] while len(l) > 66: -- cgit v1.2.1 From 36439a7d0e0896703823c68d116b9900e49df998 Mon Sep 17 00:00:00 2001 From: Pearu Peterson Date: Mon, 18 Jan 2021 15:24:24 +0200 Subject: BUG: f2py specific __user__ modules should not be used in Fortran sources to be compiled. Closes #17797. --- numpy/f2py/func2subr.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/numpy/f2py/func2subr.py b/numpy/f2py/func2subr.py index e9976f43c..21d4c009c 100644 --- a/numpy/f2py/func2subr.py +++ b/numpy/f2py/func2subr.py @@ -130,7 +130,7 @@ def createfuncwrapper(rout, signature=0): l = l + ', ' + fortranname if need_interface: for line in rout['saved_interface'].split('\n'): - if line.lstrip().startswith('use '): + if line.lstrip().startswith('use ') and '__user__' not in line: add(line) args = args[1:] @@ -222,7 +222,7 @@ def createsubrwrapper(rout, signature=0): if need_interface: for line in rout['saved_interface'].split('\n'): - if line.lstrip().startswith('use '): + if line.lstrip().startswith('use ') and '__user__' not in line: add(line) dumped_args = [] @@ -247,7 +247,10 @@ def createsubrwrapper(rout, signature=0): pass else: add('interface') - add(rout['saved_interface'].lstrip()) + for line in rout['saved_interface'].split('\n'): + if line.lstrip().startswith('use ') and '__user__' in line: + continue + add(line) add('end interface') sargs = ', '.join([a for a in args if a not in extra_args]) -- cgit v1.2.1 From 1ef11c93a52e18ee2c45d4173ec8e685ceb53e9a Mon Sep 17 00:00:00 2001 From: Pearu Peterson Date: Mon, 18 Jan 2021 20:23:18 +0200 Subject: Add test for gh17797. --- numpy/f2py/auxfuncs.py | 5 +++++ numpy/f2py/crackfortran.py | 11 ++++++++--- numpy/f2py/rules.py | 13 ++++++++++--- numpy/f2py/tests/test_callback.py | 24 ++++++++++++++++++++++++ 4 files changed, 47 insertions(+), 6 deletions(-) diff --git a/numpy/f2py/auxfuncs.py b/numpy/f2py/auxfuncs.py index 80b150655..5250fea84 100644 --- a/numpy/f2py/auxfuncs.py +++ b/numpy/f2py/auxfuncs.py @@ -257,6 +257,7 @@ def ismodule(rout): def isfunction(rout): return 'block' in rout and 'function' == rout['block'] + def isfunction_wrap(rout): if isintent_c(rout): return 0 @@ -284,6 +285,10 @@ def hasassumedshape(rout): return False +def requiresf90wrapper(rout): + return ismoduleroutine(rout) or hasassumedshape(rout) + + def isroutine(rout): return isfunction(rout) or issubroutine(rout) diff --git a/numpy/f2py/crackfortran.py b/numpy/f2py/crackfortran.py index d27845796..2aa8dc420 100755 --- a/numpy/f2py/crackfortran.py +++ b/numpy/f2py/crackfortran.py @@ -3113,7 +3113,7 @@ def crack2fortrangen(block, tab='\n', as_interface=False): result = ' result (%s)' % block['result'] if block['result'] not in argsl: argsl.append(block['result']) - body = crack2fortrangen(block['body'], tab + tabchar) + body = crack2fortrangen(block['body'], tab + tabchar, as_interface=as_interface) vars = vars2fortran( block, block['vars'], argsl, tab + tabchar, as_interface=as_interface) mess = '' @@ -3231,8 +3231,13 @@ def vars2fortran(block, vars, args, tab='', as_interface=False): show(vars) outmess('vars2fortran: No definition for argument "%s".\n' % a) continue - if a == block['name'] and not block['block'] == 'function': - continue + if a == block['name']: + if block['block'] == 'function': + if block.get('result'): + # skip declaring function if its result is already declared + continue + else: + continue if 'typespec' not in vars[a]: if 'attrspec' in vars[a] and 'external' in vars[a]['attrspec']: if a in args: diff --git a/numpy/f2py/rules.py b/numpy/f2py/rules.py index 12ed1f1ca..05fba9c4f 100755 --- a/numpy/f2py/rules.py +++ b/numpy/f2py/rules.py @@ -73,7 +73,7 @@ from .auxfuncs import ( issubroutine, issubroutine_wrap, isthreadsafe, isunsigned, isunsigned_char, isunsigned_chararray, isunsigned_long_long, isunsigned_long_longarray, isunsigned_short, isunsigned_shortarray, - l_and, l_not, l_or, outmess, replace, stripcomma, + l_and, l_not, l_or, outmess, replace, stripcomma, requiresf90wrapper ) from . import capi_maps @@ -1184,9 +1184,12 @@ def buildmodule(m, um): nb1['args'] = a nb_list.append(nb1) for nb in nb_list: + # requiresf90wrapper must be called before buildapi as it + # rewrites assumed shape arrays as automatic arrays. + isf90 = requiresf90wrapper(nb) api, wrap = buildapi(nb) if wrap: - if ismoduleroutine(nb) or issubroutine_wrap(nb): + if isf90: funcwrappers2.append(wrap) else: funcwrappers.append(wrap) @@ -1288,7 +1291,11 @@ def buildmodule(m, um): 'C It contains Fortran 77 wrappers to fortran functions.\n') lines = [] for l in ('\n\n'.join(funcwrappers) + '\n').split('\n'): - if l and l[0] == ' ': + i = l.find('!') + if i >= 0 and i < 66: + # don't split comment lines + lines.append(l + '\n') + elif l and l[0] == ' ': while len(l) >= 66: lines.append(l[:66] + '\n &') l = l[66:] diff --git a/numpy/f2py/tests/test_callback.py b/numpy/f2py/tests/test_callback.py index 81650a819..acf8c2392 100644 --- a/numpy/f2py/tests/test_callback.py +++ b/numpy/f2py/tests/test_callback.py @@ -211,3 +211,27 @@ class TestF77CallbackPythonTLS(TestF77Callback): compiler-provided """ options = ["-DF2PY_USE_PYTHON_TLS"] + + +class TestF90Callback(util.F2PyTest): + + suffix = '.f90' + + code = """ +function gh17797(f, y) result(r) + external f + integer(8) :: r, f + integer(8), dimension(:) :: y + r = f(0) + r = r + sum(y) +end function gh17797 + """ + + def test_gh17797(self): + + def incr(x): + return x + 123 + + y = np.array([1, 2, 3], dtype=np.int64) + r = self.module.gh17797(incr, y) + assert r == 123 + 1 + 2 + 3 -- cgit v1.2.1 -- cgit v1.2.1 From 065f50706192d62fc00ff39660ea051539845f12 Mon Sep 17 00:00:00 2001 From: Pearu Peterson Date: Tue, 19 Jan 2021 11:00:28 +0200 Subject: Apply reviewers comments. --- numpy/f2py/crackfortran.py | 10 +++++----- numpy/f2py/tests/test_callback.py | 14 +++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/numpy/f2py/crackfortran.py b/numpy/f2py/crackfortran.py index 2aa8dc420..1149633c0 100755 --- a/numpy/f2py/crackfortran.py +++ b/numpy/f2py/crackfortran.py @@ -3232,11 +3232,11 @@ def vars2fortran(block, vars, args, tab='', as_interface=False): outmess('vars2fortran: No definition for argument "%s".\n' % a) continue if a == block['name']: - if block['block'] == 'function': - if block.get('result'): - # skip declaring function if its result is already declared - continue - else: + if block['block'] != 'function' or block.get('result'): + # 1) skip declaring a variable that name matches with + # subroutine name + # 2) skip declaring function when its type is + # declared via `result` construction continue if 'typespec' not in vars[a]: if 'attrspec' in vars[a] and 'external' in vars[a]['attrspec']: diff --git a/numpy/f2py/tests/test_callback.py b/numpy/f2py/tests/test_callback.py index acf8c2392..6a59b6398 100644 --- a/numpy/f2py/tests/test_callback.py +++ b/numpy/f2py/tests/test_callback.py @@ -218,13 +218,13 @@ class TestF90Callback(util.F2PyTest): suffix = '.f90' code = """ -function gh17797(f, y) result(r) - external f - integer(8) :: r, f - integer(8), dimension(:) :: y - r = f(0) - r = r + sum(y) -end function gh17797 + function gh17797(f, y) result(r) + external f + integer(8) :: r, f + integer(8), dimension(:) :: y + r = f(0) + r = r + sum(y) + end function gh17797 """ def test_gh17797(self): -- cgit v1.2.1 From 5db1d5fb64ff35429205aec4b6927a4b2c6b552b Mon Sep 17 00:00:00 2001 From: Pearu Peterson Date: Tue, 19 Jan 2021 13:16:25 +0200 Subject: Apply reviewer comments. --- numpy/f2py/rules.py | 6 ++---- numpy/f2py/tests/test_callback.py | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/numpy/f2py/rules.py b/numpy/f2py/rules.py index 05fba9c4f..4e1cf0c7d 100755 --- a/numpy/f2py/rules.py +++ b/numpy/f2py/rules.py @@ -1291,8 +1291,7 @@ def buildmodule(m, um): 'C It contains Fortran 77 wrappers to fortran functions.\n') lines = [] for l in ('\n\n'.join(funcwrappers) + '\n').split('\n'): - i = l.find('!') - if i >= 0 and i < 66: + if 0 <= l.find('!') < 66: # don't split comment lines lines.append(l + '\n') elif l and l[0] == ' ': @@ -1317,8 +1316,7 @@ def buildmodule(m, um): '! It contains Fortran 90 wrappers to fortran functions.\n') lines = [] for l in ('\n\n'.join(funcwrappers2) + '\n').split('\n'): - i = l.find('!') - if i >= 0 and i < 72: + if 0 <= l.find('!') < 72: # don't split comment lines lines.append(l + '\n') elif len(l) > 72 and l[0] == ' ': diff --git a/numpy/f2py/tests/test_callback.py b/numpy/f2py/tests/test_callback.py index 6a59b6398..f847dd49f 100644 --- a/numpy/f2py/tests/test_callback.py +++ b/numpy/f2py/tests/test_callback.py @@ -217,7 +217,7 @@ class TestF90Callback(util.F2PyTest): suffix = '.f90' - code = """ + code = textwrap.dedent(""" function gh17797(f, y) result(r) external f integer(8) :: r, f @@ -225,7 +225,7 @@ class TestF90Callback(util.F2PyTest): r = f(0) r = r + sum(y) end function gh17797 - """ + """) def test_gh17797(self): -- cgit v1.2.1 From c4014c7fb4f1753f296bac842098decf061e39bb Mon Sep 17 00:00:00 2001 From: Pearu Peterson Date: Tue, 19 Jan 2021 21:35:29 +0200 Subject: Applied reviewers comments: add ident --- numpy/f2py/tests/test_callback.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/numpy/f2py/tests/test_callback.py b/numpy/f2py/tests/test_callback.py index f847dd49f..37736af21 100644 --- a/numpy/f2py/tests/test_callback.py +++ b/numpy/f2py/tests/test_callback.py @@ -217,15 +217,16 @@ class TestF90Callback(util.F2PyTest): suffix = '.f90' - code = textwrap.dedent(""" - function gh17797(f, y) result(r) - external f - integer(8) :: r, f - integer(8), dimension(:) :: y - r = f(0) - r = r + sum(y) - end function gh17797 - """) + code = textwrap.dedent( + """ + function gh17797(f, y) result(r) + external f + integer(8) :: r, f + integer(8), dimension(:) :: y + r = f(0) + r = r + sum(y) + end function gh17797 + """) def test_gh17797(self): -- cgit v1.2.1