How to Bootstrap numpy installation in setup.py

前端 未结 7 1108
陌清茗
陌清茗 2020-12-02 12:12

I have a project which has a C extension which requires numpy. Ideally, I\'d like whoever downloads my project to just be able to run python setup.py install or

7条回答
  •  悲哀的现实
    2020-12-02 13:04

    @coldfix's solution doesn't work for Cython-extensions, if Cython isn't pre-installed on the target-machine, as it fails with the error

    error: unknown file type '.pyx' (from 'xxxxx/yyyyyy.pyx')

    The reason for the failure is the premature import of setuptools.command.build_ext, because when imported, it tries to use Cython's build_ext-functionality:

    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
    

    And normally setuptools is successful, because the import happens after setup_requirements are fulfilled. However by importing it already in setup.py, only fall back solution can be used, which doesn't know any about Cython.

    One possibility to bootstrap Cython alongside with numpy, would be to postpone the import of setuptools.command.build_ext with help of an indirection/proxy:

    # 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},
        ...
    )
    

    There are other possibilities, discussed for example in this SO-question.

提交回复
热议问题