簡體   English   中英

如何在 setup.py 中引導 numpy 安裝

[英]How to Bootstrap numpy installation in setup.py

我有一個項目,它有一個 C 擴展,需要 numpy。 理想情況下,我希望下載我的項目的人能夠運行python setup.py install或使用一次調用pip The problem I have is that in my setup.py I need to import numpy to get the location of the headers, but I'd like numpy to be just a regular requirement in install_requires so that it will automatically be downloaded from the 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()但找不到任何關於它的用途的文檔。

這可能嗎?

以下至少適用於 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”的情況下會失敗,請參閱這個答案

請注意,使用setup_requires有一個微妙的缺點:numpy 不僅會在構建擴展之前編譯,而且在執行python setup.py --help時也會編譯,例如。 為避免這種情況,您可以檢查命令行選項,如https://github.com/scipy/scipy/blob/master/setup.py#L205 中建議的那樣,但另一方面,我認為這並不值得努力。

我在 [這篇文章][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'])

對我來說效果很好!

這是需要使用 numpy(對於 distutils 或 get_include)的包的基本問題。 我不知道有什么方法可以使用 pip 或輕松安裝來“引導”它。

但是,為您的模塊制作 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

關鍵是將導入numpy推遲到安裝后。 我從這個pybind11 示例中學到的一個技巧是在輔助類的__str__方法中導入numpy (下面的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'])

為了讓 pip 工作,你可以像 Scipy 一樣做: https : //github.com/scipy/scipy/blob/master/setup.py#L205

即,需要將egg_info命令傳遞給標准 setuptools/distutils,但其他命令可以使用numpy.distutils

也許更實用的解決方案是只需要預先安裝import numpy在函數范圍內import numpy @coldfix 解決方案有效,但編譯 numpy 需要永遠。 首先將其 pip 安裝為wheels 包要快得多,尤其是現在由於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(),
)

@coldfix 的解決方案不適用於 Cython 擴展,如果 Cython 沒有預安裝在目標機器上,因為它失敗並出現錯誤

錯誤:未知文件類型“.pyx”(來自“xxxxx/yyyyyy.pyx”)

失敗的原因是setuptools.command.build_ext的過早導入,因為在導入時, 它會嘗試使用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 一無所知。

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 中討論

現在(自 2018 年以來)應該通過在pyproject.toml添加 numpy 作為構建系統依賴項來解決這個問題,以便pip install在運行setup.py之前使numpy可用。

pyproject.toml文件還應指定您正在使用 Setuptools 來構建項目。 它應該是這樣的:

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

有關更多詳細信息,請參閱 Setuptools 的構建系統支持文檔

這不包括除install之外的setup.py許多其他用途,但由於這些用途主要是為您(以及您項目的其他開發人員)准備的,因此提示安裝numpy的錯誤消息可能會起作用。

您可以簡單地將 numpy 添加到您的 pyproject.toml 文件中。 這對我有用。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM