8

I am creating a Python module in Fortran using f2py. I would like produce an error (including error message) in the Python program if an error is encountered in the Fortran module. Consider the following example:

Fortran code (test.f):

subroutine foo(a,m)

  integer :: m,i
  integer, dimension(m) :: a
  !f2py intent(in) :: m
  !f2py intent(in,out) :: a
  !f2py intent(hide), depend(a) :: m=shape(a)

  do i = 1,m
    if ( a(i) .eq. 0 ) then
      print*, 'ERROR HERE..?'
    end if 
    a(i) = a(i)+1
  end do

end subroutine

This very simple program adds 1 to each element of a. But should produce an error if a(i) equal to zero. The accompanying Python code:

import test

print test.foo(np.array([1,2],dtype='uint32'))
print test.foo(np.array([0,2],dtype='uint32'))

The output is now:

[2 3]
ERROR HERE..?
[1 3]

But I want the Python program to hold on the error. Please help.

Answer

The stop command in Fortran does exactly this. Consider the updated Fortran code:

subroutine foo(a,m)

  integer :: m,i
  integer, dimension(m) :: a
  !f2py intent(in) :: m
  !f2py intent(in,out) :: a
  !f2py intent(hide), depend(a) :: m=shape(a)

  do i = 1,m
    if ( a(i) .eq. 0 ) then
      print*, 'Error from Fortran'
      stop
    end if 
    a(i) = a(i)+1
  end do

end subroutine

The output is now:

[2 3]
Error from Fortran

I.e. the Python code does not continue after the error.

Tom de Geus
  • 5,625
  • 2
  • 33
  • 77
  • 1
    Are you trying to raise a Python exception from a Fortran module? – user2357112 Aug 02 '13 at 15:47
  • 1
    Yes this is exactly what I'm trying to do – Tom de Geus Aug 02 '13 at 16:00
  • 3
    One way would be to retutn an error code from Fortran, check it in python side, and raise an exception if error occured. – ev-br Aug 02 '13 at 16:31
  • I agree. This is what I considered. But I think this is not the most elegant solution. Also I guess it is possible, since other Python modules can produce these errors. – Tom de Geus Aug 03 '13 at 10:25
  • 3
    Fortran has no support for raising exceptions. – Steve Lionel Aug 04 '13 at 00:04
  • As much as I love Fortran, I think that you have to give up a certain sense of elegance using it. Returning an exit code and checking it is probably your most elegant solution, all things considered. – SethMMorton Aug 06 '13 at 22:16
  • Returning an exit code is indeed not too bad. My personal preference is that this reduces the readability of the Python code as it involves an extra `if` statement. I did find some solution (see above) – Tom de Geus Aug 08 '13 at 07:59
  • 1
    This thread on the numpy-dev email list has some solutions for your problem: http://mail.scipy.org/pipermail/numpy-discussion/2009-January/039672.html – Robert T. McGibbon Oct 28 '13 at 07:57

2 Answers2

4

I've suggested to the numpy community to add add an extra f2py "enhancement" (raise_python_exception) which makes it possible to define a string variable in Fortran that if non-empty will cause Python to raise an exception once the function returns.

So in Fortran you would write something like:

subroutine calc_dq(q, temp, dq, error_mesg)
  !f2py raise_python_exception error_mesg

  real, intent(in) :: q, temp
  real, intent(out) :: dq

  character(len=100), intent(out) :: error_mesg

  if (.not. init_called()) then
     error_mesg = "`init` hasn't been called."
  else
     call q_flux_function(q, temp, dq)
  endif
end subroutine calc_dq

And called from Python the content of the error_mesg variable is used as the content of the exception:

In [2]: calc_dq(1.0, 300.)
---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
<ipython-input-8-c0ce0cb9cda1> in <module>()
----> 1 calc_dq(1.0, 300.)

Exception: `init` hasn't been called.

I think this is quite a convenient way of raising exceptions from Fortran as it allows the exception message to be easily defined. I have put my suggestion on github.

leifdenby
  • 1,428
  • 1
  • 13
  • 10
1

f2py does provide some statements that can be used to raise exceptions. See details here.

In particular, look at callstatement which describes how to add f2py_success = 0 which will trigger an exception.

I'm not sure this will help you with debugging the internals of the fortran library, but at least it is a start.

Mike T
  • 41,085
  • 18
  • 152
  • 203
IanSR
  • 9,898
  • 4
  • 14
  • 15
  • Link nowadays: https://numpy.org/doc/stable/f2py/signature-file.html#statements and link recovered from Wayback Machine: https://web.archive.org/web/20140625200426/http://cens.ioc.ee/projects/f2py2e/usersguide/#statements – David Jun 03 '21 at 17:40