【问题标题】:How to Bootstrap numpy installation in setup.py如何在 setup.py 中引导 numpy 安装
【发布时间】:2013-11-24 01:18:43
【问题描述】:

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

这可能吗?

【问题讨论】:

    标签: python numpy setuptools bootstrapping


    【解决方案1】:

    这是需要使用 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

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

      • 链接应始终使用 sha(您可以从 GitHub 中的“复制永久链接”访问)以防代码更改和行号更改。好像这里就发生过这样的事。从提到的代码中,我猜这是github.com/scipy/scipy/blob/…
      【解决方案3】:

      以下内容至少适用于 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 中建议的那样,但另一方面,我认为这不值得。

      【讨论】:

      • 我想知道如何做到这一点并同时使用Cython.distutils.build_ext...
      • 在上面的示例中,将setuptools.command 替换为Cython.distutils 可能会以同样的方式工作。如果不是:我使用的是cythonize(),而不是推荐的Cython.distutils.build_ext。见herehere
      • @coldfix 是的,但是我需要在运行 setup.py 之前安装 Cython。引导 setup.py 似乎很痛苦:P
      【解决方案4】:

      也许更实用的解决方案是只需要预先安装 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(),
      )
      

      【讨论】:

        【解决方案5】:

        @coldfix's solution 不适用于 Cython 扩展,如果 Cython 未预安装在目标计算机上,因为它会失败并出现错误

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

        失败的原因是setuptools.command.build_ext的过早导入,因为导入时it tries to use 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 一无所知。

        与 numpy 一起引导 Cython 的一种可能性是在间接/代理的帮助下推迟 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 中讨论过。

        【讨论】:

          【解决方案6】:

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

          很适合我!

          【讨论】:

          • 哇,这是最简单的答案,它也对我有用!它也适用于 readthedocs 网站,在这种情况下,需要自己安装包。
          【解决方案7】:

          关键是推迟导入numpy,直到它安装完成。我从这个pybind11 example 中学到的一个技巧是在帮助器类的__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'])
          

          【讨论】:

            【解决方案8】:

            现在(从 2018 年开始)应该通过在 pyproject.toml 中添加 numpy 作为 buildsystem 依赖项 来解决这个问题,以便 pip install 在运行 setup.py 之前使 numpy 可用。

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

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

            有关详细信息,请参阅 Setuptools 的Build System Support docs

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2014-11-03
              • 1970-01-01
              • 2017-05-03
              • 2016-07-17
              • 1970-01-01
              • 2019-03-15
              • 2012-07-28
              • 1970-01-01
              相关资源
              最近更新 更多