我有一个C扩展项目需要numpy。理想情况下,我希望下载我的项目的人能够运行python setup.py install
或使用一个pip
来电。我遇到的问题是,在setup.py
我需要导入numpy以获取标题的位置,但我希望numpy只是install_requires
中的常规要求,因此它会自动成为从Python Package Index下载。
以下是我正在尝试做的一个示例:
from setuptools import setup, Extension
import numpy as np
ext_modules = [Extension('vme', ['vme.c'], extra_link_args=['-lvme'],
include_dirs=[np.get_include()])]
setup(name='vme',
version='0.1',
description='Module for communicating over VME with CAEN digitizers.',
ext_modules=ext_modules,
install_requires=['numpy','pyzmq', 'Sphinx'])
显然,在安装之前我不能import numpy
在顶部。我已经看到一个setup_requires
参数传递给setup()
,但找不到任何关于它的用途的文档。
这可能吗?
答案 0 :(得分:28)
以下至少使用numpy1.8和python {2.6,2.7,3.3}:
from setuptools import setup
from setuptools.command.build_ext import build_ext as _build_ext
class build_ext(_build_ext):
def finalize_options(self):
_build_ext.finalize_options(self)
# Prevent numpy from thinking it is still in its setup process:
__builtins__.__NUMPY_SETUP__ = False
import numpy
self.include_dirs.append(numpy.get_include())
setup(
...
cmdclass={'build_ext':build_ext},
setup_requires=['numpy'],
...
)
要获得一个小的解释,请参阅{hack >>,看看为什么它失败了,请参阅this answer。
请注意,使用setup_requires
有一个微妙的缺点:numpy不仅会在构建扩展之前进行编译,而且还会在执行python setup.py --help
时进行编译。为避免这种情况,您可以检查命令行选项,如https://github.com/scipy/scipy/blob/master/setup.py#L205中建议的那样,但另一方面,我认为这不值得付出努力。
答案 1 :(得分:4)
这是需要使用numpy(对于distutils或get_include)的包的基本问题。我不知道怎么去" boot-strap"它使用pip或easy-install。
但是,很容易为您的模块制作一个conda包并提供依赖项列表,以便有人可以只执行conda install pkg-name,它将下载并安装所需的所有内容。
Conda可在Anaconda或Miniconda(python + just conda)中使用。
查看此网站:http://docs.continuum.io/conda/index.html 或者这张幻灯片获取更多信息:https://speakerdeck.com/teoliphant/packaging-and-deployment-with-conda
答案 2 :(得分:2)
要让pip工作,你可以像Scipy一样做:https://github.com/scipy/scipy/blob/master/setup.py#L205
即,egg_info
命令需要传递给标准的setuptools / distutils,但其他命令可以使用numpy.distutils
。
答案 3 :(得分:2)
或许更实际的解决方案是只需要预先安装numpy并在函数范围内安装import numpy
。 @coldfix解决方案有效,但编译numpy需要永远。作为车轮包装首先安装它的速度要快得多,特别是现在由于像manylinux这样的努力我们为大多数系统安装了轮子。
from __future__ import print_function
import sys
import textwrap
import pkg_resources
from setuptools import setup, Extension
def is_installed(requirement):
try:
pkg_resources.require(requirement)
except pkg_resources.ResolutionError:
return False
else:
return True
if not is_installed('numpy>=1.11.0'):
print(textwrap.dedent("""
Error: numpy needs to be installed first. You can install it via:
$ pip install numpy
"""), file=sys.stderr)
exit(1)
def ext_modules():
import numpy as np
some_extention = Extension(..., include_dirs=[np.get_include()])
return [some_extention]
setup(
ext_modules=ext_modules(),
)
答案 4 :(得分:1)
我在[这篇文章] [1]中找到了一个非常简单的解决方案:
或者您可以坚持使用https://github.com/pypa/pip/issues/5761。在这里,您需要在实际安装之前使用setuptools.dist安装cython和numpy:
from setuptools import dist
dist.Distribution().fetch_build_eggs(['Cython>=0.15.1', 'numpy>=1.10'])
对我来说很好!
答案 5 :(得分:1)
关键是要推迟导入numpy
,直到安装完成。我从此pybind11 example中学到的一个技巧是将numpy
导入辅助类的__str__
方法(下面的get_numpy_include
)。
from setuptools import setup, Extension
class get_numpy_include(object):
"""Defer numpy.get_include() until after numpy is installed."""
def __str__(self):
import numpy
return numpy.get_include()
ext_modules = [Extension('vme', ['vme.c'], extra_link_args=['-lvme'],
include_dirs=[get_numpy_include()])]
setup(name='vme',
version='0.1',
description='Module for communicating over VME with CAEN digitizers.',
ext_modules=ext_modules,
install_requires=['numpy','pyzmq', 'Sphinx'])
答案 6 :(得分:0)
@coldfix's solution对于Cython扩展名不起作用,如果未在目标计算机上预安装Cython,则会失败并出现错误
错误:未知文件类型“ .pyx”(来自“ xxxxx / yyyyyy.pyx”)
失败的原因是setuptools.command.build_ext
的过早导入,因为在导入时,it tries to use Cython的build_ext
功能:
try:
# Attempt to use Cython for building extensions, if available
from Cython.Distutils.build_ext import build_ext as _build_ext
# Additionally, assert that the compiler module will load
# also. Ref #1229.
__import__('Cython.Compiler.Main')
except ImportError:
_build_ext = _du_build_ext
通常,setuptools成功,因为导入是在setup_requirements
完成之后进行的。但是,通过将其导入setup.py
中,只能使用回退解决方案,而对于Cython则一无所知。
与numpy一起引导Cython
的一种可能性是在间接/代理的帮助下推迟setuptools.command.build_ext
的导入:
# factory function
def my_build_ext(pars):
# import delayed:
from setuptools.command.build_ext import build_ext as _build_ext#
# include_dirs adjusted:
class build_ext(_build_ext):
def finalize_options(self):
_build_ext.finalize_options(self)
# Prevent numpy from thinking it is still in its setup process:
__builtins__.__NUMPY_SETUP__ = False
import numpy
self.include_dirs.append(numpy.get_include())
#object returned:
return build_ext(pars)
...
setup(
...
cmdclass={'build_ext' : my_build_ext},
...
)
还有其他可能性,例如在本SO-question中进行了讨论。
答案 7 :(得分:0)
现在(自 2018 年以来)应该通过在 pyproject.toml
中添加 numpy 作为 buildsystem 依赖项 来解决这个问题,以便 pip install
使 numpy
之前可用它运行 setup.py
。
pyproject.toml
文件还应指定您正在使用 Setuptools 来构建项目。它应该看起来像这样:
[build-system]
requires = ["setuptools", "wheel", "numpy"]
build-backend = "setuptools.build_meta"
有关详细信息,请参阅 Setuptools 的 Build System Support docs。
这不包括除 setup.py
之外的 install
的许多其他用途,但由于这些用途主要用于您(以及您项目的其他开发人员),因此会出现一条错误消息,提示安装 {{ 1}} 可能会起作用。