gpt4 book ai didi

python-3.x - 在没有预安装 numpy 的情况下将 numpy.get_include() 参数添加到 setuptools

转载 作者:行者123 更新时间:2023-12-04 07:31:04 26 4
gpt4 key购买 nike

我目前正在开发一个使用 cython 的 python 包和 numpy我希望可以使用 pip install 安装该软件包来自干净的 python 安装的命令。所有依赖项都应该自动安装。我正在使用 setuptools与以下 setup.py :

import setuptools

my_c_lib_ext = setuptools.Extension(
name="my_c_lib",
sources=["my_c_lib/some_file.pyx"]
)

setuptools.setup(
name="my_lib",
version="0.0.1",
author="Me",
author_email="me@myself.com",
description="Some python library",
packages=["my_lib"],
ext_modules=[my_c_lib_ext],
setup_requires=["cython >= 0.29"],
install_requires=["numpy >= 1.15"],
classifiers=[
"Programming Language :: Python :: 3",
"Operating System :: OS Independent"
]
)

到目前为止,这非常有效。 pip install命令下载 cython用于构建,并且能够构建我的包并将其与 numpy 一起安装.

现在我想提高我的 cython 的性能代码,这导致我的 setup.py 发生了一些变化.我需要添加 include_dirs=[numpy.get_include()]调用 setuptools.Extension(...)setuptools.setup(...)这意味着我还需要 import numpy . (有理数见 http://docs.cython.org/en/latest/src/tutorial/numpy.htmlMake distutils look for numpy header files in the correct place。)

这是不好的。现在用户无法调用 pip install来自干净的环境,因为 import numpy将失败。用户需要 pip install numpy在安装我的图书馆之前。就算搬家 "numpy >= 1.15"来自 install_requiressetup_requires安装失败,因为 import numpy被较早地评估。

有没有办法评估 include_dirs在安装的后期,例如,在来自 setup_requires 的依赖项之后或 install_requires已经解决了吗?我真的很喜欢自动解决所有依赖关系,我不希望用户输入多个 pip install命令。

以下代码段有效,但未得到官方支持,因为它使用了未记录(和私有(private))的方法:
class NumpyExtension(setuptools.Extension):
# setuptools calls this function after installing dependencies
def _convert_pyx_sources_to_lang(self):
import numpy
self.include_dirs.append(numpy.get_include())
super()._convert_pyx_sources_to_lang()

my_c_lib_ext = NumpyExtension(
name="my_c_lib",
sources=["my_c_lib/some_file.pyx"]
)

文章 How to Bootstrap numpy installation in setup.py建议使用 cmdclass与自定义 build_ext类(class)。不幸的是,这破坏了 cython 的构建。扩展,因为 cython还定制 build_ext .

最佳答案

第一个问题,numpy 是什么时候?需要吗?在设置期间(即调用 build_ext -funcionality 时)和安装时使用模块时需要它。这意味着 numpy应该在 setup_requires install_requires .
有以下替代方法可以解决设置问题:

  • 使用 PEP 517/518 (更直接的 IMO)
  • 使用 setup_requires -setup 的参数并推迟 numpy 的导入直到满足安装程序的要求(在 setup.py 的执行开始时不是这种情况)

  • PEP 517/518-解决方案:
    放在 setup.py 旁边一个 pyproject.toml -file ,内容如下:
    [build-system]
    requires = ["setuptools", "wheel", "Cython>=0.29", "numpy >= 1.15"]
    它定义了构建所需的包,然后使用 pip install . 安装在带有 setup.py 的文件夹中.这种方法的一个缺点是 python setup.py install不再有效,因为它是 pip显示为 pyproject.toml .但是,我会尽可能使用这种方法。

    推迟进口
    这种方法更复杂,也有点老套,但在没有 pip 的情况下也可以使用。 .
    首先,让我们看一下迄今为止的不成功尝试:
    pybind11 技巧
    @chrisb 的“pybind11”-trick,可以找到 here : 在间接的帮助下,可以延迟对 import numpy 的调用。直到 numpy 在设置阶段出现,即:
    class get_numpy_include(object):

    def __str__(self):
    import numpy
    return numpy.get_include()
    ...
    my_c_lib_ext = setuptools.Extension(
    ...
    include_dirs=[get_numpy_include()]
    )
    聪明的!问题:它不适用于 Cython 编译器:在某个地方,Cython 传递了 get_numpy_include -反对 os.path.join(...,...)它检查参数是否真的是一个字符串,显然不是。
    这可以通过继承 str 来解决。 ,但从长远来看,上面显示了这种方法的危险——它不使用设计的机制,很脆弱,将来很容易失败。
    经典 build_ext -solution
    如下所示:
    ...
    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())

    setupttools.setup(
    ...
    cmdclass={'build_ext':build_ext},
    ...
    )
    然而,此解决方案也不适用于 cython 扩展,因为 pyx -文件不被识别。
    真正的问题是, pyx 是怎么做到的? -文件首先得到认可?答案是 this partsetuptools.command.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如果可能,尝试使用 Cython 的 build_ext,因为模块的导入延迟到 build_ext被调用,它发现 Cython 存在。
    setuptools.command.build_ext 时情况有所不同在 setup.py 的开头导入- Cython 尚不存在,并且使用了没有 cython 功能的回退。
    混合 pybind11 技巧和经典解决方案
    所以让我们添加一个间接,所以我们不必导入 setuptools.command.build_ext直接在 setup.py开头:
    ....
    # 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)
    ...
    setuptools.setup(
    ...
    cmdclass={'build_ext' : my_build_ext},
    ...
    )

    关于python-3.x - 在没有预安装 numpy 的情况下将 numpy.get_include() 参数添加到 setuptools,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54117786/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com