python - Come avviare l'installazione numpy in setup.py




setuptools bootstrapping (4)

Ho un progetto che ha un'estensione C che richiede numpy. Idealmente, mi piacerebbe che chiunque scaricasse il mio progetto fosse in grado di eseguire python setup.py install o utilizzare una chiamata a pip . Il problema che ho è che nel mio setup.py ho bisogno di importare numpy per ottenere la posizione delle intestazioni, ma mi piacerebbe che numpy sia solo un requisito normale in install_requires modo che venga scaricato automaticamente dall'Indice dei Pacchetti Python .

Ecco un esempio di ciò che sto cercando di fare:

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

Ovviamente, non posso import numpy in alto prima che sia installato. Ho visto un argomento setup_requires passato a setup() ma non riesco a trovare alcuna documentazione su cosa sia.

È possibile?


Forse una soluzione più pratica è semplicemente richiedere l'installazione di import numpy e import numpy all'interno import numpy una funzione. La soluzione @coldfix funziona ma la compilazione di numpy richiede per sempre. Molto più veloce per installarlo come pacchetto di ruote, specialmente ora che abbiamo le ruote per la maggior parte dei sistemi grazie a sforzi come 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(),
)


Questo è un problema fondamentale con i pacchetti che devono usare numpy (per distutils o get_include). Non conosco un modo per "boot-strap" usando pip o easy-install.

Tuttavia, è facile creare un pacchetto conda per il modulo e fornire l'elenco delle dipendenze in modo che qualcuno possa semplicemente eseguire un'installazione di pkg-name che eseguirà il download e l'installazione di tutto il necessario.

Conda è disponibile in Anaconda o in Miniconda (pitone + solo conda).

Vedi questo sito: http://docs.continuum.io/conda/index.html o questo slide-deck per maggiori informazioni: https://speakerdeck.com/teoliphant/packaging-and-deployment-with-conda


La soluzione di @ coldfix non funziona con le estensioni Cython, se Cython non è preinstallato sulla macchina di destinazione, poiché fallisce con l'errore

errore: tipo di file sconosciuto '.pyx' (da 'xxxxx / yyyyyy.pyx')

Il motivo dell'errore è l'importazione prematura di setuptools.command.build_ext , perché quando importato tenta di utilizzare la funzione build_ext- build_ext di 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

E normalmente setuptools ha successo, perché l'importazione avviene dopo che setup_requirements sono soddisfatti. Tuttavia importandolo già in setup.py , si può usare solo la soluzione di ripiego, che non ne sa nulla su Cython.

Una possibilità di Cython insieme a numpy, sarebbe posticipare l'importazione di setuptools.command.build_ext con l'aiuto di un riferimento indiretto / 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},
    ...
)

Ci sono altre possibilità, discusse per esempio in questa SO-question .





bootstrapping