如何在www.example.com中引导numpy安装setup.py

ni65a41a  于 2023-03-02  发布在  其他
关注(0)|答案(9)|浏览(149)

我有一个C扩展的项目,需要numpy。理想情况下,我希望下载我的项目的人能够运行python setup.py install或使用一个pip调用。我的问题是,在我的setup.py中,我需要导入numpy来获得头文件的位置。但是我希望numpy只是install_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'])

显然,在安装之前我不能在顶部安装import numpy,我看到过一个setup_requires参数传递给setup(),但是找不到任何关于它的文档。
这可能吗?

xv8emn3q

xv8emn3q1#

下面的代码至少可以在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'],
    ...
)

对于一个小的解释,看看为什么它没有“黑客”失败,见this answer
注意,使用setup_requires有一个微妙的缺点:numpy不仅在构建扩展之前会被编译,而且在执行python setup.py --help时也会被编译,为了避免这种情况,你可以检查命令行选项,就像https://github.com/scipy/scipy/blob/master/setup.py#L205中建议的那样,但是另一方面,我真的不认为这是值得的。

r8uurelv

r8uurelv2#

我找到了一个非常简单的解决办法:
或者你可以坚持使用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'])

对我来说很有效!

dtcbnfnu

dtcbnfnu3#

这是需要使用numpy的软件包的一个基本问题(对于distutils或get_include),我不知道有什么方法可以使用pip或easy-install来“引导”它。
然而,为你的模块制作一个conda包并提供依赖列表是很容易的,这样人们就可以执行一个conda install pkg-name来下载和安装所需的一切。
Conda有Anaconda和Miniconda两种版本(python +只是conda)。
查看此网站:http://docs.continuum.io/conda/index.html或此幻灯片组了解更多信息:https://speakerdeck.com/teoliphant/packaging-and-deployment-with-conda

368yc8dk

368yc8dk4#

关键是将numpy的导入推迟到安装之后,我从这个pybind11 example学到的一个技巧是在一个helper类的__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'])
ev7lccsx

ev7lccsx5#

要使pip工作,可以执行与Scipy类似的操作:https://github.com/scipy/scipy/blob/master/setup.py#L205
也就是说,egg_info命令需要传递给标准的setuptools/distutils,但其他命令可以使用numpy.distutils

dfddblmv

dfddblmv6#

也许一个更实际的解决方案是只需要预先安装numpy,并在函数作用域中安装import numpy。@coldfix解决方案可以工作,但编译numpy要花很长时间。首先以wheels包的形式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(),
)
nukf8bse

nukf8bse7#

现在(2018年左右),这个问题应该可以通过在pyproject.toml中添加numpy作为 buildsystem dependency 来解决,这样pip install就可以在运行setup.py之前使numpy可用。
pyproject.toml文件还应该指定您正在使用Setuptools来构建项目。

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

有关详细信息,请参见Setuptools的Build System Support docs
除了install之外,这里没有介绍setup.py的其他用途,但是这些用途主要是为您(以及您项目的其他开发人员)准备的,所以一条错误消息说要安装numpy可能会起作用。

x6492ojm

x6492ojm8#

如果Cython没有预先安装在目标机器上,则@coldfix的解决方案不适用于Cython扩展,因为它会失败并显示以下错误
错误:未知文件类型'.pyx'(来自'xxxxx/yyyyy. 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中讨论。

cbeh67ev

cbeh67ev9#

你可以简单地将numpy添加到你的pyproject.toml文件中。

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

相关问题