Python support

Adiak provides Python bindings based on pybind11 for the metadata/annotation APIs (init, value, fini) and a set of convenience collectors (e.g., collect_all(), walltime()). To build Adiak with Python support, enable the ENABLE_PYTHON_BINDINGS option in the CMake configuration:

$ cmake -DENABLE_PYTHON_BINDINGS=ON ..

If you want to initialize Adiak with an MPI communicator from Python, also enable (or auto-detect) MPI at configure time (mpi4py is only needed at runtime if you actually pass a communicator):

$ cmake -DENABLE_PYTHON_BINDINGS=ON -DENABLE_MPI=ON ..

Using the Python module

The Python module requires pybind11 and an installation of Python that both supports pybind11 and provides development headers (e.g., Python.h) and libraries (e.g., libpython3.8.so).

The Adiak Python module is installed in either lib/pythonX.Y/site-packages/ and/or lib64/pythonX.Y/site-packages in the Adiak installation directory. In these paths, X.Y corresponds to the major and minor version numbers of the Python installation used. Additionally, lib/ and lib64/ will be used in accordance with the configuration of the Python installed.

To use the Adiak Python module, simply add the directories above to PYTHONPATH or sys.path. Note that the module will be automatically added to PYTHONPATH when loading the Adiak package with Spack if the python variant is enabled. The module can then be imported with import pyadiak.

Example: basic usage (serial)

from datetime import datetime
from pathlib import Path

from pyadiak.annotations import init, value, fini, collect_all, walltime, cputime, systime
from pyadiak.types import Version, Path as APath, CatStr, Category

def main():
    init(None)  # serial mode

    value("str", "s")
    value("compiler", Version("gcc@8.1.0"))
    value("mydouble", 3.14)
    value("problemsize", 14000, category=Category.Tuning)
    value("countdown", 9876543210)

    grid = [4.5, 1.18, 0.24, 8.92]
    value("gridvalues", grid)

    names = {"bob", "jim", "greg"}
    value("allnames", names)

    # Flatten nested structures (or use JsonStr)
    names_arr = ["first", "second", "third"]
    xs = [1.0, 2.0, 3.0]
    ys = [1.0, 4.0, 9.0]
    value("points.names", names_arr)
    value("points.x", xs)
    value("points.y", ys)

    # Time & paths are auto-wrapped; shown explicitly here for clarity
    value("birthday", datetime.fromtimestamp(286551000))   # Timepoint
    value("nullpath", APath(Path("/dev/null")))            # Path
    value("githash", CatStr("a0c93767478f23602c2eb317f641b091c52cf374"))

    collect_all()
    walltime()
    cputime()
    systime()

    fini()

if __name__ == "__main__":
    main()

Example: MPI usage (optional)

If built with -DENABLE_MPI=ON and mpi4py is available:

from mpi4py import MPI
from pyadiak.annotations import init, value, fini

def main():
    comm = MPI.COMM_WORLD
    init(comm)           # initialize with communicator
    value("rank", comm.Get_rank())
    fini()

if __name__ == "__main__":
    main()