# Advanced F2PY use cases

## Adding user-defined functions to F2PY generated modules

User-defined Python C/API functions can be defined inside signature files using `usercode` and `pymethoddef` statements (they must be used inside the `python module` block). For example, the following signature file `spam.pyf`

    !    -*- f90 -*-
    python module spam
        usercode '''
      static char doc_spam_system[] = "Execute a shell command.";
      static PyObject *spam_system(PyObject *self, PyObject *args)
      {
        char *command;
        int sts;

        if (!PyArg_ParseTuple(args, "s", &command))
            return NULL;
        sts = system(command);
        return Py_BuildValue("i", sts);
      }
        '''
        pymethoddef '''
        {"system",  spam_system, METH_VARARGS, doc_spam_system},
        '''
    end python module spam

wraps the C library function `system()`:

    f2py -c spam.pyf

In Python this can then be used as:

    >>> import spam
    >>> status = spam.system('whoami')
    pearu
    >>> status = spam.system('blah')
    sh: line 1: blah: command not found

## Adding user-defined variables

The following example illustrates how to add user-defined variables to a F2PY generated extension module by modifying the dictionary of a F2PY generated module. Consider the following signature file (compiled with `f2py -c var.pyf`):

    !    -*- f90 -*-
    python module var
      usercode '''
        int BAR = 5;
      '''
      interface
        usercode '''
          PyDict_SetItemString(d,"BAR",PyInt_FromLong(BAR));
        '''
      end interface
    end python module

Notice that the second `usercode` statement must be defined inside an `interface` block and the module dictionary is available through the variable `d` (see `varmodule.c` generated by `f2py var.pyf` for additional details).

Usage in Python:

    >>> import var
    >>> var.BAR
    5

## Dealing with KIND specifiers

Currently, F2PY can handle only `<type spec>(kind=<kindselector>)` declarations where `<kindselector>` is a numeric integer (e.g. 1, 2, 4,…), but not a function call `KIND(..)` or any other expression. F2PY needs to know what would be the corresponding C type and a general solution for that would be too complicated to implement.

However, F2PY provides a hook to overcome this difficulty, namely, users can define their own <Fortran type> to <C type> maps. For example, if Fortran 90 code contains:

    REAL(kind=KIND(0.0D0)) ...

then create a mapping file containing a Python dictionary:

    {'real': {'KIND(0.0D0)': 'double'}}

for instance.

Use the `--f2cmap` command-line option to pass the file name to F2PY. By default, F2PY assumes file name is `.f2py_f2cmap` in the current working directory.

More generally, the f2cmap file must contain a dictionary with items:

    <Fortran typespec> : {<selector_expr>:<C type>}

that defines mapping between Fortran type:

    <Fortran typespec>([kind=]<selector_expr>)

and the corresponding <C type>. The <C type> can be one of the following:

    double
    float
    long_double
    char
    signed_char
    unsigned_char
    short
    unsigned_short
    int
    long
    long_long
    unsigned
    complex_float
    complex_double
    complex_long_double
    string

For more information, see the F2Py source code `numpy/f2py/capi_maps.py`.

previous

Using via `scikit-build`

next

F2PY test suite