41

我有一个项目,它有一个需要 numpy 的 C 扩展。理想情况下,我希望下载我的项目的人能够运行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()但找不到任何关于它的用途的文档。

这可能吗?

4

8 回答 8

30

以下至少适用于 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”它会失败,见这个答案

请注意, usingsetup_requires有一个微妙的缺点:例如,numpy 不仅会在构建扩展之前编译,而且还会在执行时编译python setup.py --help。为避免这种情况,您可以检查命令行选项,如https://github.com/scipy/scipy/blob/master/setup.py#L205中建议的那样,但另一方面,我真的不认为这是值得的努力。

于 2014-02-07T07:24:20.100 回答
5

我在 [this post][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'])

对我来说效果很好!

于 2020-03-18T13:35:39.657 回答
4

这是需要使用 numpy(对于 distutils 或 get_include)的包的一个基本问题。我不知道使用 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

于 2013-11-12T07:55:07.450 回答
4

关键是将导入推迟numpy到安装后。我从这个pybind11 示例中学到的一个技巧是导入辅助类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'])
于 2020-07-04T03:09:37.280 回答
3

要让 pip 工作,你可以像 Scipy 一样做:https ://github.com/scipy/scipy/blob/master/setup.py#L205

即,该egg_info命令需要传递给标准的 setuptools/distutils,但其他命令可以使用numpy.distutils.

于 2013-11-13T13:03:55.087 回答
2

也许更实际的解决方案是只需要预先安装 numpy 并import numpy在函数范围内。@coldfix 解决方案有效,但编译 numpy 需要很长时间。首先 pip 将其安装为 wheel 包要快得多,尤其是现在我们已经为大多数系统提供了轮子,这要归功于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(),
)
于 2017-01-10T18:28:28.537 回答
1

@coldfix 的解决方案不适用于 Cython 扩展,如果 Cython 没有预先安装在目标机器上,因为它失败并出现错误

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

失败的原因是过早导入setuptools.command.build_ext,因为在导入时,它会尝试使用Cython 的 -functionality 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 一无所知。

Cython与 numpy 一起引导的一种可能性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中讨论过。

于 2019-01-11T20:02:44.670 回答
1

现在(自 2018 年以来)应该通过在 中添加 numpy 作为构建系统依赖项来解决此问题pyproject.toml,以便在运行之前pip install使其numpy可用setup.py

pyproject.toml文件还应指定您正在使用 Setuptools 构建项目。它应该看起来像这样:

[build-system]
requires = ["setuptools", "wheel", "numpy"]
build-backend = "setuptools.build_meta"

有关详细信息,请参阅 Setuptools 的构建系统支持文档

这不包括setup.py除 之外的许多其他用途install,但因为这些用途主要是为您(和您项目的其他开发人员)提供的,所以一条错误消息说安装numpy可能有效。

于 2021-06-18T15:46:43.250 回答