diff options
author | Rohit Goswami <rgoswami@quansight.com> | 2022-02-22 13:02:21 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-02-22 13:02:21 +0000 |
commit | caf5ace54641cea3a81b63f6ec46675cb31b87c3 (patch) | |
tree | 18e390d39228792e3f510a86cd93aead886ad9f0 | |
parent | dfa890e7312f3afe6350cdfcc62c7d93a49c66ee (diff) | |
parent | 148baf608d1ef8e0cbc3d5e0bbe141608095529b (diff) | |
download | numpy-caf5ace54641cea3a81b63f6ec46675cb31b87c3.tar.gz |
Merge pull request #20559 from melissawm/f2py-guide
DOC: Refactoring f2py user guide
-rw-r--r-- | doc/source/f2py/code/add-edited.pyf | 6 | ||||
-rw-r--r-- | doc/source/f2py/code/add-improved.f | 16 | ||||
-rw-r--r-- | doc/source/f2py/code/add.f | 11 | ||||
-rw-r--r-- | doc/source/f2py/code/add.pyf | 6 | ||||
-rw-r--r-- | doc/source/f2py/code/filter.f | 19 | ||||
-rw-r--r-- | doc/source/f2py/code/myroutine-edited.pyf | 17 | ||||
-rw-r--r-- | doc/source/f2py/code/myroutine.f90 | 10 | ||||
-rw-r--r-- | doc/source/f2py/code/myroutine.pyf | 17 | ||||
-rw-r--r-- | doc/source/f2py/f2py-examples.rst | 245 | ||||
-rw-r--r-- | doc/source/f2py/f2py-reference.rst | 12 | ||||
-rw-r--r-- | doc/source/f2py/f2py-user.rst | 11 | ||||
-rw-r--r-- | doc/source/f2py/f2py.getting-started.rst | 110 | ||||
-rw-r--r-- | doc/source/f2py/index.rst | 34 | ||||
-rw-r--r-- | doc/source/f2py/python-usage.rst | 276 | ||||
-rw-r--r-- | doc/source/f2py/signature-file.rst | 146 | ||||
-rw-r--r-- | doc/source/f2py/usage.rst | 425 | ||||
-rw-r--r-- | doc/source/glossary.rst | 34 | ||||
-rw-r--r-- | doc/source/user/c-info.python-as-glue.rst | 298 | ||||
-rw-r--r-- | numpy/f2py/__init__.py | 24 | ||||
-rwxr-xr-x | numpy/f2py/f2py2e.py | 8 | ||||
-rw-r--r-- | tools/refguide_check.py | 1 |
21 files changed, 951 insertions, 775 deletions
diff --git a/doc/source/f2py/code/add-edited.pyf b/doc/source/f2py/code/add-edited.pyf new file mode 100644 index 000000000..4d2047274 --- /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 000000000..65f70c9bc --- /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 000000000..5e7556b28 --- /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 000000000..d2583e333 --- /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 000000000..fb44343fa --- /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 000000000..14e455416 --- /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(kind=8) dimension(:),intent(in) :: c + real(kind=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 000000000..592796a6a --- /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 000000000..ef8f16789 --- /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(kind=8) dimension(:),intent(in) :: c + real(kind=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 new file mode 100644 index 000000000..8dcdec075 --- /dev/null +++ b/doc/source/f2py/f2py-examples.rst @@ -0,0 +1,245 @@ +.. _f2py-examples: + +F2PY examples +============= + +Below are some examples of F2PY usage. This list is not comprehensive, but can +be used as a starting point when wrapping your own code. + +F2PY walkthrough: a basic extension module +------------------------------------------ + +Creating source for a basic extension module +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Consider the following subroutine, contained in a file named :file:`add.f` + +.. 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:: + + 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 +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:: + + python -m numpy.f2py -c -m add add.f + +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 + + >>> import add + >>> print(add.zadd.__doc__) + zadd(a,b,c,n) + + Wrapper for ``zadd``. + + Parameters + ---------- + a : input rank-1 array('D') with bounds (*) + b : input rank-1 array('D') with bounds (*) + c : input rank-1 array('D') with bounds (*) + n : input int + +Improving the basic interface +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +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 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. + +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:: + + python -m numpy.f2py -h add.pyf -m add add.f + +This command creates the ``add.pyf`` file in the current directory. The section +of this file corresponding to ``zadd`` is: + +.. literalinclude:: ./code/add.pyf + :language: fortran + +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. + +.. 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 +passed to the underlying code. The intent(hide) directive tells f2py +to not allow the user to specify the variable, ``n``, but instead to +get it from the size of ``a``. The depend( ``a`` ) directive is +necessary to tell f2py that the value of n depends on the input a (so +that it won't try to create the variable n until the variable a is +created). + +After modifying ``add.pyf``, the new Python module file can be generated +by compiling both ``add.f`` and ``add.pyf``:: + + python -m numpy.f2py -c add.pyf add.f + +The new interface's docstring is: + +.. code-block:: python + + >>> import add + >>> print(add.zadd.__doc__) + c = zadd(a,b) + + Wrapper for ``zadd``. + + Parameters + ---------- + a : input rank-1 array('D') with bounds (n) + b : input rank-1 array('D') with bounds (n) + + Returns + ------- + c : rank-1 array('D') with bounds (n) + +Now, the function can be called in a much more robust way: + +.. code-block:: + + >>> add.zadd([1, 2, 3], [4, 5, 6]) + array([5.+0.j, 7.+0.j, 9.+0.j]) + +Notice the automatic conversion to the correct format that occurred. + +Inserting directives in Fortran source +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +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: + +.. literalinclude:: ./code/add-improved.f + :language: fortran + +Then, one can compile the extension module using:: + + 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 +contained ``A(N)`` instead of ``A(*)`` and so forth with ``B`` and ``C``, +then nearly the same interface can be obtained by placing the +``INTENT(OUT) :: C`` comment line in the source code. The only difference +is that ``N`` would be an optional input that would default to the length +of ``A``. + +A filtering example +------------------- + +This example shows a function that filters a two-dimensional array of double +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. + +.. literalinclude:: ./code/filter.f + :language: fortran + +This code can be compiled and linked into an extension module named +filter using:: + + 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. + + +``depends`` keyword example +--------------------------- + +Consider the following code, saved in the file ``myroutine.f90``: + +.. literalinclude:: ./code/myroutine.f90 + :language: fortran + +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 + >>> x = myroutine.s(2, 3, np.array([5, 6, 7])) + >>> x + array([[5., 0., 0.], + [0., 0., 0.]]) + +Now, instead of generating the extension module directly, we will create a +signature file for this subroutine first. This is a common pattern for +multi-step extension module generation. In this case, after running + +.. code-block:: python + + python -m numpy.f2py myroutine.f90 -h myroutine.pyf + +the following signature file is generated: + +.. literalinclude:: ./code/myroutine.pyf + :language: fortran + +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. + + +Read more +--------- + +* `Wrapping C codes using f2py <https://scipy.github.io/old-wiki/pages/Cookbook/f2py_and_NumPy.html>`_ +* `F2py section on the SciPy Cookbook <https://scipy-cookbook.readthedocs.io/items/F2Py.html>`_ +* `F2py example: Interactive System for Ice sheet Simulation <http://websrv.cs.umt.edu/isis/index.php/F2py_example>`_ +* `"Interfacing With Other Languages" section on the SciPy Cookbook. + <https://scipy-cookbook.readthedocs.io/items/idx_interfacing_with_other_languages.html>`_ diff --git a/doc/source/f2py/f2py-reference.rst b/doc/source/f2py/f2py-reference.rst new file mode 100644 index 000000000..28db0bfee --- /dev/null +++ b/doc/source/f2py/f2py-reference.rst @@ -0,0 +1,12 @@ +.. _f2py-reference: + +F2PY reference manual +===================== + +.. toctree:: + :maxdepth: 2 + + signature-file + python-usage + buildtools/index + advanced diff --git a/doc/source/f2py/f2py-user.rst b/doc/source/f2py/f2py-user.rst new file mode 100644 index 000000000..70d4aedd0 --- /dev/null +++ b/doc/source/f2py/f2py-user.rst @@ -0,0 +1,11 @@ +.. _f2py-user: + +F2PY user guide +=============== + +.. toctree:: + :maxdepth: 2 + + f2py.getting-started + usage + f2py-examples
\ No newline at end of file diff --git a/doc/source/f2py/f2py.getting-started.rst b/doc/source/f2py/f2py.getting-started.rst index c1a006f6f..da88b46f5 100644 --- a/doc/source/f2py/f2py.getting-started.rst +++ b/doc/source/f2py/f2py.getting-started.rst @@ -7,15 +7,14 @@ Wrapping Fortran or C functions to Python using F2PY consists of the following steps: -* Creating the so-called signature file that contains descriptions of - wrappers to Fortran or C functions, also called the signatures of the - functions. For Fortran routines, F2PY can create an initial - signature file by scanning Fortran source codes and - tracking all relevant information needed to create wrapper - functions. +* Creating the so-called :doc:`signature file <signature-file>` that contains + descriptions of wrappers to Fortran or C functions, also called the signatures + of the functions. For Fortran routines, F2PY can create an initial signature + file by scanning Fortran source codes and tracking all relevant information + needed to create wrapper functions. - * Optionally, F2PY created signature files can be edited to optimize - wrapper functions, to make them "smarter" and more "Pythonic". + * Optionally, F2PY-created signature files can be edited to optimize wrapper + 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. @@ -24,7 +23,8 @@ following steps: * In building the extension modules, F2PY uses ``numpy_distutils`` which supports a number of Fortran 77/90/95 compilers, including Gnu, Intel, Sun - Fortran, SGI MIPSpro, Absoft, NAG, Compaq etc. + Fortran, SGI MIPSpro, Absoft, NAG, Compaq etc. For different build systems, + see :ref:`f2py-bldsys`. Depending on the situation, these steps can be carried out in a single composite command or step-by-step; in which case some steps can be omitted or combined @@ -40,6 +40,13 @@ illustration, save it as ``fib1.f``: .. literalinclude:: ./code/fib1.f :language: fortran +.. note:: + + F2PY parses Fortran/C signatures to build wrapper functions to be used with + Python. However, it is not a compiler, and does not check for additional + errors in source code, nor does it implement the entire language standards. + Some errors may pass silently (or as warnings) and need to be verified by the + user. The quick way ============== @@ -51,6 +58,18 @@ run python -m numpy.f2py -c fib1.f -m fib1 +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 @@ -103,15 +122,15 @@ Fortran subroutine ``FIB`` is accessible via ``fib1.fib``:: F2PY implements basic compatibility checks between related arguments in order to avoid unexpected crashes. - * When a NumPy array, that is Fortran contiguous and has a ``dtype`` - corresponding to a presumed Fortran type, is used as an input array - argument, then its C pointer is directly passed to Fortran. + * When a NumPy array that is :term:`Fortran <Fortran order>` + :term:`contiguous` and has a ``dtype`` corresponding to a presumed Fortran + type is used as an input array argument, then its C pointer is directly + passed to Fortran. - Otherwise F2PY makes a contiguous copy (with the proper ``dtype``) of - the input array and passes a C pointer of the copy to the Fortran - subroutine. As a result, any possible changes to the (copy of) - input array have no effect to the original argument, as - demonstrated below:: + Otherwise, F2PY makes a contiguous copy (with the proper ``dtype``) of the + input array and passes a C pointer of the copy to the Fortran subroutine. As + a result, any possible changes to the (copy of) input array have no effect + on the original argument, as demonstrated below:: >>> a = np.ones(8, 'i') >>> fib1.fib(a) @@ -121,11 +140,11 @@ Fortran subroutine ``FIB`` is accessible via ``fib1.fib``:: Clearly, this is unexpected, as Fortran typically passes by reference. That the above example worked with ``dtype=float`` is considered accidental. - F2PY provides an ``intent(inplace)`` attribute that modifies - the attributes of an input array so that any changes made by - Fortran routine will be reflected in the input argument. For example, - if one specifies the ``intent(inplace) a`` directive (see subsequent - sections on how), then the example above would read:: + F2PY provides an ``intent(inplace)`` attribute that modifies the attributes + of an input array so that any changes made by the Fortran routine will be + reflected in the input argument. For example, if one specifies the + ``intent(inplace) a`` directive (see :ref:`f2py-attributes` for details), + then the example above would read:: >>> a = np.ones(8, 'i') >>> fib1.fib(a) @@ -133,8 +152,8 @@ Fortran subroutine ``FIB`` is accessible via ``fib1.fib``:: [ 0. 1. 1. 2. 3. 5. 8. 13.] However, the recommended way to have changes made by Fortran subroutine - propagate to Python is to use the ``intent(out)`` attribute. That approach is - more efficient and also cleaner. + propagate to Python is to use the ``intent(out)`` attribute. That approach + is more efficient and also cleaner. * The usage of ``fib1.fib`` in Python is very similar to using ``FIB`` in Fortran. However, using *in situ* output arguments in Python is poor style, @@ -145,23 +164,23 @@ Fortran subroutine ``FIB`` is accessible via ``fib1.fib``:: may lead to difficult to find bugs, not to mention the fact that the codes will be less readable when all required type checks are implemented. - Though the approach to wrapping Fortran routines for Python discussed so far is - very straightforward, it has several drawbacks (see the comments above). + Though the approach to wrapping Fortran routines for Python discussed so far + is very straightforward, it has several drawbacks (see the comments above). The drawbacks are due to the fact that there is no way for F2PY to determine - the actual intention of the arguments; that is there is ambiguity in + the actual intention of the arguments; that is, there is ambiguity in distinguishing between input and output arguments. Consequently, F2PY assumes that all arguments are input arguments by default. - However, there are ways (see below) to remove this ambiguity by "teaching" - F2PY about the true intentions of function arguments, and F2PY is then able to - generate more explicit, easier to use, and less error prone wrappers for - Fortran functions. + There are ways (see below) to remove this ambiguity by "teaching" F2PY about + the true intentions of function arguments, and F2PY is then able to generate + more explicit, easier to use, and less error prone wrappers for Fortran + functions. The smart way ============== -Let us apply the steps for wrapping Fortran functions to Python one by -one. +If we want to have more control over how F2PY will treat the interface to our +Fortran code, we can apply the wrapping steps one by one. * First, we create a signature file from ``fib1.f`` by running: @@ -169,21 +188,21 @@ one. python -m numpy.f2py fib1.f -m fib2 -h fib1.pyf - The signature file is saved to ``fib1.pyf`` (see the ``-h`` flag) and - its contents are shown below. + The signature file is saved to ``fib1.pyf`` (see the ``-h`` flag) and its + contents are shown below. .. literalinclude:: ./code/fib1.pyf :language: fortran * Next, we'll teach F2PY that the argument ``n`` is an input argument (using the ``intent(in)`` attribute) and that the result, i.e., the contents of ``a`` - after calling the Fortran function ``FIB``, should be returned to Python (using - the ``intent(out)`` attribute). In addition, an array ``a`` should be created - dynamically using the size determined by the input argument ``n`` (using the - ``depend(n)`` attribute to indicate this dependence relation). + after calling the Fortran function ``FIB``, should be returned to Python + (using the ``intent(out)`` attribute). In addition, an array ``a`` should be + created dynamically using the size determined by the input argument ``n`` + (using the ``depend(n)`` attribute to indicate this dependence relation). The contents of a suitably modified version of ``fib1.pyf`` (saved as - ``fib2.pyf``) is as follows: + ``fib2.pyf``) are as follows: .. literalinclude:: ./code/fib2.pyf :language: fortran @@ -215,15 +234,18 @@ In Python:: .. note:: - * The signature of ``fib2.fib`` now more closely corresponds to the - intention of Fortran subroutine ``FIB``: given the number ``n``, - ``fib2.fib`` returns the first ``n`` Fibonacci numbers as a NumPy array. - The new Python signature ``fib2.fib`` also rules out the unexpected behaviour in ``fib1.fib``. + * The signature of ``fib2.fib`` now more closely corresponds to the intention + of the Fortran subroutine ``FIB``: given the number ``n``, ``fib2.fib`` + returns the first ``n`` Fibonacci numbers as a NumPy array. The new Python + signature ``fib2.fib`` also rules out the unexpected behaviour in + ``fib1.fib``. * Note that by default, using a single ``intent(out)`` also implies ``intent(hide)``. Arguments that have the ``intent(hide)`` attribute specified will not be listed in the argument list of a wrapper function. + For more details, see :doc:`signature-file`. + The quick and smart way ======================== diff --git a/doc/source/f2py/index.rst b/doc/source/f2py/index.rst index 56df31b4e..913eacbb1 100644 --- a/doc/source/f2py/index.rst +++ b/doc/source/f2py/index.rst @@ -5,10 +5,10 @@ F2PY user guide and reference manual ===================================== The purpose of the ``F2PY`` --*Fortran to Python interface generator*-- utility -is to provide a connection between Python and Fortran -languages. F2PY is a part of NumPy_ (``numpy.f2py``) and also available as a -standalone command line tool ``f2py`` when ``numpy`` is installed that -facilitates creating/building Python C/API extension modules that make it +is to provide a connection between Python and Fortran. F2PY is a part of NumPy_ +(``numpy.f2py``) and also available as a standalone command line tool. + +F2PY facilitates creating/building Python C/API extension modules that make it possible * to call Fortran 77/90/95 external subroutines and Fortran 90/95 @@ -18,15 +18,25 @@ possible from Python. +F2PY can be used either as a command line tool ``f2py`` or as a Python +module ``numpy.f2py``. While we try to provide the command line tool as part +of the numpy setup, some platforms like Windows make it difficult to +reliably put the executables on the ``PATH``. If the ``f2py`` command is not +available in your system, you may have to run it as a module:: + + python -m numpy.f2py + +If you run ``f2py`` with no arguments, and the line ``numpy Version`` at the +end matches the NumPy version printed from ``python -m numpy.f2py``, then you +can use the shorter version. If not, or if you cannot run ``f2py``, you should +replace all calls to ``f2py`` mentioned in this guide with the longer version. + .. toctree:: - :maxdepth: 2 - - usage - f2py.getting-started - python-usage - signature-file - buildtools/index - advanced + :maxdepth: 3 + + f2py-user + f2py-reference + .. _Python: https://www.python.org/ .. _NumPy: https://www.numpy.org/ diff --git a/doc/source/f2py/python-usage.rst b/doc/source/f2py/python-usage.rst index ef8ccd7dd..c3379f6c5 100644 --- a/doc/source/f2py/python-usage.rst +++ b/doc/source/f2py/python-usage.rst @@ -2,41 +2,48 @@ Using F2PY bindings in Python ================================== -All wrappers for Fortran/C routines, common blocks, or for Fortran -90 module data generated by F2PY are exposed to Python as ``fortran`` -type objects. Routine wrappers are callable ``fortran`` type objects -while wrappers to Fortran data have attributes referring to data -objects. +In this page, you can find a full description and a few examples of common usage +patterns for F2PY with Python and different argument types. For more examples +and use cases, see :ref:`f2py-examples`. + +Fortran type objects +==================== + +All wrappers for Fortran/C routines, common blocks, or for Fortran 90 module +data generated by F2PY are exposed to Python as ``fortran`` type objects. +Routine wrappers are callable ``fortran`` type objects while wrappers to Fortran +data have attributes referring to data objects. All ``fortran`` type objects have an attribute ``_cpointer`` that contains a ``CObject`` referring to the C pointer of the corresponding Fortran/C function -or variable at the C level. Such ``CObjects`` can be used as a callback argument +or variable at the C level. Such ``CObjects`` can be used as callback arguments for F2PY generated functions to bypass the Python C/API layer for calling Python -functions from Fortran or C when the computational aspects of such functions are -implemented in C or Fortran and wrapped with F2PY (or any other tool capable of -providing the ``CObject`` of a function). +functions from Fortran or C. This can be useful when the computational aspects +of such functions are implemented in C or Fortran and wrapped with F2PY (or any +other tool capable of providing the ``CObject`` of a function). Consider a Fortran 77 file ```ftype.f``: - .. literalinclude:: ./code/ftype.f - :language: fortran +.. literalinclude:: ./code/ftype.f + :language: fortran and a wrapper built using ``f2py -c ftype.f -m ftype``. -In Python: +In Python, you can observe the types of ``foo`` and ``data``, and how to access +individual objects of the wrapped Fortran code. - .. literalinclude:: ./code/results/ftype_session.dat - :language: python +.. literalinclude:: ./code/results/ftype_session.dat + :language: python Scalar arguments ================= -In general, a scalar argument for a F2PY generated wrapper function can -be an ordinary Python scalar (integer, float, complex number) as well as -an arbitrary sequence object (list, tuple, array, string) of -scalars. In the latter case, the first element of the sequence object -is passed to Fortran routine as a scalar argument. +In general, a scalar argument for a F2PY generated wrapper function can be an +ordinary Python scalar (integer, float, complex number) as well as an arbitrary +sequence object (list, tuple, array, string) of scalars. In the latter case, the +first element of the sequence object is passed to the Fortran routine as a +scalar argument. .. note:: @@ -44,52 +51,57 @@ is passed to Fortran routine as a scalar argument. narrowing e.g. when type-casting float to integer or complex to float, F2PY *does not* raise an exception. - * For complex to real type-casting only the real part of a complex number is used. + * For complex to real type-casting only the real part of a complex number + is used. * ``intent(inout)`` scalar arguments are assumed to be array objects in order to have *in situ* changes be effective. It is recommended to use - arrays with proper type but also other types work. + arrays with proper type but also other types work. :ref:`Read more about + the intent attribute <f2py-attributes>`. Consider the following Fortran 77 code: - .. literalinclude:: ./code/scalar.f - :language: fortran +.. literalinclude:: ./code/scalar.f + :language: fortran and wrap it using ``f2py -c -m scalar scalar.f``. In Python: - .. literalinclude:: ./code/results/scalar_session.dat - :language: python +.. literalinclude:: ./code/results/scalar_session.dat + :language: python String arguments ================= -F2PY generated wrapper functions accept almost any Python object as -a string argument, since ``str`` is applied for non-string objects. -Exceptions are NumPy arrays that must have type code ``'c'`` or -``'1'`` when used as string arguments. +F2PY generated wrapper functions accept almost any Python object as a string +argument, since ``str`` is applied for non-string objects. Exceptions are NumPy +arrays that must have type code ``'S1'`` or ``'b'`` (corresponding to the +outdated ``'c'`` or ``'1'`` typecodes, respectively) when used as string +arguments. See :ref:`arrays.scalars` for more information on these typecodes. -A string can have an arbitrary length when used as a string argument -for an F2PY generated wrapper function. If the length is greater than -expected, the string is truncated silently. If the length is smaller than -expected, additional memory is allocated and filled with ``\0``. +A string can have an arbitrary length when used as a string argument for an F2PY +generated wrapper function. If the length is greater than expected, the string +is truncated silently. If the length is smaller than expected, additional memory +is allocated and filled with ``\0``. -Because Python strings are immutable, an ``intent(inout)`` argument -expects an array version of a string in order to have *in situ* changes be effective. +.. TODO: review this section once https://github.com/numpy/numpy/pull/19388 is merged. + +Because Python strings are immutable, an ``intent(inout)`` argument expects an +array version of a string in order to have *in situ* changes be effective. Consider the following Fortran 77 code: - .. literalinclude:: ./code/string.f - :language: fortran +.. literalinclude:: ./code/string.f + :language: fortran and wrap it using ``f2py -c -m mystring string.f``. Python session: - .. literalinclude:: ./code/results/string_session.dat - :language: python +.. literalinclude:: ./code/results/string_session.dat + :language: python Array arguments @@ -99,40 +111,17 @@ In general, array arguments for F2PY generated wrapper functions accept arbitrary sequences that can be transformed to NumPy array objects. There are two notable exceptions: -* ``intent(inout)`` array arguments must always be proper-contiguous (defined below) and have a - compatible ``dtype``, otherwise an exception is raised. +* ``intent(inout)`` array arguments must always be + :term:`proper-contiguous <contiguous>` and have a compatible ``dtype``, + otherwise an exception is raised. * ``intent(inplace)`` array arguments will be changed *in situ* if the argument - has a different type than expected (see the ``intent(inplace)`` attribute for - more information). - -In general, if a NumPy array is proper-contiguous and has a proper type then it -is directly passed to the wrapped Fortran/C function. Otherwise, an element-wise -copy of the input array is made and the copy, being proper-contiguous and with -proper type, is used as the array argument. - -There are two types of proper-contiguous NumPy arrays: - -* Fortran-contiguous arrays refer to data that is stored columnwise, - i.e. the indexing of data as stored in memory starts from the lowest - dimension; -* C-contiguous, or simply contiguous arrays, refer to data that is stored - rowwise, i.e. the indexing of data as stored in memory starts from the highest - dimension. - -For one-dimensional arrays these notions coincide. - -For example, a 2x2 array ``A`` is Fortran-contiguous if its elements -are stored in memory in the following order:: - - A[0,0] A[1,0] A[0,1] A[1,1] - -and C-contiguous if the order is as follows:: - - A[0,0] A[0,1] A[1,0] A[1,1] + has a different type than expected (see the ``intent(inplace)`` + :ref:`attribute <f2py-attributes>` for more information). -To test whether an array is C-contiguous, use the ``.flags.c_contiguous`` -attribute of NumPy arrays. To test for Fortran contiguity, use the -``.flags.f_contiguous`` attribute. +In general, if a NumPy array is :term:`proper-contiguous <contiguous>` and has +a proper type then it is directly passed to the wrapped Fortran/C function. +Otherwise, an element-wise copy of the input array is made and the copy, being +proper-contiguous and with proper type, is used as the array argument. Usually there is no need to worry about how the arrays are stored in memory and whether the wrapped functions, being either Fortran or C functions, assume one @@ -144,19 +133,19 @@ physical memory in your computer, then care must be taken to ensure the usage of proper-contiguous and proper type arguments. To transform input arrays to column major storage order before passing -them to Fortran routines, use the function ``numpy.asfortranarray(<array>)``. +them to Fortran routines, use the function `numpy.asfortranarray`. Consider the following Fortran 77 code: - .. literalinclude:: ./code/array.f - :language: fortran +.. literalinclude:: ./code/array.f + :language: fortran and wrap it using ``f2py -c -m arr array.f -DF2PY_REPORT_ON_ARRAY_COPY=1``. In Python: - .. literalinclude:: ./code/results/array_session.dat - :language: python +.. literalinclude:: ./code/results/array_session.dat + :language: python .. _Call-back arguments: @@ -167,15 +156,15 @@ F2PY supports calling Python functions from Fortran or C codes. Consider the following Fortran 77 code: - .. literalinclude:: ./code/callback.f - :language: fortran +.. literalinclude:: ./code/callback.f + :language: fortran and wrap it using ``f2py -c -m callback callback.f``. In Python: - .. literalinclude:: ./code/results/callback_session.dat - :language: python +.. literalinclude:: ./code/results/callback_session.dat + :language: python In the above example F2PY was able to guess accurately the signature of the call-back function. However, sometimes F2PY cannot establish the @@ -183,13 +172,13 @@ appropriate signature; in these cases the signature of the call-back function must be explicitly defined in the signature file. To facilitate this, signature files may contain special modules (the names of -these modules contain the special ``__user__`` sub-string) that defines the +these modules contain the special ``__user__`` sub-string) that define the various signatures for call-back functions. Callback arguments in routine signatures have the ``external`` attribute (see also the ``intent(callback)`` -attribute). To relate a callback argument with its signature in a ``__user__`` -module block, a ``use`` statement can be utilized as illustrated below. The same -signature for a callback argument can be referred to in different routine -signatures. +:ref:`attribute <f2py-attributes>`). To relate a callback argument with its +signature in a ``__user__`` module block, a ``use`` statement can be utilized as +illustrated below. The same signature for a callback argument can be referred to +in different routine signatures. We use the same Fortran 77 code as in the previous example but now we will pretend that F2PY was not able to guess the signatures of @@ -200,69 +189,67 @@ file ``callback2.pyf`` using F2PY:: Then modify it as follows - .. include:: ./code/callback2.pyf - :literal: +.. include:: ./code/callback2.pyf + :literal: -Finally, we build the extension module using ``f2py -c callback2.pyf callback.f``. +Finally, we build the extension module using +``f2py -c callback2.pyf callback.f``. An example Python session for this snippet would be identical to the previous example except that the argument names would differ. -Sometimes a Fortran package may require that users provide routines -that the package will use. F2PY can construct an interface to such -routines so that Python functions can be called from Fortran. +Sometimes a Fortran package may require that users provide routines that the +package will use. F2PY can construct an interface to such routines so that +Python functions can be called from Fortran. Consider the following Fortran 77 subroutine that takes an array as its input and applies a function ``func`` to its elements. - .. literalinclude:: ./code/calculate.f - :language: fortran +.. literalinclude:: ./code/calculate.f + :language: fortran The Fortran code expects that the function ``func`` has been defined externally. In order to use a Python function for ``func``, it must have an attribute -``intent(callback)`` and, it must be specified before the ``external`` statement. +``intent(callback)`` and it must be specified before the ``external`` statement. Finally, build an extension module using ``f2py -c -m foo calculate.f`` In Python: - .. literalinclude:: ./code/results/calculate_session.dat - :language: python +.. literalinclude:: ./code/results/calculate_session.dat + :language: python The function is included as an argument to the python function call to the Fortran subroutine even though it was *not* in the Fortran subroutine argument list. The "external" keyword refers to the C function generated by f2py, not the -python function itself. The python function is essentially being supplied to the +Python function itself. The python function is essentially being supplied to the C function. -The callback function may also be explicitly set in the module. -Then it is not necessary to pass the function in the argument list to -the Fortran function. This may be desired if the Fortran function calling -the python callback function is itself called by another Fortran function. +The callback function may also be explicitly set in the module. Then it is not +necessary to pass the function in the argument list to the Fortran function. +This may be desired if the Fortran function calling the Python callback function +is itself called by another Fortran function. Consider the following Fortran 77 subroutine: - .. literalinclude:: ./code/extcallback.f - :language: fortran +.. literalinclude:: ./code/extcallback.f + :language: fortran and wrap it using ``f2py -c -m pfromf extcallback.f``. In Python: - .. literalinclude:: ./code/results/extcallback_session.dat - :language: python +.. literalinclude:: ./code/results/extcallback_session.dat + :language: python Resolving arguments to call-back functions -=========================================== +------------------------------------------ -F2PY generated interfaces are very flexible with respect to call-back -arguments. For each call-back argument an additional optional -argument ``<name>_extra_args`` is introduced by F2PY. This argument -can be used to pass extra arguments to user provided call-back -functions. +F2PY generated interfaces are very flexible with respect to call-back arguments. For each call-back argument an additional optional +argument ``<name>_extra_args`` is introduced by F2PY. This argument can be used +to pass extra arguments to user provided call-back functions. -If a F2PY generated wrapper function expects the following call-back -argument:: +If a F2PY generated wrapper function expects the following call-back argument:: def fun(a_1,...,a_n): ... @@ -282,20 +269,20 @@ is provided by a user, and in addition, fun_extra_args = (e_1,...,e_p) -is used, then the following rules are applied when a Fortran or C -function evaluates the call-back argument ``gun``: +is used, then the following rules are applied when a Fortran or C function +evaluates the call-back argument ``gun``: * If ``p == 0`` then ``gun(a_1, ..., a_q)`` is called, here ``q = min(m, n)``. * If ``n + p <= m`` then ``gun(a_1, ..., a_n, e_1, ..., e_p)`` is called. -* If ``p <= m < n + p`` then ``gun(a_1, ..., a_q, e_1, ..., e_p)`` is called, here - ``q=m-p``. +* If ``p <= m < n + p`` then ``gun(a_1, ..., a_q, e_1, ..., e_p)`` is called, + and here ``q=m-p``. * If ``p > m`` then ``gun(e_1, ..., e_m)`` is called. -* If ``n + p`` is less than the number of required arguments to ``gun`` - then an exception is raised. +* If ``n + p`` is less than the number of required arguments to ``gun`` then an + exception is raised. -If the function ``gun`` may return any number of objects as a tuple; then -the following rules are applied: +If the function ``gun`` may return any number of objects as a tuple; then the +following rules are applied: * If ``k < l``, then ``y_{k + 1}, ..., y_l`` are ignored. * If ``k > l``, then only ``x_1, ..., x_l`` are set. @@ -304,48 +291,47 @@ the following rules are applied: Common blocks ============== -F2PY generates wrappers to ``common`` blocks defined in a routine -signature block. Common blocks are visible to all Fortran codes linked -to the current extension module, but not to other extension modules -(this restriction is due to the way Python imports shared libraries). In -Python, the F2PY wrappers to ``common`` blocks are ``fortran`` type -objects that have (dynamic) attributes related to the data members of -the common blocks. When accessed, these attributes return as NumPy array -objects (multidimensional arrays are Fortran-contiguous) which -directly link to data members in common blocks. Data members can be -changed by direct assignment or by in-place changes to the +F2PY generates wrappers to ``common`` blocks defined in a routine signature +block. Common blocks are visible to all Fortran codes linked to the current +extension module, but not to other extension modules (this restriction is due to +the way Python imports shared libraries). In Python, the F2PY wrappers to +``common`` blocks are ``fortran`` type objects that have (dynamic) attributes +related to the data members of the common blocks. When accessed, these +attributes return as NumPy array objects (multidimensional arrays are +Fortran-contiguous) which directly link to data members in common blocks. Data +members can be changed by direct assignment or by in-place changes to the corresponding array objects. Consider the following Fortran 77 code: - .. literalinclude:: ./code/common.f - :language: fortran +.. literalinclude:: ./code/common.f + :language: fortran and wrap it using ``f2py -c -m common common.f``. In Python: - .. literalinclude:: ./code/results/common_session.dat - :language: python +.. literalinclude:: ./code/results/common_session.dat + :language: python Fortran 90 module data ======================= -The F2PY interface to Fortran 90 module data is similar to the handling of Fortran 77 -common blocks. +The F2PY interface to Fortran 90 module data is similar to the handling of +Fortran 77 common blocks. Consider the following Fortran 90 code: - .. literalinclude:: ./code/moddata.f90 - :language: fortran +.. literalinclude:: ./code/moddata.f90 + :language: fortran and wrap it using ``f2py -c -m moddata moddata.f90``. In Python: - .. literalinclude:: ./code/results/moddata_session.dat - :language: python +.. literalinclude:: ./code/results/moddata_session.dat + :language: python Allocatable arrays @@ -355,12 +341,12 @@ F2PY has basic support for Fortran 90 module allocatable arrays. Consider the following Fortran 90 code: - .. literalinclude:: ./code/allocarr.f90 - :language: fortran +.. literalinclude:: ./code/allocarr.f90 + :language: fortran and wrap it using ``f2py -c -m allocarr allocarr.f90``. In Python: - .. literalinclude:: ./code/results/allocarr_session.dat - :language: python +.. literalinclude:: ./code/results/allocarr_session.dat + :language: python diff --git a/doc/source/f2py/signature-file.rst b/doc/source/f2py/signature-file.rst index b80b31509..cea3682c2 100644 --- a/doc/source/f2py/signature-file.rst +++ b/doc/source/f2py/signature-file.rst @@ -2,28 +2,39 @@ Signature file ================== -The syntax specification for signature files (.pyf files) is modeled on the -Fortran 90/95 language specification. Almost all Fortran 90/95 standard -constructs are understood, both in free and fixed format (recall that Fortran 77 -is a subset of Fortran 90/95). F2PY introduces some extensions to the Fortran -90/95 language specification that help in the design of the Fortran to Python -interface, making it more "Pythonic". +The interface definition file (.pyf) is how you can fine-tune the interface +between Python and Fortran. The syntax specification for signature files +(``.pyf`` files) is modeled on the Fortran 90/95 language specification. Almost +all Fortran 90/95 standard constructs are understood, both in free and fixed +format (recall that Fortran 77 is a subset of Fortran 90/95). F2PY introduces +some extensions to the Fortran 90/95 language specification that help in the +design of the Fortran to Python interface, making it more "Pythonic". Signature files may contain arbitrary Fortran code so that any Fortran 90/95 -codes can be treated as signature files. F2PY silently ignores -Fortran 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. +codes can be treated as signature files. F2PY silently ignores Fortran +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 + `NumPy GitHub issue tracker <https://github.com/numpy/numpy/issues>`_ 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 used. +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 +used. The syntax of signature files is presented below. +Signature files syntax +====================== + Python module block -===================== +------------------- A signature file may contain one (recommended) or more ``python module`` blocks. The ``python module`` block describes the contents of @@ -63,7 +74,7 @@ previous section. Fortran/C routine signatures -============================= +---------------------------- The signature of a Fortran routine has the following structure:: @@ -93,8 +104,10 @@ The signature of a Fortran block data has the following structure:: [<include statements>] end [ block data [<block data name>] ] +.. _type-declarations: + Type declarations -================= +----------------- The definition of the ``<argument/variable type declaration>`` part is @@ -128,27 +141,27 @@ and * ``<arrayspec>`` is a comma separated list of dimension bounds; -* ``<init_expr>`` is a `C expression`__; +* ``<init_expr>`` is a :ref:`C expression <c-expressions>`; * ``<intlen>`` may be negative integer for ``integer`` type specifications. In such cases ``integer*<negintlen>`` represents unsigned C integers; -__ `C expressions`_ - If an argument has no ``<argument type declaration>``, its type is determined by applying ``implicit`` rules to its name. Statements -========== +---------- Attribute statements ^^^^^^^^^^^^^^^^^^^^^ -* The ``<argument/variable attribute statement>`` is - ``<argument/variable type declaration>`` without ``<typespec>``. -* In addition, in an attribute statement one cannot use other - attributes, also ``<entitydecl>`` can be only a list of names. +The ``<argument/variable attribute statement>`` is similar to the +``<argument/variable type declaration>``, but without ``<typespec>``. + +An attribute statement cannot contain other attributes, and ``<entitydecl>`` can +be only a list of names. See :ref:`f2py-attributes` for more details on the +attributes that can be used by F2PY. Use statements ^^^^^^^^^^^^^^^ @@ -165,9 +178,8 @@ Use statements <rename_list> := <local_name> => <use_name> [ , <rename_list> ] -* Currently F2PY uses ``use`` statement only for linking call-back - modules and ``external`` arguments (call-back functions), see - :ref:`Call-back arguments`. +* Currently F2PY uses ``use`` statements only for linking call-back modules and + ``external`` arguments (call-back functions). See :ref:`Call-back arguments`. Common block statements ^^^^^^^^^^^^^^^^^^^^^^^ @@ -199,9 +211,7 @@ Other statements except the following: + ``call`` statements and function calls of ``external`` arguments - (`more details`__?); - - __ external_ + (see :ref:`more details on external arguments <external>`); + ``include`` statements :: @@ -256,7 +266,7 @@ Other statements F2PY statements ^^^^^^^^^^^^^^^^ - In addition, F2PY introduces the following statements: +In addition, F2PY introduces the following statements: ``threadsafe`` Uses a ``Py_BEGIN_ALLOW_THREADS .. Py_END_ALLOW_THREADS`` block @@ -271,10 +281,9 @@ F2PY statements block>``. ``callprotoargument <C-typespecs>`` - When the ``callstatement`` statement is used then F2PY may not - generate proper prototypes for Fortran/C functions (because - ``<C-expr>`` may contain any function calls and F2PY has no way - to determine what should be the proper prototype). + When the ``callstatement`` statement is used, F2PY may not generate proper + prototypes for Fortran/C functions (because ``<C-expr>`` may contain function + calls, and F2PY has no way to determine what should be the proper prototype). With this statement you can explicitly specify the arguments of the corresponding prototype:: @@ -321,61 +330,64 @@ F2PY statements __ https://docs.python.org/extending/index.html +.. _f2py-attributes: + Attributes -============ +---------- -The following attributes are used by F2PY: +The following attributes can be used by F2PY. ``optional`` - The corresponding argument is moved to the end of ``<optional - arguments>`` list. A default value for an optional argument can be - specified via ``<init_expr>``, see the ``entitydecl`` definition. - + The corresponding argument is moved to the end of ``<optional arguments>`` + list. A default value for an optional argument can be specified via + ``<init_expr>`` (see the ``entitydecl`` :ref:`definition <type-declarations>`) .. note:: * The default value must be given as a valid C expression. - * Whenever ``<init_expr>`` is used, ``optional`` attribute - is set automatically by F2PY. + * Whenever ``<init_expr>`` is used, the ``optional`` attribute is set + automatically by F2PY. * For an optional array argument, all its dimensions must be bounded. ``required`` - The corresponding argument with this attribute considered mandatory. This is - the default. ``required`` should only be specified if there is a need to + The corresponding argument with this attribute is considered mandatory. This + is the default. ``required`` should only be specified if there is a need to disable the automatic ``optional`` setting when ``<init_expr>`` is used. - If a Python ``None`` object is used as a required argument, the - argument is treated as optional. That is, in the case of array - argument, the memory is allocated. If ``<init_expr>`` is given, then the - corresponding initialization is carried out. + If a Python ``None`` object is used as a required argument, the argument is + treated as optional. That is, in the case of array arguments, the memory is + allocated. If ``<init_expr>`` is given, then the corresponding initialization + is carried out. ``dimension(<arrayspec>)`` The corresponding variable is considered as an array with dimensions given in ``<arrayspec>``. ``intent(<intentspec>)`` - This specifies the "intention" of the corresponding - argument. ``<intentspec>`` is a comma separated list of the - following keys: + This specifies the "intention" of the corresponding argument. ``<intentspec>`` + is a comma separated list of the following keys: * ``in`` - The corresponding argument is considered to be input-only. This means that the value of - the argument is passed to a Fortran/C function and that the function is - expected to not change the value of this argument. + The corresponding argument is considered to be input-only. This means that + the value of the argument is passed to a Fortran/C function and that the + function is expected to not change the value of this argument. * ``inout`` - The corresponding argument is marked for input/output or as an *in situ* output - argument. ``intent(inout)`` arguments can be only "contiguous" NumPy - arrays with proper type and size. Here "contiguous" can be either in the - Fortran or C sense. The latter coincides with the default contiguous + The corresponding argument is marked for input/output or as an *in situ* + output argument. ``intent(inout)`` arguments can be only + :term:`contiguous` NumPy arrays (in either the Fortran or C sense) with + proper type and size. The latter coincides with the default contiguous concept used in NumPy and is effective only if ``intent(c)`` is used. F2PY assumes Fortran contiguous arguments by default. .. note:: - Using ``intent(inout)`` is generally not recommended, use ``intent(in,out)`` instead. + Using ``intent(inout)`` is generally not recommended, as it can cause + unexpected results. For example, scalar arguments using + ``intent(inout)`` are assumed to be array objects in order to have + *in situ* changes be effective. Use ``intent(in,out)`` instead. - See also the ``intent(inplace)`` attribute. + See also the ``intent(inplace)`` attribute. * ``inplace`` The corresponding argument is considered to be an input/output or *in situ* output @@ -586,15 +598,15 @@ The following attributes are used by F2PY: values. 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:: @@ -613,6 +625,8 @@ For fixed format Fortran codes, ``<comment char>`` must be at the first column of a file, of course. For free format Fortran codes, the F2PY directives can appear anywhere in a file. +.. _c-expressions: + C expressions ^^^^^^^^^^^^^^ diff --git a/doc/source/f2py/usage.rst b/doc/source/f2py/usage.rst index 1bf406ff2..332cc5bce 100644 --- a/doc/source/f2py/usage.rst +++ b/doc/source/f2py/usage.rst @@ -2,250 +2,291 @@ Using F2PY =========== -F2PY can be used either as a command line tool ``f2py`` or as a Python -module ``numpy.f2py``. While we try to provide the command line tool as part -of the numpy setup, some platforms like Windows make it difficult to -reliably put the executables on the ``PATH``. We will refer to ``f2py`` -in this document but you may have to run it as a module:: +This page contains a reference to all command-line options for the ``f2py`` +command, as well as a reference to internal functions of the ``numpy.f2py`` +module. - python -m numpy.f2py +Using ``f2py`` as a command-line tool +===================================== -If you run ``f2py`` with no arguments, and the line ``numpy Version`` at the -end matches the NumPy version printed from ``python -m numpy.f2py``, then you -can use the shorter version. If not, or if you cannot run ``f2py``, you should -replace all calls to ``f2py`` here with the longer version. +When used as a command-line tool, ``f2py`` has three major modes, distinguished +by the usage of ``-c`` and ``-h`` switches. -Command ``f2py`` -================= +1. Signature file generation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -When used as a command line tool, ``f2py`` has three major modes, -distinguished by the usage of ``-c`` and ``-h`` switches: +To scan Fortran sources and generate a signature file, use -Signature file generation -^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. code-block:: sh -1. To scan Fortran sources and generate a signature file, use + f2py -h <filename.pyf> <options> <fortran files> \ + [[ only: <fortran functions> : ] \ + [ skip: <fortran functions> : ]]... \ + [<fortran files> ...] - .. code-block:: sh +.. note:: - f2py -h <filename.pyf> <options> <fortran files> \ - [[ only: <fortran functions> : ] \ - [ skip: <fortran functions> : ]]... \ - [<fortran files> ...] + A Fortran source file can contain many routines, and it is often not + necessary to allow all routines to be usable from Python. In such cases, + either specify which routines should be wrapped (in the ``only: .. :`` part) + or which routines F2PY should ignore (in the ``skip: .. :`` part). - .. note:: +If ``<filename.pyf>`` is specified as ``stdout``, then signatures are written to +standard output instead of a file. - A Fortran source file can contain many routines, and it is often - not necessary to allow all routines be usable from Python. In such cases, - either specify which routines should be wrapped (in the ``only: .. :`` part) - or which routines F2PY should ignored (in the ``skip: .. :`` part). +Among other options (see below), the following can be used in this mode: - If ``<filename.pyf>`` is specified as ``stdout`` then signatures - are written to standard output instead of a file. + ``--overwrite-signature`` + Overwrites an existing signature file. - Among other options (see below), the following can be used - in this mode: +2. Extension module construction +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ``--overwrite-signature`` - Overwrites an existing signature file. +To construct an extension module, use -Extension module construction -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. code-block:: sh -2. To construct an extension module, use + f2py -m <modulename> <options> <fortran files> \ + [[ only: <fortran functions> : ] \ + [ skip: <fortran functions> : ]]... \ + [<fortran files> ...] - .. code-block:: sh +The constructed extension module is saved as ``<modulename>module.c`` to the +current directory. - f2py -m <modulename> <options> <fortran files> \ - [[ only: <fortran functions> : ] \ - [ skip: <fortran functions> : ]]... \ - [<fortran files> ...] +Here ``<fortran files>`` may also contain signature files. Among other options +(see below), the following options can be used in this mode: - The constructed extension module is saved as - ``<modulename>module.c`` to the current directory. + ``--debug-capi`` + Adds debugging hooks to the extension module. When using this extension + module, various diagnostic information about the wrapper is written to the + standard output, for example, the values of variables, the steps taken, etc. - Here ``<fortran files>`` may also contain signature files. - Among other options (see below), the following options can be used - in this mode: + ``-include'<includefile>'`` + Add a CPP ``#include`` statement to the extension module source. + ``<includefile>`` should be given in one of the following forms - ``--debug-capi`` - Adds debugging hooks to the extension module. When using this extension - module, various diagnostic information about the wrapper is written to - the standard output, for example, the values of variables, the steps taken, - etc. + .. code-block:: cpp - ``-include'<includefile>'`` - Add a CPP ``#include`` statement to the extension module source. - ``<includefile>`` should be given in one of the following forms + "filename.ext" + <filename.ext> - .. code-block:: cpp + The include statement is inserted just before the wrapper functions. This + feature enables using arbitrary C functions (defined in ``<includefile>``) + in F2PY generated wrappers. - "filename.ext" - <filename.ext> + .. note:: This option is deprecated. Use ``usercode`` statement to specify + C code snippets directly in signature files. - The include statement is inserted just before the wrapper - functions. This feature enables using arbitrary C functions - (defined in ``<includefile>``) in F2PY generated wrappers. + ``--[no-]wrap-functions`` + Create Fortran subroutine wrappers to Fortran functions. + ``--wrap-functions`` is default because it ensures maximum portability and + compiler independence. - .. note:: This option is deprecated. Use ``usercode`` statement to specify C code snippets directly in signature files. + ``--include-paths <path1>:<path2>:..`` + Search include files from given directories. - ``--[no-]wrap-functions`` - Create Fortran subroutine wrappers to Fortran functions. - ``--wrap-functions`` is default because it ensures maximum - portability and compiler independence. + ``--help-link [<list of resources names>]`` + List system resources found by ``numpy_distutils/system_info.py``. For + example, try ``f2py --help-link lapack_opt``. - ``--include-paths <path1>:<path2>:..`` - Search include files from given directories. +3. Building a module +^^^^^^^^^^^^^^^^^^^^ - ``--help-link [<list of resources names>]`` - List system resources found by ``numpy_distutils/system_info.py``. - For example, try ``f2py --help-link lapack_opt``. +To build an extension module, use -Building a module -^^^^^^^^^^^^^^^^^ +.. code-block:: sh -3. To build an extension module, use - - .. code-block:: sh - - f2py -c <options> <fortran files> \ - [[ only: <fortran functions> : ] \ - [ skip: <fortran functions> : ]]... \ - [ <fortran/c source files> ] [ <.o, .a, .so files> ] + f2py -c <options> <fortran files> \ + [[ only: <fortran functions> : ] \ + [ skip: <fortran functions> : ]]... \ + [ <fortran/c source files> ] [ <.o, .a, .so files> ] - If ``<fortran files>`` contains a signature file, then the source for - an extension module is constructed, all Fortran and C sources are - compiled, and finally all object and library files are linked to the - extension module ``<modulename>.so`` which is saved into the current - directory. - - If ``<fortran files>`` does not contain a signature file, then an - extension module is constructed by scanning all Fortran source codes - for routine signatures, before proceeding to build the extension module. +If ``<fortran files>`` contains a signature file, then the source for an +extension module is constructed, all Fortran and C sources are compiled, and +finally all object and library files are linked to the extension module +``<modulename>.so`` which is saved into the current directory. + +If ``<fortran files>`` does not contain a signature file, then an extension +module is constructed by scanning all Fortran source codes for routine +signatures, before proceeding to build the extension module. - Among other options (see below) and options described for previous - modes, the following options can be used in this mode: +Among other options (see below) and options described for previous modes, the +following options can be used in this mode: - ``--help-fcompiler`` - List the available Fortran compilers. - ``--help-compiler`` **[depreciated]** - List the available Fortran compilers. - ``--fcompiler=<Vendor>`` - Specify a Fortran compiler type by vendor. - ``--f77exec=<path>`` - Specify the path to a F77 compiler - ``--fcompiler-exec=<path>`` **[depreciated]** - Specify the path to a F77 compiler - ``--f90exec=<path>`` - Specify the path to a F90 compiler - ``--f90compiler-exec=<path>`` **[depreciated]** - Specify the path to a F90 compiler - ``--f77flags=<string>`` - Specify F77 compiler flags - ``--f90flags=<string>`` - Specify F90 compiler flags - ``--opt=<string>`` - Specify optimization flags - ``--arch=<string>`` - Specify architecture specific optimization flags - ``--noopt`` - Compile without optimization flags - ``--noarch`` - Compile without arch-dependent optimization flags - ``--debug`` - Compile with debugging information - ``-l<libname>`` - Use the library ``<libname>`` when linking. - ``-D<macro>[=<defn=1>]`` - Define macro ``<macro>`` as ``<defn>``. - ``-U<macro>`` - Define macro ``<macro>`` - ``-I<dir>`` - Append directory ``<dir>`` to the list of directories searched for - include files. - ``-L<dir>`` - Add directory ``<dir>`` to the list of directories to be searched - for ``-l``. - ``link-<resource>`` - Link the extension module with <resource> as defined by - ``numpy_distutils/system_info.py``. E.g. to link with optimized - LAPACK libraries (vecLib on MacOSX, ATLAS elsewhere), use - ``--link-lapack_opt``. See also ``--help-link`` switch. - - .. note:: The ``f2py -c`` option must be applied either to an existing ``.pyf`` file (plus the source/object/library files) or one must specify the ``-m <modulename>`` option (plus the sources/object/library files). Use one of the following options: - - .. code-block:: sh - - f2py -c -m fib1 fib1.f - - or - - .. code-block:: sh - - f2py -m fib1 fib1.f -h fib1.pyf - f2py -c fib1.pyf fib1.f - - For more information, see the `Building C and C++ Extensions`__ Python documentation for details. + ``--help-fcompiler`` + List the available Fortran compilers. + ``--help-compiler`` **[depreciated]** + List the available Fortran compilers. + ``--fcompiler=<Vendor>`` + Specify a Fortran compiler type by vendor. + ``--f77exec=<path>`` + Specify the path to a F77 compiler + ``--fcompiler-exec=<path>`` **[depreciated]** + Specify the path to a F77 compiler + ``--f90exec=<path>`` + Specify the path to a F90 compiler + ``--f90compiler-exec=<path>`` **[depreciated]** + Specify the path to a F90 compiler + ``--f77flags=<string>`` + Specify F77 compiler flags + ``--f90flags=<string>`` + Specify F90 compiler flags + ``--opt=<string>`` + Specify optimization flags + ``--arch=<string>`` + Specify architecture specific optimization flags + ``--noopt`` + Compile without optimization flags + ``--noarch`` + Compile without arch-dependent optimization flags + ``--debug`` + Compile with debugging information + ``-l<libname>`` + Use the library ``<libname>`` when linking. + ``-D<macro>[=<defn=1>]`` + Define macro ``<macro>`` as ``<defn>``. + ``-U<macro>`` + Define macro ``<macro>`` + ``-I<dir>`` + Append directory ``<dir>`` to the list of directories searched for include + files. + ``-L<dir>`` + Add directory ``<dir>`` to the list of directories to be searched for + ``-l``. + ``link-<resource>`` + Link the extension module with <resource> as defined by + ``numpy_distutils/system_info.py``. E.g. to link with optimized LAPACK + libraries (vecLib on MacOSX, ATLAS elsewhere), use ``--link-lapack_opt``. + See also ``--help-link`` switch. + +.. note:: + + The ``f2py -c`` option must be applied either to an existing ``.pyf`` file + (plus the source/object/library files) or one must specify the + ``-m <modulename>`` option (plus the sources/object/library files). Use one of + the following options: + + .. code-block:: sh + + f2py -c -m fib1 fib1.f + + or + + .. code-block:: sh + + f2py -m fib1 fib1.f -h fib1.pyf + f2py -c fib1.pyf fib1.f + + For more information, see the `Building C and C++ Extensions`__ Python + documentation for details. __ https://docs.python.org/3/extending/building.html - When building an extension module, a combination of the following - macros may be required for non-gcc Fortran compilers: +When building an extension module, a combination of the following macros may be +required for non-gcc Fortran compilers: - .. code-block:: sh +.. code-block:: sh - -DPREPEND_FORTRAN - -DNO_APPEND_FORTRAN - -DUPPERCASE_FORTRAN + -DPREPEND_FORTRAN + -DNO_APPEND_FORTRAN + -DUPPERCASE_FORTRAN - To test the performance of F2PY generated interfaces, use - ``-DF2PY_REPORT_ATEXIT``. Then a report of various timings is - printed out at the exit of Python. This feature may not work on - all platforms, currently only Linux platform is supported. +To test the performance of F2PY generated interfaces, use +``-DF2PY_REPORT_ATEXIT``. Then a report of various timings is printed out at the +exit of Python. This feature may not work on all platforms, and currently only +Linux is supported. - To see whether F2PY generated interface performs copies of array - arguments, use ``-DF2PY_REPORT_ON_ARRAY_COPY=<int>``. When the size - of an array argument is larger than ``<int>``, a message about - the coping is sent to ``stderr``. +To see whether F2PY generated interface performs copies of array arguments, use +``-DF2PY_REPORT_ON_ARRAY_COPY=<int>``. When the size of an array argument is +larger than ``<int>``, a message about the copying is sent to ``stderr``. Other options ^^^^^^^^^^^^^ -``-m <modulename>`` - Name of an extension module. Default is ``untitled``. - - .. warning:: Don't use this option if a signature file (\*.pyf) is used. -``--[no-]lower`` - Do [not] lower the cases in ``<fortran files>``. By default, - ``--lower`` is assumed with ``-h`` switch, and ``--no-lower`` - without the ``-h`` switch. -``-include<header>`` - Writes additional headers in the C wrapper, can be passed multiple times, - generates #include <header> each time. Note that this is meant to be passed in - single quotes and without spaces, for example ``'-include<stdbool.h>'`` -``--build-dir <dirname>`` - All F2PY generated files are created in ``<dirname>``. Default is - ``tempfile.mkdtemp()``. -``--quiet`` - Run quietly. -``--verbose`` - Run with extra verbosity. -``-v`` - Print the F2PY version and exit. - -Execute ``f2py`` without any options to get an up-to-date list of -available options. + ``-m <modulename>`` + Name of an extension module. Default is ``untitled``. + + .. warning:: Don't use this option if a signature file (``*.pyf``) is used. + + ``--[no-]lower`` + Do [not] lower the cases in ``<fortran files>``. By default, ``--lower`` is + assumed with ``-h`` switch, and ``--no-lower`` without the ``-h`` switch. + ``-include<header>`` + Writes additional headers in the C wrapper, can be passed multiple times, + generates #include <header> each time. Note that this is meant to be passed + in single quotes and without spaces, for example ``'-include<stdbool.h>'`` + ``--build-dir <dirname>`` + All F2PY generated files are created in ``<dirname>``. Default is + ``tempfile.mkdtemp()``. + ``--quiet`` + Run quietly. + ``--verbose`` + Run with extra verbosity. + ``-v`` + Print the F2PY version and exit. + +Execute ``f2py`` without any options to get an up-to-date list of available +options. Python module ``numpy.f2py`` ============================ -.. warning:: +The f2py program is written in Python and can be run from inside your code +to compile Fortran code at runtime, as follows: + +.. code-block:: python - The current Python interface to the ``f2py`` module is not mature and - may change in the future. + from numpy import f2py + with open("add.f") as sourcefile: + sourcecode = sourcefile.read() + f2py.compile(sourcecode, modulename='add') + import add + +The source string can be any valid Fortran code. If you want to save +the extension-module source code then a suitable file-name can be +provided by the ``source_fn`` keyword to the compile function. + +When using ``numpy.f2py`` as a module, the following functions can be invoked. + +.. warning:: + The current Python interface to the ``f2py`` module is not mature and may + change in the future. .. automodule:: numpy.f2py :members: +Automatic extension module generation +===================================== + +If you want to distribute your f2py extension module, then you only +need to include the .pyf file and the Fortran code. The distutils +extensions in NumPy allow you to define an extension module entirely +in terms of this interface file. A valid ``setup.py`` file allowing +distribution of the ``add.f`` module (as part of the package +``f2py_examples`` so that it would be loaded as ``f2py_examples.add``) is: + +.. code-block:: python + + def configuration(parent_package='', top_path=None) + from numpy.distutils.misc_util import Configuration + config = Configuration('f2py_examples',parent_package, top_path) + config.add_extension('add', sources=['add.pyf','add.f']) + return config + + if __name__ == '__main__': + from numpy.distutils.core import setup + setup(**configuration(top_path='').todict()) + +Installation of the new package is easy using:: + + pip install . + +assuming you have the proper permissions to write to the main site- +packages directory for the version of Python you are using. For the +resulting package to work, you need to create a file named ``__init__.py`` +(in the same directory as ``add.pyf``). Notice the extension module is +defined entirely in terms of the ``add.pyf`` and ``add.f`` files. The +conversion of the .pyf file to a .c file is handled by `numpy.distutils`.
\ No newline at end of file diff --git a/doc/source/glossary.rst b/doc/source/glossary.rst index aa2dc13df..bd75bf274 100644 --- a/doc/source/glossary.rst +++ b/doc/source/glossary.rst @@ -280,10 +280,36 @@ Glossary contiguous - An array is contiguous if - * it occupies an unbroken block of memory, and - * array elements with higher indexes occupy higher addresses (that - is, no :term:`stride` is negative). + + An array is contiguous if: + + - it occupies an unbroken block of memory, and + - array elements with higher indexes occupy higher addresses (that + is, no :term:`stride` is negative). + + There are two types of proper-contiguous NumPy arrays: + + - Fortran-contiguous arrays refer to data that is stored column-wise, + i.e. the indexing of data as stored in memory starts from the + lowest dimension; + - C-contiguous, or simply contiguous arrays, refer to data that is + stored row-wise, i.e. the indexing of data as stored in memory + starts from the highest dimension. + + For one-dimensional arrays these notions coincide. + + For example, a 2x2 array ``A`` is Fortran-contiguous if its elements are + stored in memory in the following order:: + + A[0,0] A[1,0] A[0,1] A[1,1] + + and C-contiguous if the order is as follows:: + + A[0,0] A[0,1] A[1,0] A[1,1] + + To test whether an array is C-contiguous, use the ``.flags.c_contiguous`` + attribute of NumPy arrays. To test for Fortran contiguity, use the + ``.flags.f_contiguous`` attribute. copy diff --git a/doc/source/user/c-info.python-as-glue.rst b/doc/source/user/c-info.python-as-glue.rst index 6d514f146..4db789856 100644 --- a/doc/source/user/c-info.python-as-glue.rst +++ b/doc/source/user/c-info.python-as-glue.rst @@ -116,303 +116,7 @@ signatures for the subroutines it encounters, or you can guide how the subroutine interfaces with Python by constructing an interface-definition-file (or modifying the f2py-produced one). -.. index:: - single: f2py - -Creating source for a basic extension module --------------------------------------------- - -Probably the easiest way to introduce f2py is to offer a simple -example. Here is one of the subroutines 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 - -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 - -You should be able to run this command assuming your search-path is -set-up properly. 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 Python just like any other extension module. - - -Creating a compiled extension module ------------------------------------- - -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 - -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:: - - >>> import add - >>> print(add.zadd.__doc__) - zadd(a,b,c,n) - - Wrapper for ``zadd``. - - Parameters - ---------- - a : input rank-1 array('D') with bounds (*) - b : input rank-1 array('D') with bounds (*) - c : input rank-1 array('D') with bounds (*) - n : input int - -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:: - - >>> 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:: - - f2py -h add.pyf -m add add.f - -This command leaves the file add.pyf in the current directory. The -section of this file corresponding to zadd is: - -.. code-block:: fortran - - 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 - -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. - -.. 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 - -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 -passed to the underlying code. The intent(hide) directive tells f2py -to not allow the user to specify the variable, ``n``, but instead to -get it from the size of ``a``. The depend( ``a`` ) directive is -necessary to tell f2py that the value of n depends on the input a (so -that it won't try to create the variable n until the variable a is -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 - -The new interface has docstring:: - - >>> import add - >>> print(add.zadd.__doc__) - c = zadd(a,b) - - Wrapper for ``zadd``. - - Parameters - ---------- - a : input rank-1 array('D') with bounds (n) - b : input rank-1 array('D') with bounds (n) - - Returns - ------- - c : rank-1 array('D') with bounds (n) - -Now, the function can be called in a much more robust way:: - - >>> add.zadd([1, 2, 3], [4, 5, 6]) - array([5.+0.j, 7.+0.j, 9.+0.j]) - -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. -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 - -Then, one can compile the extension module using:: - - 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 -contained ``A(N)`` instead of ``A(*)`` and so forth with ``B`` and ``C``, -then nearly the same interface can be obtained by placing the -``INTENT(OUT) :: C`` comment line in the source code. The only difference -is that ``N`` would be an optional input that would default to the length -of ``A``. - - -A filtering example -------------------- - -For comparison with the other methods to be discussed. Here is another -example of a function that filters a two-dimensional array of double -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 - -This code can be compiled and linked into an extension module named -filter using:: - - f2py -c -m filter filter.f - -This will produce an extension module named filter.so in the current -directory with a method named dfilter2d that returns a filtered -version of the input. - - -Calling f2py from Python ------------------------- - -The f2py program is written in Python and can be run from inside your code -to compile Fortran code at runtime, as follows: - -.. code-block:: python - - from numpy import f2py - with open("add.f") as sourcefile: - sourcecode = sourcefile.read() - f2py.compile(sourcecode, modulename='add') - import add - -The source string can be any valid Fortran code. If you want to save -the extension-module source code then a suitable file-name can be -provided by the ``source_fn`` keyword to the compile function. - - -Automatic extension module generation -------------------------------------- - -If you want to distribute your f2py extension module, then you only -need to include the .pyf file and the Fortran code. The distutils -extensions in NumPy allow you to define an extension module entirely -in terms of this interface file. A valid ``setup.py`` file allowing -distribution of the ``add.f`` module (as part of the package -``f2py_examples`` so that it would be loaded as ``f2py_examples.add``) is: - -.. code-block:: python - - def configuration(parent_package='', top_path=None) - from numpy.distutils.misc_util import Configuration - config = Configuration('f2py_examples',parent_package, top_path) - config.add_extension('add', sources=['add.pyf','add.f']) - return config - - if __name__ == '__main__': - from numpy.distutils.core import setup - setup(**configuration(top_path='').todict()) - -Installation of the new package is easy using:: - - pip install . - -assuming you have the proper permissions to write to the main site- -packages directory for the version of Python you are using. For the -resulting package to work, you need to create a file named ``__init__.py`` -(in the same directory as ``add.pyf``). Notice the extension module is -defined entirely in terms of the ``add.pyf`` and ``add.f`` files. The -conversion of the .pyf file to a .c file is handled by `numpy.disutils`. - - -Conclusion ----------- - -The interface definition file (.pyf) is how you can fine-tune the interface -between Python and Fortran. There is decent documentation for f2py at -:ref:`f2py`. There is also more information on using f2py (including how to use -it to wrap C codes) at the `"Interfacing With Other Languages" heading of the -SciPy Cookbook. -<https://scipy-cookbook.readthedocs.io/items/idx_interfacing_with_other_languages.html>`_ +See the :ref:`F2PY documentation <f2py>` for more information and examples. The f2py method of linking compiled code is currently the most sophisticated and integrated approach. It allows clean separation of diff --git a/numpy/f2py/__init__.py b/numpy/f2py/__init__.py index b1cb74fae..15c219ad4 100644 --- a/numpy/f2py/__init__.py +++ b/numpy/f2py/__init__.py @@ -47,11 +47,11 @@ def compile(source, source_fn : str, optional Name of the file where the fortran source is written. The default is to use a temporary file with the extension - provided by the `extension` parameter - extension : {'.f', '.f90'}, optional + provided by the ``extension`` parameter + extension : ``{'.f', '.f90'}``, optional Filename extension if `source_fn` is not provided. The extension tells which fortran standard is used. - The default is `.f`, which implies F77 standard. + The default is ``.f``, which implies F77 standard. .. versionadded:: 1.11.0 @@ -124,7 +124,7 @@ def compile(source, def get_include(): """ - Return the directory that contains the fortranobject.c and .h files. + Return the directory that contains the ``fortranobject.c`` and ``.h`` files. .. note:: @@ -151,15 +151,15 @@ def get_include(): building a Python extension using a ``.pyf`` signature file is a two-step process. For a module ``mymod``: - - Step 1: run ``python -m numpy.f2py mymod.pyf --quiet``. This - generates ``_mymodmodule.c`` and (if needed) - ``_fblas-f2pywrappers.f`` files next to ``mymod.pyf``. - - Step 2: build your Python extension module. This requires the - following source files: + * Step 1: run ``python -m numpy.f2py mymod.pyf --quiet``. This + generates ``_mymodmodule.c`` and (if needed) + ``_fblas-f2pywrappers.f`` files next to ``mymod.pyf``. + * Step 2: build your Python extension module. This requires the + following source files: - - ``_mymodmodule.c`` - - ``_mymod-f2pywrappers.f`` (if it was generated in step 1) - - ``fortranobject.c`` + * ``_mymodmodule.c`` + * ``_mymod-f2pywrappers.f`` (if it was generated in Step 1) + * ``fortranobject.c`` See Also -------- diff --git a/numpy/f2py/f2py2e.py b/numpy/f2py/f2py2e.py index bb5b32878..5bc9113af 100755 --- a/numpy/f2py/f2py2e.py +++ b/numpy/f2py/f2py2e.py @@ -411,14 +411,16 @@ def run_main(comline_list): where ``<args>=string.join(<list>,' ')``, but in Python. Unless ``-h`` is used, this function returns a dictionary containing information on generated modules and their dependencies on source - files. For example, the command ``f2py -m scalar scalar.f`` can be - executed from Python as follows + files. You cannot build extension modules with this function, that is, - using ``-c`` is not allowed. Use ``compile`` command instead + using ``-c`` is not allowed. Use the ``compile`` command instead. Examples -------- + The command ``f2py -m scalar scalar.f`` can be executed from Python as + follows. + .. literalinclude:: ../../source/f2py/code/results/run_main_session.dat :language: python diff --git a/tools/refguide_check.py b/tools/refguide_check.py index baa71e39a..619d6c644 100644 --- a/tools/refguide_check.py +++ b/tools/refguide_check.py @@ -131,6 +131,7 @@ RST_SKIPLIST = [ 'c-info.ufunc-tutorial.rst', 'c-info.python-as-glue.rst', 'f2py.getting-started.rst', + 'f2py-examples.rst', 'arrays.nditer.cython.rst', # See PR 17222, these should be fixed 'basics.dispatch.rst', |