Is there a way to have the equivalent of the Python try statement in Cython for the cimport?
Something like that:
try:
cimport something
except ImportError:
pass
I would need this to write a Cython extension that can be compiled with or without mpi4py. This is very standard in compiled languages where the mpi commands can be put between #ifdef and #endif preprocessor directives. How can we obtain the same result in Cython?
I tried this but it does not work:
try:
from mpi4py import MPI
from mpi4py cimport MPI
from mpi4py.mpi_c cimport *
except ImportError:
rank = 0
nb_proc = 1
# solve a incompatibility between openmpi and mpi4py versions
cdef extern from 'mpi-compat.h': pass
does_it_work = 'Not yet'
Actually it works well if mpi4py is correctly installed but if
import mpi4py
raises an ImportError, the Cython file does not
compile and I get the error:
Error compiling Cython file:
------------------------------------------------------------
...
try:
from mpi4py import MPI
from mpi4py cimport MPI
^
------------------------------------------------------------
mod.pyx:4:4: 'mpi4py.pxd' not found
The file setup.py
:
from setuptools import setup, Extension
from Cython.Distutils import build_ext
import os
here = os.path.abspath(os.path.dirname(__file__))
include_dirs = [here]
try:
import mpi4py
except ImportError:
pass
else:
INCLUDE_MPI = '/usr/lib/openmpi/include'
include_dirs.extend([
INCLUDE_MPI,
mpi4py.get_include()])
name = 'mod'
ext = Extension(
name,
include_dirs=include_dirs,
sources=['mod.pyx'])
setup(name=name,
cmdclass={"build_ext": build_ext},
ext_modules=[ext])
Using a try-catch block in this way is something you won't be able to do. The extension module you are making must be statically compiled and linked against the things it uses
cimport
to load at the C-level. A try-catch block is something that will be executed when the module is imported, not when it is compiled.On the other hand, in theory, you should be able to get the effect you're looking for using Cython's support for conditional compilation. In your
setup.py
file you can check to see if the needed modules are defined and then define environment variables to be passed to the Cython compiler that, in turn, depend on whether or not the needed modules are present.There's an example of how to do this in one of Cython's tests. There they pass a dictionary containing the desired environment variables to the constructor for Cython's
Extension
class as the keyword argumentpyrex_compile_time_env
, which has been renamed tocython_compile_time_env
, and forCython.Build.Dependencies.cythonize
is calledcompile_time_env
).Thank you for your very useful answer @IanH. I include an example to show what it gives.
The file
setup.py
:And the file
mod.pyx
, with a little bit of realmpi
commands:Build with
python setup.py build_ext --inplace
and test withpython -c "import mod"
andmpirun -np 4 python -c "import mod"
. Ifmpi4py
is not installed, one can still build the module and use it in sequential.