diff --git a/doc/source/f2py/code/add-edited.pyf b/doc/source/f2py/code/add-edited.pyf new file mode 100644 index 000000000000..a1c375996940 --- /dev/null +++ b/doc/source/f2py/code/add-edited.pyf @@ -0,0 +1,6 @@ + subroutine zadd(a,b,c,n) ! in :add:add.f + double complex dimension(n) :: a + double complex dimension(n) :: b + double complex intent(out),dimension(n) :: c + integer intent(hide),depend(a) :: n=len(a) + end subroutine zadd \ No newline at end of file diff --git a/doc/source/f2py/code/add-improved.f b/doc/source/f2py/code/add-improved.f new file mode 100644 index 000000000000..f12b6560b6fc --- /dev/null +++ b/doc/source/f2py/code/add-improved.f @@ -0,0 +1,16 @@ + C + SUBROUTINE ZADD(A,B,C,N) + C + CF2PY INTENT(OUT) :: C + CF2PY INTENT(HIDE) :: N + CF2PY DOUBLE COMPLEX :: A(N) + CF2PY DOUBLE COMPLEX :: B(N) + CF2PY DOUBLE COMPLEX :: C(N) + DOUBLE COMPLEX A(*) + DOUBLE COMPLEX B(*) + DOUBLE COMPLEX C(*) + INTEGER N + DO 20 J = 1, N + C(J) = A(J) + B(J) + 20 CONTINUE + END \ No newline at end of file diff --git a/doc/source/f2py/code/add.f b/doc/source/f2py/code/add.f new file mode 100644 index 000000000000..c3002fd25c37 --- /dev/null +++ b/doc/source/f2py/code/add.f @@ -0,0 +1,11 @@ + C + SUBROUTINE ZADD(A,B,C,N) + C + DOUBLE COMPLEX A(*) + DOUBLE COMPLEX B(*) + DOUBLE COMPLEX C(*) + INTEGER N + DO 20 J = 1, N + C(J) = A(J)+B(J) + 20 CONTINUE + END diff --git a/doc/source/f2py/code/add.pyf b/doc/source/f2py/code/add.pyf new file mode 100644 index 000000000000..6a2a8533d4e3 --- /dev/null +++ b/doc/source/f2py/code/add.pyf @@ -0,0 +1,6 @@ + subroutine zadd(a,b,c,n) ! in :add:add.f + double complex dimension(*) :: a + double complex dimension(*) :: b + double complex dimension(*) :: c + integer :: n + end subroutine zadd \ No newline at end of file diff --git a/doc/source/f2py/code/filter.f b/doc/source/f2py/code/filter.f new file mode 100644 index 000000000000..a23e2d9b1d7a --- /dev/null +++ b/doc/source/f2py/code/filter.f @@ -0,0 +1,19 @@ +C + SUBROUTINE DFILTER2D(A,B,M,N) +C + DOUBLE PRECISION A(M,N) + DOUBLE PRECISION B(M,N) + INTEGER N, M +CF2PY INTENT(OUT) :: B +CF2PY INTENT(HIDE) :: N +CF2PY INTENT(HIDE) :: M + DO 20 I = 2,M-1 + DO 40 J = 2,N-1 + B(I,J) = A(I,J) + + $ (A(I-1,J)+A(I+1,J) + + $ A(I,J-1)+A(I,J+1) )*0.5D0 + + $ (A(I-1,J-1) + A(I-1,J+1) + + $ A(I+1,J-1) + A(I+1,J+1))*0.25D0 + 40 CONTINUE + 20 CONTINUE + END diff --git a/doc/source/f2py/code/myroutine-edited.pyf b/doc/source/f2py/code/myroutine-edited.pyf new file mode 100644 index 000000000000..c1af805c2311 --- /dev/null +++ b/doc/source/f2py/code/myroutine-edited.pyf @@ -0,0 +1,17 @@ + ! -*- f90 -*- + ! Note: the context of this file is case sensitive. + + python module myroutine ! in + interface ! in :myroutine + subroutine s(n,m,c,x) ! in :myroutine:myroutine.f90 + integer intent(in) :: n + integer intent(in) :: m + real*8 dimension(:),intent(in) :: c + real*8 dimension(n,m),intent(out) :: x + end subroutine s + end interface + end python module myroutine + + ! This file was auto-generated with f2py (version:1.23.0.dev0+120.g4da01f42d). + ! See: + ! https://web.archive.org/web/20140822061353/http://cens.ioc.ee/projects/f2py2e \ No newline at end of file diff --git a/doc/source/f2py/code/myroutine.f90 b/doc/source/f2py/code/myroutine.f90 new file mode 100644 index 000000000000..592796a6a380 --- /dev/null +++ b/doc/source/f2py/code/myroutine.f90 @@ -0,0 +1,10 @@ +subroutine s(n, m, c, x) + implicit none + integer, intent(in) :: n, m + real(kind=8), intent(out), dimension(n,m) :: x + real(kind=8), intent(in) :: c(:) + + x = 0.0d0 + x(1, 1) = c(1) + +end subroutine s \ No newline at end of file diff --git a/doc/source/f2py/code/myroutine.pyf b/doc/source/f2py/code/myroutine.pyf new file mode 100644 index 000000000000..0576fb888a51 --- /dev/null +++ b/doc/source/f2py/code/myroutine.pyf @@ -0,0 +1,17 @@ +! -*- f90 -*- + ! Note: the context of this file is case sensitive. + + python module myroutine ! in + interface ! in :myroutine + subroutine s(n,m,c,x) ! in :myroutine:myroutine.f90 + integer intent(in) :: n + integer intent(in) :: m + real*8 dimension(:),intent(in) :: c + real*8 dimension(n,m),intent(out),depend(m,n) :: x + end subroutine s + end interface + end python module myroutine + + ! This file was auto-generated with f2py (version:1.23.0.dev0+120.g4da01f42d). + ! See: + ! https://web.archive.org/web/20140822061353/http://cens.ioc.ee/projects/f2py2e \ No newline at end of file diff --git a/doc/source/f2py/f2py-examples.rst b/doc/source/f2py/f2py-examples.rst index bae0a14480f9..471b0ec597cc 100644 --- a/doc/source/f2py/f2py-examples.rst +++ b/doc/source/f2py/f2py-examples.rst @@ -14,26 +14,15 @@ Creating source for a basic extension module Consider the following subroutine, contained in a file named :file:`add.f` -.. code-block:: fortran - - C - SUBROUTINE ZADD(A,B,C,N) - C - DOUBLE COMPLEX A(*) - DOUBLE COMPLEX B(*) - DOUBLE COMPLEX C(*) - INTEGER N - DO 20 J = 1, N - C(J) = A(J)+B(J) - 20 CONTINUE - END +.. literalinclude:: ./code/add.f + :language: fortran This routine simply adds the elements in two contiguous arrays and places the result in a third. The memory for all three arrays must be provided by the calling routine. A very basic interface to this routine can be automatically generated by f2py:: - f2py -m add add.f + python -m numpy.f2py -m add add.f This command will produce an extension module named :file:`addmodule.c` in the current directory. This extension module can now be compiled and used from @@ -42,18 +31,21 @@ Python just like any other extension module. Creating a compiled extension module ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. note:: + + This usage depends heavily on ``numpy.distutils``, see :ref:`f2py-bldsys` + for more details. + You can also get f2py to both compile :file:`add.f` along with the produced extension module leaving only a shared-library extension file that can be imported from Python:: - f2py -c -m add add.f + python -m numpy.f2py -c -m add add.f -This command leaves a file named add.{ext} in the current directory -(where {ext} is the appropriate extension for a Python extension -module on your platform --- so, pyd, *etc.* ). This module may then be -imported from Python. It will contain a method for each subroutine in -add (zadd, cadd, dadd, sadd). The docstring of each method contains -information about how the module method may be called: +This command produces a Python extension module compatible with your platform. +This module may then be imported from Python. It will contain a method for each +subroutine in ``add``. The docstring of each method contains information about +how the module method may be called: .. code-block:: python @@ -73,55 +65,43 @@ information about how the module method may be called: Improving the basic interface ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The default interface is a very literal translation of the Fortran -code into Python. The Fortran array arguments must now be NumPy arrays -and the integer argument should be an integer. The interface will -attempt to convert all arguments to their required types (and shapes) -and issue an error if unsuccessful. However, because it knows nothing -about the semantics of the arguments (such that C is an output and n -should really match the array sizes), it is possible to abuse this -function in ways that can cause Python to crash. For example: +The default interface is a very literal translation of the Fortran code into +Python. The Fortran array arguments are converted to NumPy arrays and the +integer argument should be mapped to a ``C`` integer. The interface will attempt +to convert all arguments to their required types (and shapes) and issue an error +if unsuccessful. However, because ``f2py`` knows nothing about the semantics of +the arguments (such that ``C`` is an output and ``n`` should really match the +array sizes), it is possible to abuse this function in ways that can cause +Python to crash. For example: .. code-block:: python >>> add.zadd([1, 2, 3], [1, 2], [3, 4], 1000) -will cause a program crash on most systems. Under the covers, the -lists are being converted to proper arrays but then the underlying add -loop is told to cycle way beyond the borders of the allocated memory. - -In order to improve the interface, directives should be provided. This -is accomplished by constructing an interface definition file. It is -usually best to start from the interface file that f2py can produce -(where it gets its default behavior from). To get f2py to generate the -interface file use the -h option:: +will cause a program crash on most systems. Under the hood, the lists are being +converted to arrays but then the underlying ``add`` function is told to cycle +way beyond the borders of the allocated memory. - f2py -h add.pyf -m add add.f +In order to improve the interface, ``f2py`` supports directives. This is +accomplished by constructing a signature file. It is usually best to start from +the interfaces that ``f2py`` produces in that file, which correspond to the +default behavior. To get ``f2py`` to generate the interface file use the ``-h`` +option:: -This command leaves the file add.pyf in the current directory. The -section of this file corresponding to zadd is: + python -m numpy.f2py -h add.pyf -m add add.f -.. code-block:: fortran +This command creates the ``add.pyf`` file in the current directory. The section +of this file corresponding to ``zadd`` is: - subroutine zadd(a,b,c,n) ! in :add:add.f - double complex dimension(*) :: a - double complex dimension(*) :: b - double complex dimension(*) :: c - integer :: n - end subroutine zadd +.. literalinclude:: ./code/add.pyf + :language: fortran -By placing intent directives and checking code, the interface can be -cleaned up quite a bit until the Python module method is both easier -to use and more robust. +By placing intent directives and checking code, the interface can be cleaned up +quite a bit so the Python module method is both easier to use and more robust to +malformed inputs. -.. code-block:: fortran - - subroutine zadd(a,b,c,n) ! in :add:add.f - double complex dimension(n) :: a - double complex dimension(n) :: b - double complex intent(out),dimension(n) :: c - integer intent(hide),depend(a) :: n=len(a) - end subroutine zadd +.. literalinclude:: ./code/add-edited.pyf + :language: fortran The intent directive, intent(out) is used to tell f2py that ``c`` is an output variable and should be created by the interface before being @@ -135,9 +115,9 @@ created). After modifying ``add.pyf``, the new Python module file can be generated by compiling both ``add.f`` and ``add.pyf``:: - f2py -c add.pyf add.f + python -m numpy.f2py -c add.pyf add.f -The new interface has docstring: +The new interface's docstring is: .. code-block:: python @@ -168,32 +148,23 @@ Notice the automatic conversion to the correct format that occurred. Inserting directives in Fortran source ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The nice interface can also be generated automatically by placing the -variable directives as special comments in the original Fortran code. +The robust interface of the previous section can also be generated automatically +by placing the variable directives as special comments in the original Fortran +code. + +.. note:: + + For projects where the Fortran code is being actively developed, this may be + preferred. + Thus, if the source code is modified to contain: -.. code-block:: fortran - - C - SUBROUTINE ZADD(A,B,C,N) - C - CF2PY INTENT(OUT) :: C - CF2PY INTENT(HIDE) :: N - CF2PY DOUBLE COMPLEX :: A(N) - CF2PY DOUBLE COMPLEX :: B(N) - CF2PY DOUBLE COMPLEX :: C(N) - DOUBLE COMPLEX A(*) - DOUBLE COMPLEX B(*) - DOUBLE COMPLEX C(*) - INTEGER N - DO 20 J = 1, N - C(J) = A(J) + B(J) - 20 CONTINUE - END +.. literalinclude:: ./code/add-improved.f + :language: fortran Then, one can compile the extension module using:: - f2py -c -m add add.f + python -m numpy.f2py -c -m add add.f The resulting signature for the function add.zadd is exactly the same one that was created previously. If the original source code had @@ -211,54 +182,28 @@ precision floating-point numbers using a fixed averaging filter. The advantage of using Fortran to index into multi-dimensional arrays should be clear from this example. -.. code-block:: - - SUBROUTINE DFILTER2D(A,B,M,N) - C - DOUBLE PRECISION A(M,N) - DOUBLE PRECISION B(M,N) - INTEGER N, M - CF2PY INTENT(OUT) :: B - CF2PY INTENT(HIDE) :: N - CF2PY INTENT(HIDE) :: M - DO 20 I = 2,M-1 - DO 40 J=2,N-1 - B(I,J) = A(I,J) + - $ (A(I-1,J)+A(I+1,J) + - $ A(I,J-1)+A(I,J+1) )*0.5D0 + - $ (A(I-1,J-1) + A(I-1,J+1) + - $ A(I+1,J-1) + A(I+1,J+1))*0.25D0 - 40 CONTINUE - 20 CONTINUE - END +.. literalinclude:: ./code/filter.f + :language: fortran This code can be compiled and linked into an extension module named filter using:: - f2py -c -m filter filter.f + python -m numpy.f2py -c -m filter filter.f This will produce an extension module in the current directory with a method -named dfilter2d that returns a filtered version of the input. +named ``dfilter2d`` that returns a filtered version of the input. ``depends`` keyword example --------------------------- -Consider the following code, saved in the file ``myroutine.f90``:: - - subroutine s(n, m, c, x) - implicit none - integer, intent(in) :: n, m - real*8, intent(out), dimension(n,m) :: x - real*8, intent(in) :: c(:) - - x = 0.0d0 - x(1, 1) = c(1) +Consider the following code, saved in the file ``myroutine.f90``: - end subroutine s +.. literalinclude:: ./code/myroutine.f90 + :language: fortran -Wrapping this with ``f2py -c myroutine.f90 -m myroutine``, we can do the -following in Python:: +Wrapping this with ``python -m numpy.f2py -c myroutine.f90 -m myroutine``, we +can do the following in Python:: >>> import numpy as np >>> import myroutine @@ -268,58 +213,22 @@ following in Python:: [0., 0., 0.]]) Now, instead of generating the extension module directly, we will create a -signature file for this subroutine first. This may be a common pattern in +signature file for this subroutine first. This is a common pattern for multi-step extension module generation. In this case, after running -.. code-block:: - - f2py myroutine.f90 -h myroutine.pyf - -the following signature file is generated:: - - ! -*- f90 -*- - ! Note: the context of this file is case sensitive. - - python module myroutine ! in - interface ! in :myroutine - subroutine s(n,m,c,x) ! in :myroutine:myroutine.f90 - integer intent(in) :: n - integer intent(in) :: m - real*8 dimension(:),intent(in) :: c - real*8 dimension(n,m),intent(out),depend(m,n) :: x - end subroutine s - end interface - end python module myroutine - - ! This file was auto-generated with f2py (version:1.23.0.dev0+120.g4da01f42d). - ! See: - ! https://web.archive.org/web/20140822061353/http://cens.ioc.ee/projects/f2py2e - - -Now, if we run ``f2py -c myroutine.pyf myroutine.f90`` we see an error; note -that the signature file included a ``depend(m,n)`` statement for x which is not -necessary. Indeed, editing the file above to read - -.. code-block:: + python -m numpy.f2py myroutine.f90 -h myroutine.pyf - ! -*- f90 -*- - ! Note: the context of this file is case sensitive. +the following signature file is generated: - python module myroutine ! in - interface ! in :myroutine - subroutine s(n,m,c,x) ! in :myroutine:myroutine.f90 - integer intent(in) :: n - integer intent(in) :: m - real*8 dimension(:),intent(in) :: c - real*8 dimension(n,m),intent(out) :: x - end subroutine s - end interface - end python module myroutine +.. literalinclude:: ./code/myroutine.pyf + :language: fortran - ! This file was auto-generated with f2py (version:1.23.0.dev0+120.g4da01f42d). - ! See: - ! https://web.archive.org/web/20140822061353/http://cens.ioc.ee/projects/f2py2e +Now, if we run ``python -m numpy.f2py -c myroutine.pyf myroutine.f90`` we see an +error; note that the signature file included a ``depend(m,n)`` statement for +``x`` which is not necessary. Indeed, editing the file above to read +.. literalinclude:: ./code/myroutine-edited.pyf + :language: fortran and running ``f2py -c myroutine.pyf myroutine.f90`` yields correct results. diff --git a/doc/source/f2py/f2py.getting-started.rst b/doc/source/f2py/f2py.getting-started.rst index 9c9d16dab0b7..da88b46f550d 100644 --- a/doc/source/f2py/f2py.getting-started.rst +++ b/doc/source/f2py/f2py.getting-started.rst @@ -14,7 +14,7 @@ following steps: needed to create wrapper functions. * Optionally, F2PY-created signature files can be edited to optimize wrapper - functions, to make them "smarter" and more "Pythonic". + functions, which can make them "smarter" and more "Pythonic". * F2PY reads a signature file and writes a Python C/API module containing Fortran/C/Python bindings. @@ -64,6 +64,12 @@ or, alternatively, if the ``f2py`` command-line tool is available, f2py -c fib1.f -m fib1 +.. note:: + + Because the ``f2py`` command might not be available in all system, notably on + Windows, we will use the ``python -m numpy.f2py`` command throughout this + guide. + This command compiles and wraps ``fib1.f`` (``-c``) to create the extension module ``fib1.so`` (``-m``) in the current directory. A list of command line options can be seen by executing ``python -m numpy.f2py``. Now, in Python the diff --git a/doc/source/f2py/signature-file.rst b/doc/source/f2py/signature-file.rst index e0c886c133fc..697b259cd6f0 100644 --- a/doc/source/f2py/signature-file.rst +++ b/doc/source/f2py/signature-file.rst @@ -16,6 +16,13 @@ constructs that are irrelevant for creating the interface. However, this also means that syntax errors are not caught by F2PY and will only be caught when the library is built. +.. note:: + + Currently, F2PY may fail with valid Fortran constructs, such as intrinsic + modules. If this happens, you can check the + :ref:`NumPy GitHub issue tracker ` for + possible workarounds or work-in-progress ideas. + In general, the contents of the signature files are case-sensitive. When scanning Fortran codes to generate a signature file, F2PY lowers all cases automatically except in multi-line blocks or when the ``--no-lower`` option is @@ -596,10 +603,10 @@ Extensions F2PY directives ^^^^^^^^^^^^^^^^ -The F2PY directives allow using F2PY signature file constructs in -Fortran 77/90 source codes. With this feature one can (almost) completely skip -the intermediate signature file generation and apply F2PY directly to Fortran -source codes. +The F2PY directives allow using F2PY signature file constructs in Fortran 77/90 +source codes. With this feature one can (almost) completely skip the +intermediate signature file generation and apply F2PY directly to Fortran source +codes. F2PY directives have the following form::