Search code examples
pythonfortranctypes

Why am I getting this error? <class 'TypeError'>: wrong type


I have a Python driver calling a Fortran subroutine. The subroutine has 1 character, then 3 integers. Before I added the character variable at the start and didn't have the argtypes call, it ran fine. But adding the character (and its length) plus the artgtypes call at the start gives a TypeError:

import ctypes as ct
lib = ct.CDLL('FTN_lib.dll')
fs = getattr(lib,'PY_OBJFUN_MOD_mp_GETSIZE')
fs.restype = None
fs.argtypes = [ct.c_char_p,ct.c_int,ct.c_int,ct.c_int,ct.c_int]
x = b'x ' + sys.argv[1].encode('UTF-8') + b' debug=900'
n = ct.c_int(0)
nl = ct.c_int(0)
nnl = ct.c_int(0)
fs(x, len(x), ct.byref(n), ct.byref(nl), ct.byref(nnl))
fs(x, len(x), ct.byref(n), ct.byref(nl), ct.byref(nnl))

ctypes.ArgumentError: argument 3: <class 'TypeError'>: wrong type

It seems the addition of fs.argtypes is causing the problem. The test code didn't have it, and it worked fine. Adding fs.argtypes causes the test code to fail too. Hence there is some problem using ct.c_int construct which is used as ct_byref in the call.

The Fortran code header is:

  subroutine getsize(file,n,nl,nnl)
    implicit none
    character(*), intent(in ) :: file
    integer     , intent(out) :: n   
    integer     , intent(out) :: nl  
    integer     , intent(out) :: nnl 

Solution

  • Fortran passes the integers by reference instead of by value. argtypes for the integer parameters should be ct.POINTER(ct.c_int).

    Note: A comment on another answer indicates the string size should be int32 on 32-bit systems and int64 on64-bit. I’d use c_size_t. It also says string lengths are added to the end of the parameter list and not interleaved. I don’t have Fortran to test.

    Try:

    fs.argtypes = ct.c_char_p, ct.POINTER(ct.c_int), ct.POINTER(ct.c_int), ct.POINTER(ct.c_int), ct.c_size_t
    x = b'x ' + sys.argv[1].encode('UTF-8') + b' debug=900'
    n = ct.c_int(0)
    nl = ct.c_int(0)
    nnl = ct.c_int(0)
    fs(x, ct.byref(n), ct.byref(nl), ct.byref(nnl), len(x))