requirements.txt vs setup.py


111

Ho iniziato a lavorare con Python. Ho aggiunto requirements.txte setup.pyal mio progetto. Tuttavia, sono ancora confuso sullo scopo di entrambi i file. Ho letto che setup.pyè progettato per cose ridistribuibili e che requirements.txtè progettato per cose non ridistribuibili. Ma non sono sicuro che sia esatto.

In che modo questi due file devono essere veramente utilizzati?


1
Hai cercato sul Web utilizzando il titolo esatto? Questo articolo (il primo successo quando ho cercato) è il migliore che ho letto sull'argomento.
Chris,

2
Questo articolo potrebbe essere utile: caremad.io/posts/2013/07/setup-vs-requirement (spiacente, troppo pigro per estrarre gli elementi essenziali in una risposta corretta). Un'altra cosa è che alcuni strumenti (ad esempio il test) possono avere i loro pregiudizi verso l'uno o l'altro, ma non lasciarti disturbare se hai appena iniziato a lavorare su Python.
drdaeman

Risposte:


83

requirements.txt

Questo ti aiuta a configurare il tuo ambiente di sviluppo. Programmi come pippossono essere utilizzati per installare tutti i pacchetti elencati nel file in un colpo solo. Dopodiché puoi iniziare a sviluppare il tuo script python. Particolarmente utile se si prevede che altri contribuiscano allo sviluppo o utilizzino ambienti virtuali. Ecco come lo usi:

pip install -r requirements.txt

setup.py

Questo ti permette di creare pacchetti che puoi ridistribuire. Questo script ha lo scopo di installare il pacchetto sul sistema dell'utente finale, non di preparare l'ambiente di sviluppo come pip install -r requirements.txtfa. Vedi questa risposta per maggiori dettagli su setup.py.

Le dipendenze del tuo progetto sono elencate in entrambi i file.


2
In quali casi ne avrei solo uno? In quale avrei entrambi?
Martin Thoma

27
Ehm ... scrivi solo per divertimento sulla tua macchina locale: Nessuno dei due. Lo script è sviluppato su più macchine / vitualenvs ma non ridistribuito: requirements.txt. Lo script è sviluppato solo sulla tua macchina ma dovrebbe essere ridistribuito: setup.py. Lo script verrà ridistribuito e sviluppato in più ambienti: Entrambi.
Andreas

Potresti aggiungere questo alla risposta?
Martin Thoma

58

La risposta breve è che requirements.txtserve solo per elencare i requisiti del pacchetto. setup.pyd'altra parte è più simile a uno script di installazione. Se non prevedi di installare il codice python, in genere ti servirà solo requirements.txt.

Il file setup.pydescrive, oltre alle dipendenze del pacchetto, l'insieme di file e moduli che dovrebbero essere impacchettati (o compilati, nel caso di moduli nativi (cioè, scritti in C)) e metadati da aggiungere agli elenchi dei pacchetti python ( es. nome del pacchetto, versione del pacchetto, descrizione del pacchetto, autore, ...).

Poiché entrambi i file elencano le dipendenze, ciò può portare a un po 'di duplicazione. Leggi sotto per i dettagli.

requirements.txt


Questo file elenca i requisiti del pacchetto Python. È un file di testo semplice (facoltativamente con commenti) che elenca le dipendenze del pacchetto del tuo progetto Python (uno per riga). Essa non descrive il modo in cui è installato il pacchetto python. In genere si utilizza il file dei requisiti con pip install -r requirements.txt.

Il nome del file di testo è arbitrario, ma spesso lo è requirements.txtper convenzione. Quando esplori i repository di codice sorgente di altri pacchetti Python, potresti incappare in altri nomi, come dev-dependencies.txto dependencies-dev.txt. Quelli hanno lo stesso scopo dependencies.txtma generalmente elencano dipendenze aggiuntive di interesse per gli sviluppatori di un particolare pacchetto, vale a dire per testare il codice sorgente (es. Pytest, pylint, ecc.) Prima del rilascio. Gli utenti del pacchetto in genere non avrebbero bisogno dell'intero set di dipendenze dello sviluppatore per eseguire il pacchetto.

Se requirements-X.txtsono presenti più varianti, di solito una elencherà le dipendenze di runtime e l'altra il tempo di compilazione o le dipendenze di test. Alcuni progetti mettono in cascata anche il loro file dei requisiti, cioè quando un file dei requisiti include un altro file ( esempio ). Ciò può ridurre la ripetizione.

setup.py


Questo è uno script python che utilizza il setuptoolsmodulo per definire un pacchetto python (nome, file inclusi, metadati del pacchetto e installazione). Sarà, come requirements.txt, anche l'elenco runtime dipendenze del pacchetto. Setuptools è il modo di fatto per compilare e installare pacchetti python, ma ha i suoi difetti, che nel tempo hanno portato allo sviluppo di nuovi "meta-package manager", come pip. Esempi di difetti di setuptools sono la sua incapacità di installare più versioni dello stesso pacchetto e la mancanza di un comando di disinstallazione.

Quando un utente python fa pip install ./pkgdir_my_module(o pip install my-module), pip verrà eseguito setup.pynella directory (o modulo) data. Allo stesso modo, qualsiasi modulo che ha un setup.pypuò essere pipinstallato, ad esempio eseguendolo pip install .dalla stessa cartella.

Ho davvero bisogno di entrambi?


La risposta breve è no, ma è bello averli entrambi. Raggiungono scopi diversi, ma possono essere utilizzati entrambi per elencare le dipendenze.

C'è un trucco che potresti prendere in considerazione per evitare di duplicare il tuo elenco di dipendenze tra requirements.txte setup.py. Se hai già scritto un file completamente funzionante setup.pyper il tuo pacchetto e le tue dipendenze sono per lo più esterne, potresti considerare di avere un semplice requirements.txtcon solo quanto segue:

 # requirements.txt
 #
 # installs dependencies from ./setup.py, and the package itself,
 # in editable mode
 -e .

 # (the -e above is optional). you could also just install the package
 # normally with just the line below (after uncommenting)
 # .

È un'opzione -especiale pip installche installa il pacchetto specificato in modalità modificabile . Quando pip -r requirements.txtviene eseguito su questo file, pip installerà le tue dipendenze tramite l'elenco in ./setup.py. L'opzione modificabile inserirà un collegamento simbolico nella directory di installazione (invece di un uovo o una copia archiviata). Consente agli sviluppatori di modificare il codice in posizione dal repository senza reinstallarlo.

Puoi anche trarre vantaggio da ciò che viene chiamato "setuptools extra" quando hai entrambi i file nel repository dei pacchetti. Puoi definire pacchetti opzionali in setup.py in una categoria personalizzata e installare quei pacchetti solo da quella categoria con pip:

# setup.py
from setuptools import setup
setup(
   name="FOO"
   ...
   extras_require = {
       'dev': ['pylint'],
       'build': ['requests']
   }
   ...
)

e poi, nel file dei requisiti:

# install packages in the [build] category, from setup.py
# (path/to/mypkg is the directory where setup.py is)
-e path/to/mypkg[build]

Ciò manterrebbe tutti i tuoi elenchi di dipendenze all'interno di setup.py.

Nota : normalmente eseguiresti pip e setup.py da una sandbox, come quelle create con il programma virtualenv. Ciò eviterà di installare pacchetti Python fuori dal contesto dell'ambiente di sviluppo del progetto.


7
e puoi anche avere solo .senza -edentro requirements.txt. Questo metodo delega solo tutti i requisiti a setup.pye non è necessario forzare nessuno nella modalità modificabile. Gli utenti possono ancora farlo pip install -e .se lo desiderano.
stason

1
Trucco interessante con "-e". in requirements.txt, ma questo non vanifica lo scopo di requirements.txt di essere le specifiche di sistema esatte? Perché anche in quel caso averne uno?
Ben Ogorek,

Puoi avere i requisiti di sistema esatti all'interno di setup.py. Avere "." in requirements.txt fa utilizzare setup.py nella cartella corrente. L'utilizzo -e .utilizza anche setup.py per trovare le dipendenze, ma collega la cartella corrente (al suo posto, con un collegamento simbolico) nella cartella di installazione di pip, invece di prenderne una copia: useresti -egeneralmente solo se stai sviluppando il pacchetto. Con -e, le modifiche ai file del pacchetto python (* .py) avranno effetto immediatamente nel tuo ambiente pip, invece di dover forzare la reinstallazione del pacchetto dopo ogni modifica.
init_js

@init_js è la "cartella corrente" relativa al file dei requisiti o CWD da cui viene chiamato pip? Cioè, se lo fai, cd foo && pip install -r ./bar/requirements.txtcercherà setup.py in foo/baro foo? In quest'ultimo caso, c'è un modo per ottenere il primo?
Dan M.

pip -r REQnon si preoccupa della directory in cui si trova REQ. È possibile alimentarlo da una FIFO anche se si desidera: pip install -r <(echo "mylib1"; echo "mylib2";). Dov'è la <(CMD)sostituzione del comando bash, non il reindirizzamento stdin.
init_js

12

Per completezza, ecco come la vedo in 3 4 diverse angolazioni.

  1. I loro scopi di progettazione sono diversi

Questa è la descrizione precisa citata dalla documentazione ufficiale (enfasi mia):

Mentre install_requires (in setup.py) definisce le dipendenze per un singolo progetto , i file dei requisiti sono spesso usati per definire i requisiti per un ambiente Python completo .

Mentre i requisiti di install_requires sono minimi, i file dei requisiti spesso contengono un elenco esaustivo delle versioni bloccate allo scopo di ottenere installazioni ripetibili di un ambiente completo.

Ma potrebbe non essere ancora facile da capire, quindi nella sezione successiva, ci sono 2 esempi concreti per dimostrare come i 2 approcci dovrebbero essere usati, in modo diverso.

  1. I loro usi effettivi sono quindi (supposti per essere) diversi

    • Se il tuo progetto foosta per essere rilasciato come libreria standalone (il che significa, altri probabilmente lo farebbero import foo), allora tu (e i tuoi utenti a valle) vorresti avere una dichiarazione di dipendenza flessibile, in modo che la tua libreria non lo farebbe (e non deve ) essere "esigente" su quale dovrebbe essere la versione esatta delle VOSTRE dipendenze. Quindi, in genere, il tuo setup.py conterrebbe righe come questa:

      install_requires=[
          'A>=1,<2',
          'B>=2'
      ]
    • Se vuoi solo "documentare" o "bloccare" in qualche modo il tuo ambiente corrente ESATTO per la tua applicazione bar, il che significa che tu oi tuoi utenti vorreste usare la vostra applicazione così barcom'è, cioè in esecuzione python bar.py, potreste voler congelare il vostro ambiente in modo che si comporterebbe sempre allo stesso modo. In tal caso, il file dei requisiti sarà simile a questo:

      A==1.2.3
      B==2.3.4
      # It could even contain some dependencies NOT strickly required by your library
      pylint==3.4.5
  2. In realtà, quale uso?

    • Se stai sviluppando un'applicazione barche verrà utilizzata da python bar.py, anche se è "solo uno script per divertimento", ti consigliamo comunque di usare requirements.txt perché, chissà, la prossima settimana (che è Natale) riceverai un nuovo computer come regalo, quindi dovrai configurare di nuovo il tuo ambiente esatto.

    • Se stai sviluppando una libreria fooche verrà utilizzata da import foo, devi preparare un file setup.py. Periodo. Ma puoi comunque scegliere di fornire anche un requirements.txt allo stesso tempo, che può:

      (a) essere nello A==1.2.3stile (come spiegato in # 2 sopra);

      (b) o contenere semplicemente un singolo magico .

      .

      che equivarrebbe all'incirca a "installare i requisiti in base a setup.py" senza duplicazione. Personalmente ritengo che questo ultimo approccio offuschi la linea, aggiunga confusione e NON apporti valore, ma è comunque un trucco derivato da un approccio menzionato dal manutentore di packaging Python Donald nel suo post sul blog .

  3. Limiti inferiori diversi.

    Anche dopo aver seguito i 3 criteri di cui sopra e aver deciso correttamente che la tua libreria hybrid-engineuserebbe a setup.pyper dichiarare la sua dipendenza engine>=1.2.0, e la tua applicazione di esempio reliable-caruserebbe requirements.txtper dichiarare la sua dipendenza engine>=1.2.3, anche se l'ultima versione di engineè già alla 1.4.0. Come vedi, la tua scelta per il loro numero di limite inferiore è ancora leggermente diversa. Ed ecco perché.

    • hybrid-enginedipende dal engine>=1.2.0fatto che, ipoteticamente parlando, la capacità di "combustione interna" necessaria è stata introdotta per la prima volta engine 1.2.0, e quella capacità è la necessità di hybrid-engine, indipendentemente dal fatto che ci possano essere alcuni bug (minori) all'interno di tale versione e siano stati corretti nelle versioni successive 1.2.1 , 1.2.2 e 1.2.3.

    • reliable-cardipende dal engine>=1.2.3fatto che quella è la prima versione SENZA problemi noti, finora. Sicuramente ci sono nuove capacità nelle versioni successive, diciamo, "motore elettrico" introdotto engine 1.3.0e "reattore nucleare" introdotto engine 1.4.0, ma non sono necessarie per il progetto reliable-car.


"la tua libreria non sarebbe (e non deve) essere 'schizzinosa' su quale dovrebbe essere la versione esatta delle tue dipendenze." Potresti approfondire un po 'questo punto? Immagino che il tuo codice sia in genere testato solo con versioni specifiche di dipendenze e questo approccio può essere un po 'pericoloso. Presumo che una libreria dovrebbe funzionare con una gamma di versioni perché non vuoi installare troppe versioni di dipendenze? Per risparmiare spazio su disco?
Taro Kiritani

@TaroKiritani In realtà ho elencato 2 diversi scenari fianco a fianco, il caso della biblioteca e il caso della domanda. Forse non hai mai lavorato in una biblioteca prima? Come libreria, ci si aspetta che venga consumata dai pacchetti a valle. Quindi, se sei esigente nel bloccare la TUA dipendenza A==1.2.3, e poi se il pacchetto a valle della tua libreria dipende da A==1.2.4, ora non ci sarà un modo per soddisfare entrambi. La soluzione per ridurre al minimo questo conflitto è che la tua libreria definisca un intervallo che sai potrebbe funzionare. Supponendo che molte librerie a monte seguano già semver.org , A>=1,<2funzionerebbe.
RayLuo

Non mi ero reso conto che solo una versione di un pacchetto può essere installata in un unico ambiente. stackoverflow.com/a/6572017/5686692 Grazie per i chiarimenti.
Taro Kiritani

1
@TaroKiritani, sì, altrimenti come sarebbe il vostro know applicazione quale versione di foonon import foodare? Quelle risposte hacky accettate in quel link che hai fornito sono un perfetto esempio del perché il manutentore del pacchetto "non dovrebbe e non deve essere pignolo". :-) Ora posso avere il tuo voto positivo?
RayLuo

1
Potrei anche commentare quel nuovo pensiero, ma poi questa sezione dei commenti sta già andando fuori tema e difficile da seguire per i nuovi arrivati. Ti suggerirei di porre una nuova domanda "Usiamo tox o qualcosa del genere per garantire che la mia libreria
funzioni
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.