Skip to content

Issue with f2py in Numpy 1.13 when character arrays appear in a callback function #10027

Closed

Description

@swryan

There is an issue with f2py in Numpy 1.13 when character arrays appear in a callback function. The following example works with Numpy 1.12 but not in 1.13:

#! /usr/bin/env python

from __future__ import print_function
import numpy
from subprocess import call

#
# build extension from FORTRAN source
#
source = """
       subroutine func_with_callback(callBack, cu, lencu)

       implicit none

       integer :: lencu
       character*8 cu(lencu)
       external callBack

       print *,'Lencu:', lencu

       print *,'Calling callback...'
       call callBack(cu, lencu)
       print *,'Back in fortran...'

       end subroutine func_with_callback
"""

with open("callback.f", "w") as src_file:
    src_file.write(source)

rc = call("f2py callback.f -m callback -h callback.pyf".split())
if rc: quit()

rc = call("f2py -c callback.pyf callback.f".split())
if rc: quit()


#
# define callback function
#
def callBack(cu, lencu):
    print ('In callback:', cu)

#
# call library function with callback
#
from callback import func_with_callback
print(func_with_callback.__doc__)

print("\nNumpy Version:", numpy.__version__, "\n")

cu = numpy.zeros((1, 8), 'c')

func_with_callback(callBack, cu)

================

Numpy Version: 1.12.1

Lencu: 1
Calling callback...
In callback: [['' '' '' '' '' '' '' '']]
Back in fortran...

================

Numpy Version: 1.13.3

Lencu: 1
Calling callback...
Call-back cb_callback_in_func_with_callback__user__routines failed.
Traceback (most recent call last):
File "test_callback.py", line 57, in
func_with_callback(callBack, cu)
ValueError: data type must provide an itemsize

Activity

  1. charris commented on Nov 15, 2017

    @charris
    Member

    The problem came in with a618b4e, #8948.

  2. added this to the milestone on Nov 15, 2017
  3. charris commented on Nov 15, 2017

    @charris
    Member

    The proximate cause is this code in the generated source:

      if (cb_callBack_in_func_with_callback__user__routines_nofargs>capi_i) {
        PyArrayObject *tmp_arr = (PyArrayObject *)PyArray_New(&PyArray_Type,2,cu_Dims,NPY_STRING,NULL,(char*)cu,0,NPY_ARRAY_CARRAY,NULL); /*XXX: Hmm, what will destroy this array??? */
    
  4. added 3 commits that reference this issue on Nov 18, 2017
    9a36ead
    8825fac
  5. aelanman commented on Dec 8, 2021

    @aelanman

    I've recently come across this issue while using f2py in numpy 1.20.3. As a minimum working example, I have the following simple fortran module which declares two allocatable arrays (charge is real type and names is character). The subroutine "main" will allocate them:

    ! -*- f90 -*-
    
          module inputs
          implicit none
                  real*8, dimension(:,:), target, allocatable :: charge
                  integer is_alloc
                  character(len=10), allocatable, dimension(:) :: names
          end module inputs
    
          subroutine main(N)
          use inputs
          implicit none
    
          integer ii, jj, N
          
          IF (allocated(charge)) THEN
             deallocate(charge)
          end if
          allocate(charge(N, N))
          allocate(character(len=10) :: names(N)) !, source="TEST")
    
          END subroutine
    

    I can build this by running python setup.py build_ext --inplace with the following setup.py file (having put the above code in test.f90):

    from numpy.distutils.core import Extension
    from numpy.distutils.core import setup
    from numpy.distutils.misc_util import Configuration
    
    
    F90_COMBINED = "test.f90"
    
    calc_ext = Extension(
        name="alloc",
        sources=[F90_COMBINED],
        include_dirs=['.'],
        libraries=['gsl', 'gslcblas'],
        extra_f90_compile_args=['-Wargument-mismatch'],
    )
    
    def configuration(parent_package='', top_path=None):
    
        config = Configuration('', parent_package, top_path,
                               ext_modules=[calc_ext])
        return config
    
    if __name__ == "__main__":
        setup(configuration=configuration)
    

    This builds a module called alloc. Here's a screencap of what happens if I try to access each allocated array.
    image

    Any suggestions would be greatly appreciated!

  6. HaoZeke commented on Jun 5, 2022

    @HaoZeke
    Member

    Note that the original issue of callbacks and character arrays is fixed by #19388. The issue raised for allocations is still relevant and tracked separately.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions