2016-05-26 57 views
15

Sto creando un file setup.py per un progetto con alcuni moduli di estensione Cython.setup_requires con Cython?

ho già ottenuto questo lavoro:

from setuptools import setup, Extension 
from Cython.Build import cythonize 

setup(
    name=..., 
    ..., 
    ext_modules=cythonize([ ... ]), 
) 

Questo installa bene. Tuttavia, questo presuppone che Cython sia installato. Cosa succede se non è installato? Capisco che questo è ciò che il parametro setup_requires è per:

from setuptools import setup, Extension 
from Cython.Build import cythonize 

setup(
    name=..., 
    ..., 
    setup_requires=['Cython'], 
    ..., 
    ext_modules=cythonize([ ... ]), 
) 

Tuttavia, se Cython non è già installato, questo sarà ovviamente venga meno

$ python setup.py install 
Traceback (most recent call last): 
    File "setup.py", line 2, in <module> 
    from Cython.Build import cythonize 
ImportError: No module named Cython.Build 

Qual è il modo corretto di fare questo? Ho bisogno di importare in qualche modo Cython solo dopo l'esecuzione del passo setup_requires, ma ho bisogno di Cython per specificare i valori ext_modules.

risposta

4

È necessario disporre il from Cython.Build import cythonize in un try-except e nel except, definire cythonize come una funzione fittizia. In questo modo lo script può essere caricato senza fallire con uno ImportError.

Successivamente, quando viene gestito l'argomento setup_requires, verrà installato Cython e lo script di installazione verrà rieseguito. Dal momento che a quel punto Cython è installato, sarete in grado di importare con successo cythonize

try: 
    from Cython.Build import cythonize 
except ImportError: 
    def cythonize(*args, **kwargs): 
     from Cython.Build import cythonize 
     return cythonize(*args, **kwargs) 

EDIT

Come notato nei commenti, dopo le offerte di setuptools con dipendenze mancanti, non si ri-carico Cython. Non avevo pensato prima, ma si potrebbe anche tentare un approccio late-binding per spegnendo cythonize

+0

Questo è un po 'hacky, e tuttavia, piuttosto fresco! Non sapevo che lo script è stato rieseguito, questo ha molto senso. – Claudiu

+0

Hmm, quindi se installo senza aver prima installato Cython, l'installazione funziona (installa Cython) ma i moduli di estensione non sono installati (non è possibile importarli dagli script). Qualche idea su cosa potrebbe accadere? – Claudiu

+0

Curioso. Ah bene, non deve essere veramente ri-eseguito. Di solito non ho bisogno di 'Cython' per l'installazione, solo lo sviluppo. Invece di creare istanze 'Extension' con' cythonize', basta crearle direttamente sui file .c generati da 'Cython'. Leggi questo esempio https://github.com/mobiusklein/brainpy/blob/master/setup.py – mobiusklein

17

A partire dal rilascio di 18.0setuptools (rilasciata il 2015/06/23) è possibile specificare Cython in setup_requires e superare fonti *.pyx moduli per regolare setuptools.Extension:

from setuptools import setup, Extension 


setup(
    # ... 
    setup_requires=[ 
     # Setuptools 18.0 properly handles Cython extensions. 
     'setuptools>=18.0', 
     'cython', 
    ], 
    ext_modules=[ 
     Extension(
      'mylib', 
      sources=['src/mylib.pyx'], 
     ), 
    ], 
) 
+0

Ottima risposta, grazie! Preferiresti questo approccio accanto all'approccio in cui i file Cython sono compilati in anticipo e i file .c sono usati in setup.py, il che significa che Cython non è necessario per costruire il pacchetto? – Martinsos

+1

@Martinsos supponendo che Cython sia installabile su tutte le piattaforme di destinazione usando setuptools (dovrebbe, ma ci sono sempre eccezioni), l'utilizzo di un approccio specifico rimuove il problema di generarli.c file durante la distribuzione della libreria senza perdere nulla, quindi sì, mi sento di raccomandare questo approccio. L'unica eccezione se questo processo non funziona, ad es. se si targetizza il sistema con setuptools molto vecchi, cosa che non vorrei di default. – rutsky