Cómo arrancar la instalación numpy en setup.py

Tengo un proyecto que tiene una extensión C que requiere numpy. Idealmente, me gustaría que quienquiera que descargue mi proyecto pueda ejecutar python setup.py install o usar una llamada a pip . El problema que tengo es que en mi setup.py necesito importar numpy para obtener la ubicación de los encabezados, pero me gustaría que numpy sea un requisito regular en install_requires para que se descargue automáticamente del Índice de Paquetes de Python .

Aquí hay una muestra de lo que estoy tratando de hacer:

 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']) 

Obviamente, no puedo import numpy en la parte superior antes de que se instale. He visto un argumento setup_requires pasado a setup() pero no puedo encontrar ninguna documentación sobre para qué sirve.

es posible?

Lo siguiente funciona al menos con numpy1.8 y 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'], ... ) 

Para una pequeña explicación, vea por qué falla sin el “truco”, vea esta respuesta .

Tenga en cuenta que el uso de setup_requires tiene un inconveniente sutil: numpy no solo se comstackrá antes de construir extensiones, sino también cuando se hace python setup.py --help , por ejemplo. Para evitar esto, puede buscar opciones de línea de comando, como se sugiere en https://github.com/scipy/scipy/blob/master/setup.py#L205 , pero por otro lado, realmente no creo que valga la pena el esfuerzo.

Este es un problema fundamental con los paquetes que necesitan usar numpy (para distutils o get_include). No conozco una forma de “ajustarlo” con pip o instalarlo fácilmente.

Sin embargo, es fácil hacer un paquete de Conda para su módulo y proporcionar la lista de dependencias para que alguien pueda simplemente hacer un Conda instalar pkg-name que descargará e instalará todo lo necesario.

Conda está disponible en Anaconda o en Miniconda (python + just conda).

Consulte este sitio web: http://docs.continuum.io/conda/index.html o este paquete de diapositivas para obtener más información: https://speakerdeck.com/teoliphant/packaging-and-deployment-with-conda

Para que pip funcione, puedes hacer lo mismo que Scipy: https://github.com/scipy/scipy/blob/master/setup.py#L205

Es decir, el comando egg_info debe pasarse a setuptools / distutils estándar, pero otros comandos pueden usar numpy.distutils .

Tal vez una solución más práctica es simplemente requerir que se instale numpy de antemano e import numpy dentro del scope de una función. La solución de @coldfix funciona, pero la comstackción de números tarda una eternidad. Mucho más rápido de instalarlo primero como un paquete de ruedas, especialmente ahora que tenemos ruedas para la mayoría de los sistemas gracias a esfuerzos como 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(), ) 

La solución de @ coldfix no funciona con las extensiones de Cython, si Cython no está preinstalado en la máquina de destino, ya que falla con el error

error: tipo de archivo desconocido ‘.pyx’ (de ‘xxxxx / yyyyyy.pyx’)

El motivo del error es la importación prematura de setuptools.command.build_ext , porque cuando se importa, intenta usar la build_ext build_ext de Cython:

 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 

Y normalmente setuptools es exitoso, porque la importación ocurre después de que se cumplen los setup_requirements . Sin embargo, al importarlo ya en setup.py , solo se puede utilizar la solución de retroceso, que no sabe nada acerca de Cython.

Una posibilidad para arrancar Cython junto con numpy, sería posponer la importación de setuptools.command.build_ext con la ayuda de un 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}, ... ) 

Hay otras posibilidades, discutidas por ejemplo en esta pregunta de SO .