I am currently developing a python package that uses cython
and numpy
and I want the package to be installable using the pip install
command from a clean python installation. All dependencies should be installed automatically. I am using setuptools
with the following setup.py
:
import setuptools
my_c_lib_ext = setuptools.Extension(
name="my_c_lib",
sources=["my_c_lib/some_file.pyx"]
)
setuptools.setup(
name="my_lib",
version="0.0.1",
author="Me",
author_email="[email protected]",
description="Some python library",
packages=["my_lib"],
ext_modules=[my_c_lib_ext],
setup_requires=["cython >= 0.29"],
install_requires=["numpy >= 1.15"],
classifiers=[
"Programming Language :: Python :: 3",
"Operating System :: OS Independent"
]
)
This has worked great so far. The pip install
command downloads cython
for the build and is able to build my package and install it together with numpy
.
Now I want to improve the performance of my cython
code, which leads to some changes in my setup.py
. I need to add include_dirs=[numpy.get_include()]
to either the call of setuptools.Extension(...)
or setuptools.setup(...)
which means that I also need to import numpy
. (See http://docs.cython.org/en/latest/src/tutorial/numpy.html and Make distutils look for numpy header files in the correct place for rationals.)
This is bad. Now the user cannot call pip install
from a clean environment, because import numpy
will fail. The user needs to pip install numpy
before installing my library. Even if I move "numpy >= 1.15"
from install_requires
to setup_requires
the installation fails, because the import numpy
is evaluated earlier.
Is there a way to evaluate the include_dirs
at a later point of the installation, for example, after the dependencies from setup_requires
or install_requires
have been resolved? I really like to have all dependencies resolved automatically and I dont want the user to type multiple pip install
commands.
The following snippet works, but it is not officially supported because it uses an undocumented (and private) method:
class NumpyExtension(setuptools.Extension):
# setuptools calls this function after installing dependencies
def _convert_pyx_sources_to_lang(self):
import numpy
self.include_dirs.append(numpy.get_include())
super()._convert_pyx_sources_to_lang()
my_c_lib_ext = NumpyExtension(
name="my_c_lib",
sources=["my_c_lib/some_file.pyx"]
)
The article How to Bootstrap numpy installation in setup.py proposes using a cmdclass
with custom build_ext
class. Unfortunately, this breaks the build of the cython
extension because cython
also customizes build_ext
.
cython
also customizesbuild_ext
. If I use the proposed solution, thecython
build fails withDon't know how to compile my_c_lib/some_file.pyx
, which means that the customizedbuild_ext
command ofcython
is not used anymore. – Theresaos.PathLike
instead ofobject
, becausecython
requires astr
,bytes
, orPathLike
object andstr
/bytes
do not work because they are immutable. Do you want to create an answer from your comment oder should I self-answer my question? – Theresabuild_ext
log options before requirements are installed, it will fail. On the other handCommand.finalize_options
is the right place to handle such things - for a proper solution one should figure out, how it can work with Cython. – Hustlerequires
element of the[build-system]
section of apyproject.toml
file. That file might also need to specify a "build backend". For instance:build-backend = "setuptools.build_meta"
. – Letendre