Python 如何在setup.py中引导numpy安装

Python 如何在setup.py中引导numpy安装,python,numpy,setuptools,bootstrapping,Python,Numpy,Setuptools,Bootstrapping,我有一个项目,它有一个C扩展,需要numpy。理想情况下,我希望下载我的项目的人能够运行python setup.py安装,或者只需调用一次pip。我遇到的问题是,在我的setup.py中,我需要导入numpy以获取头的位置,但我希望numpy只是install\u requires中的常规要求,以便它将自动从Python包索引下载 以下是我尝试做的一个示例: from setuptools import setup, Extension import numpy as np ext_modu

我有一个项目,它有一个C扩展,需要numpy。理想情况下,我希望下载我的项目的人能够运行
python setup.py安装
,或者只需调用一次
pip
。我遇到的问题是,在我的
setup.py
中,我需要导入numpy以获取头的位置,但我希望numpy只是
install\u requires
中的常规要求,以便它将自动从Python包索引下载

以下是我尝试做的一个示例:

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'])
显然,在安装numpy之前,我无法在顶部导入numpy。我看到一个
setup\u需要将
参数传递给
setup()
,但找不到关于它的用途的任何文档


这可能吗?

这是需要使用numpy(用于distutils或get\u include)的包的一个基本问题。我不知道如何使用pip或简易安装“引导”it

但是,为您的模块制作一个conda包并提供依赖项列表很容易,这样某人就可以只做一个conda install pkg名称,它将下载并安装所需的所有内容

Conda在Anaconda或Miniconda中可用(python+just Conda)

请参阅本网站:
或此幻灯片了解更多信息:

要使pip正常工作,您可以执行与Scipy类似的操作:


也就是说,
egg_info
命令需要传递给标准的setuptools/distutils,但是其他命令可以使用
numpy.distutils
以下命令至少适用于numpy1.8和python{2.6,2.7,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”的原因,请参阅


注意,使用
setup\u requires
有一个微妙的缺点:numpy不仅在构建扩展之前被编译,而且在执行
python setup.py--help
时也会被编译。为了避免这种情况,您可以检查命令行选项,如中所建议的,但另一方面,我并不认为这是值得的。

也许更实际的解决方案是只需要预先安装numpy,然后在函数范围内导入numpy@coldfix解决方案可以工作,但编译numpy需要花费很长时间。pip首先将其作为一个wheels包安装要快得多,特别是现在,由于像这样的努力,大多数系统都有了轮子

不适用于Cython扩展,如果Cython未预装在目标计算机上,因为它会因错误而失败

错误:未知文件类型“.pyx”(来自“xxxxx/yyyyy.pyx”)

失败的原因是过早导入
setuptools.command.build\u ext
,因为导入时,Cython的
build\u 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\u要求之后进行的。但是,通过在
setup.py
中导入它,只能使用回退解决方案,而Cython对此一无所知

与numpy一起引导
Cython
的一种可能性是在间接/代理的帮助下推迟导入
setuptools.command.build\u 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},
    ...
)

还有其他可能性,例如在本文中讨论。

我在[这篇文章][1]中找到了一个非常简单的解决方案:

或者你可以坚持。在这里,您可以在实际安装之前使用setuptools.dist安装cython和numpy:


很适合我

关键是推迟导入
numpy
,直到安装完成。我从中学到的一个技巧是在助手类的
\uuuu str\uuuu
方法中导入
numpy
get\u numpy\u include

从设置工具导入设置,扩展
类get\u numpy\u include(对象):
“”“将numpy.get_include()延迟到安装numpy之后。”“”
定义(自我):
进口numpy
返回numpy.get_include()
ext_modules=[Extension('vme',['vme.c'],extra_link_args=['-lvme'],
include_dirs=[get_numpy_include()])]
安装程序(name='vme',
version='0.1',
description='VME上与CAEN数字化仪通信的模块。',
ext_模块=ext_模块,
安装_需要=['numpy'、'pyzmq'、'Sphinx'])

我想知道如何做到这一点,同时使用
Cython.distutils.build\u ext
在上面的示例中,它可能会以同样的方式替换
setuptools.command
为Cython.distutils
。如果不是:我使用的是
cythonize()
,而不是建议使用的
Cython.distutils.build\u ext
。请参阅和@coldfix是,但我需要在运行setup.py之前安装Cython。Bootstraping setup.py似乎很痛苦:哦,这是最简单的答案,对我来说也很有效!它也适用于readthedocs网站,在这种情况下,需要自行安装软件包。
# 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},
    ...
)
from setuptools import dist
dist.Distribution().fetch_build_eggs(['Cython>=0.15.1', 'numpy>=1.10'])