Tom de Geus
Tom de Geus

Reputation: 5965

Stop python code in (Fortran) module error using f2py?

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.

Upvotes: 7

Views: 1455

Answers (2)

IanSR
IanSR

Reputation: 10556

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.

Upvotes: 1

leifdenby
leifdenby

Reputation: 1468

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.

Upvotes: 4

Related Questions