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:

char
signed_char
short
int
long_long
float
double
long_double
complex_float
complex_double
complex_long_double
string

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