Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

f2py: Exposing parameters from "used" modules

I assume that this question has been addressed somewhere, but I have spent an inordinate amount of time looking around for the answer including digging into the source code a bit. I have tried to put the problem in the first paragraph. The rest shows a basic example of the problem.

I am attempting to compile a module that contains a USE statement pointing to another, more general, module. I would prefer to keep the used module separate so that it can be used in several "packages" as a set of general settings. When I compile the two modules using f2py everything works as advertised from the fortran side, but from the python side USE appears to be ignored. If I allow f2py to generate a signature file, the file contains a USE statement as is appropriate, but if I complete the compilation and import from the resulting library the parameters from the used module are not available in the module that contains the use statement. Below are two modules illustrating the situation:

MODULE test
    INTEGER, PARAMETER :: a = 1
END MODULE test

MODULE test2
    USE test
    INTEGER, PARAMETER :: b = 2
END MODULE test2

In order to show the intermediate step I ran f2py -h test.pyf test.f90 test2.f90. The following signature file is generated; note that the "test2" module contains "use test":

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

python module test ! in
    interface  ! in :test
        module test ! in :test:test.f90
            integer, parameter,optional :: a=1
        end module test
        module test2 ! in :test:test2.f90
            use test
            integer, parameter,optional :: b=2
        end module test2
    end interface
end python module test

! This file was auto-generated with f2py (version:2).
! See http://cens.ioc.ee/projects/f2py2e/

If I now compile with f2py --fcompiler=gfortran -c test.pyf test.f90 test2.f90 I obtain test.so (same as running f2py --fcompiler=gfortran -m test -c test.f90 test2.f90 without creating the signature file first). Importing from this library in python exposes test.test.a and test.test2.b, but does not expose test.test2.a as can be seen here:

In [1]: import test

In [2]: print test.test.a
1

In [3]: print test.test2.b
2

In [4]: print test.test2.a
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
/users/solbrig/svn_checkouts/inversion/satmet/branches/solbrig/rootpath/data/users
/GeoIPS/src/test/<ipython-input-4-bffcf464e408> in <module>() 
----> 1 print test.test2.a

AttributeError: a

Just to illustrate that b is defined properly in test2 from the perspective of fortran, the following code uses test2 and prints both b and b:

SUBROUTINE run_test()
    USE test2
    IMPLICIT NONE
    print *, "a = ", a
    print *, "b = ", b
END SUBROUTINE run_test

After compiling with "f2py -m run_test -c test.f90 test2.f90 run_test.f90" and obtaining run_test.so, run_test can be imported in python and works as expected:

In [1]: import run_test

In [2]: run_test.run_test()
 a =            1
 b =            2

Any help with this issue would be greatly appreciated.

TL;DR : When an F90 module that contains a USE is compiled by f2py it does not expose the parameters that are defined in the "used" module as attributes in Python.

like image 750
Vorticity Avatar asked Jun 17 '13 20:06

Vorticity


1 Answers

I have found a temporary solution to this problem, but it is not optimal. I will continue to work through the f2py source so that I can better understand it and fix the problem within the code itself. Until then, this is my solution which was inspired by chatcannon's comment to the issue I posted to nympy's github.

There are several ways to approach this problem from a temporary standpoint including a couple of ways of modifying the .pyf files. I don't want to have to modify the .pyf files as it becomes very cumbersome as part of a larger package. To avoid this, I added f2py directives to my f90 source.

Taking the example from my original question:

MODULE test
    INTEGER, PARAMETER :: a = 1
END MODULE test

MODULE test2
    USE test
    INTEGER, PARAMETER :: b = 2
END MODULE test2

simply add an f2py directive in test2 to show f2py how to define test2.a:

MODULE test
    INTEGER, PARAMETER :: a = 1
END MODULE test

MODULE test2
    USE test
    !f2py integer, parameter :: a  ! THIS EXPOSES `a` in `test2`
    INTEGER, PARAMETER :: b = 2
END MODULE test2

Importing from the resulting test.so correctly exposes test2.a:

In [1]: import test

In [2]: print test.test.a
1

In [3]: print test.test.b
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
.../test_solution/<ipython-input-3-798b14f59815> in <module>()
----> 1 print test.test.b

AttributeError: b

In [4]: print test.test2.a
1

In [5]: print test.test2.b
2
like image 75
Vorticity Avatar answered Nov 11 '22 06:11

Vorticity