question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

BUG: f2py generated signature file and automatic arrays

See original GitHub issue

Describe the issue:

Let’s consider the following subroutine in a test.f90 file that declares an automatic array from two variables(*):

subroutine test (nx, ny, arr)

  implicit none

  integer, intent(in) :: nx
  integer, intent(in) :: ny
  integer, dimension(nx*ny) :: arr

return
end subroutine test

It used to work with numpy 1.22.0 or earlier, despite the Warning: cross-dependence between variables "ny" and "nx" and the weird shape checks as shown in the generated test.pyf signature file below:

!    -*- f90 -*-
! Note: the context of this file is case sensitive.

python module test ! in 
    interface  ! in :test
        subroutine test(nx,ny,arr) ! in :test:src/test.f90
            integer, optional,intent(in),check(shape(arr, 0) == nx * ny),depend(ny,arr) :: nx=shape(arr, 0) / nx
            integer, optional,intent(in),check(shape(arr, 0) == nx * ny),depend(nx,arr) :: ny=shape(arr, 0) / nx
            integer dimension(nx * ny) :: arr
        end subroutine test
    end interface 
end python module test

! This file was auto-generated with f2py (version:1.22.0).
! See:
! https://web.archive.org/web/20140822061353/http://cens.ioc.ee/projects/f2py2e

However, with numpy 1.22.1 or later, it generates a test.pyf with “swapped” nx / ny:

!    -*- f90 -*-
! Note: the context of this file is case sensitive.

python module test ! in 
    interface  ! in :test
        subroutine test(nx,ny,arr) ! in :test:src/test.f90
            integer, optional,intent(in),check(shape(arr, 0) == nx * ny),depend(ny,arr) :: nx=shape(arr, 0) / ny
            integer, optional,intent(in),check(shape(arr, 0) == nx * ny),depend(arr,nx) :: ny=shape(arr, 0) / nx
            integer dimension(nx * ny) :: arr
        end subroutine test
    end interface 
end python module test

! This file was auto-generated with f2py (version:1.22.1).
! See:
! https://web.archive.org/web/20140822061353/http://cens.ioc.ee/projects/f2py2e

Which causes the following recursion error when trying to generate the Python extension from the signature file:

Reading fortran codes...
        Reading file 'test.pyf' (format:free)
Post-processing...
        Block: test
                        Block: test
Traceback (most recent call last):
  File "/Users/me/env/bin/f2py", line 8, in <module>
    sys.exit(main())
  File "/Users/me/env/lib/python3.9/site-packages/numpy/f2py/f2py2e.py", line 693, in main
    run_main(sys.argv[1:])
  File "/Users/me/env/lib/python3.9/site-packages/numpy/f2py/f2py2e.py", line 430, in run_main
    postlist = callcrackfortran(files, options)
  File "/Users/me/env/lib/python3.9/site-packages/numpy/f2py/f2py2e.py", line 333, in callcrackfortran
    postlist = crackfortran.crackfortran(files)
  File "/Users/me/env/lib/python3.9/site-packages/numpy/f2py/crackfortran.py", line 3209, in crackfortran
    postlist = postcrack(grouplist[0])
  File "/Users/me/env/lib/python3.9/site-packages/numpy/f2py/crackfortran.py", line 1926, in postcrack
    g = postcrack(g, tab=tab + '\t')
  File "/Users/me/env/lib/python3.9/site-packages/numpy/f2py/crackfortran.py", line 1945, in postcrack
    block['body'] = analyzebody(block, args, tab=tab)
  File "/Users/me/env/lib/python3.9/site-packages/numpy/f2py/crackfortran.py", line 2107, in analyzebody
    b = postcrack(b, as_, tab=tab + '\t')
  File "/Users/me/env/lib/python3.9/site-packages/numpy/f2py/crackfortran.py", line 1945, in postcrack
    block['body'] = analyzebody(block, args, tab=tab)
  File "/Users/me/env/lib/python3.9/site-packages/numpy/f2py/crackfortran.py", line 2107, in analyzebody
    b = postcrack(b, as_, tab=tab + '\t')
  File "/Users/me/env/lib/python3.9/site-packages/numpy/f2py/crackfortran.py", line 1941, in postcrack
    block['vars'] = analyzevars(block)
  File "/Users/me/env/lib/python3.9/site-packages/numpy/f2py/crackfortran.py", line 2458, in analyzevars
    params = get_parameters(vars, get_useparameters(block))
  File "/Users/me/env/lib/python3.9/site-packages/numpy/f2py/crackfortran.py", line 2329, in get_parameters
    for n in get_sorted_names(vars):
  File "/Users/me/env/lib/python3.9/site-packages/numpy/f2py/crackfortran.py", line 2257, in get_sorted_names
    depend_dict = _calc_depend_dict(vars)
  File "/Users/me/env/lib/python3.9/site-packages/numpy/f2py/crackfortran.py", line 2250, in _calc_depend_dict
    _get_depend_dict(n, vars, depend_dict)
  File "/Users/me/env/lib/python3.9/site-packages/numpy/f2py/crackfortran.py", line 2236, in _get_depend_dict
    or _get_depend_dict(word, vars, deps):
  File "/Users/me/env/lib/python3.9/site-packages/numpy/f2py/crackfortran.py", line 2236, in _get_depend_dict
    or _get_depend_dict(word, vars, deps):
  File "/Users/me/env/lib/python3.9/site-packages/numpy/f2py/crackfortran.py", line 2236, in _get_depend_dict
    or _get_depend_dict(word, vars, deps):
  [Previous line repeated 979 more times]
  File "/Users/me/env/lib/python3.9/site-packages/numpy/f2py/crackfortran.py", line 2228, in _get_depend_dict
    if '=' in vars[name] and not isstring(vars[name]):
  File "/Users/me/env/lib/python3.9/site-packages/numpy/f2py/auxfuncs.py", line 77, in isstring
    return _isstring(var) and not isarray(var)
  File "/Users/me/env/lib/python3.9/site-packages/numpy/f2py/auxfuncs.py", line 72, in _isstring
    return 'typespec' in var and var['typespec'] == 'character' and \
RecursionError: maximum recursion depth exceeded in comparison

The difference between the two generated signature files seems to be a result of #20721.

(*) Do you think the issue here could be considered as a regression? Or is the example here wrong and we should not declare dimensions of automatic arrays from two or more variables? Not sure about this as I’m not a Fortran expert and haven’t found much info about this practice, although I’d be surprised that compilers let us do it if it wasn’t valid.

Reproduce the code example:

# see f90 / pyf source above

Error message:

No response

NumPy/Python version information:

Numpy 1.22.0 / 1.22.1 Python 3.9

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:7 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
benbovycommented, Jun 30, 2022

👍 Great thanks!

0reactions
charriscommented, Jul 1, 2022

Here is a list of the 21 changed files:

	modified:   numpy/f2py/auxfuncs.py
	modified:   numpy/f2py/capi_maps.py
	modified:   numpy/f2py/cb_rules.py
	modified:   numpy/f2py/cfuncs.py
	modified:   numpy/f2py/common_rules.py
	modified:   numpy/f2py/crackfortran.py
	modified:   numpy/f2py/f90mod_rules.py
	modified:   numpy/f2py/func2subr.py
	modified:   numpy/f2py/rules.py
	modified:   numpy/f2py/src/fortranobject.c
	modified:   numpy/f2py/src/fortranobject.h
	modified:   numpy/f2py/tests/src/array_from_pyobj/wrapmodule.c
	new file:   numpy/f2py/tests/src/crackfortran/pubprivmod.f90
	modified:   numpy/f2py/tests/test_array_from_pyobj.py
	modified:   numpy/f2py/tests/test_callback.py
	new file:   numpy/f2py/tests/test_character.py
	modified:   numpy/f2py/tests/test_crackfortran.py
	new file:   numpy/f2py/tests/test_docs.py
	modified:   numpy/f2py/tests/test_f2py2e.py
	modified:   numpy/f2py/tests/test_return_character.py
	modified:   numpy/f2py/tests/util.py
Read more comments on GitHub >

github_iconTop Results From Across the Web

BUG: F2py creates bad wrapper functions when fortran code ...
This file is autogenerated with f2py (version:1.21.2) ! It contains Fortran 90 wrappers to fortran functions. subroutine f2pywrapexample ...
Read more >
f2py error with allocatable arrays - python - Stack Overflow
The first is to use module level allocatable arrays (described in the ... You need to create a signature file with the command...
Read more >
Three ways to wrap - getting started — NumPy v1.9 Manual
In the case of Fortran routines, F2PY can create initial signature file by scanning Fortran source codes and catching all relevant information needed...
Read more >
F2Py with allocatable and assumed shape arrays
Once you have a C signature, just call it from Python in any way you like, ... py main.py This module 'pymod' is...
Read more >
Signature file - NumPy 中文
When scanning Fortran codes and writing a signature file, F2PY lowers all cases automatically except in multiline blocks or when --no-lower ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found