Perché la CLI di flask è consigliata su Flask.run?


13

In Flask 0.11 è flaskstata introdotta una CLI. Sia i documenti che il log delle modifiche indicano che questo è raccomandato.

Documenti del server di sviluppo :

A partire da Flask 0.11 ci sono molti modi integrati per eseguire un server di sviluppo. La migliore è l' utility della riga di comando del pallone , ma è anche possibile continuare a utilizzare il Flask.run()metodo.

Riga di comando

Lo script della riga di comando della beuta (Command Line Interface) è fortemente raccomandato per lo sviluppo perché fornisce un'esperienza di ricarica superiore a causa del modo in cui carica l'applicazione. L'utilizzo di base è così:

$ export FLASK_APP=my_application
$ export FLASK_DEBUG=1
$ flask run

Log delle modifiche :

  • Aggiunto flaske il flask.climodulo per avviare il server di debug locale tramite il sistema CLI click. Questo è raccomandato rispetto al vecchio flask.run()metodo in quanto funziona più velocemente e più affidabile a causa di un design diverso e sostituisce Flask-Script.

Finora non ho notato questa "esperienza di ricarica superiore". Non riesco a vedere il punto di utilizzare l'interfaccia della riga di comando su uno script personalizzato.

Se si utilizza Flask.run, scriverei semplicemente un file Python:

#!/usr/bin/env python3
from my_app import app


if __name__ == '__main__':
    app.run(debug=True)

Se si utilizza l'interfaccia della riga di comando, è necessario specificare le variabili di ambiente. Nei documenti CLI è indicato che questo può essere integrato nello activatescript di virtualenvwrapper. Personalmente ritengo che questo sia parte dell'applicazione e penso che dovrebbe essere sotto il controllo della versione. Purtroppo, è necessario uno script di shell:

#!/usr/bin/env bash
export FLASK_APP=my_app:app
export FLASK_DEBUG=1

flask run

Naturalmente questo sarà accompagnato da uno script bat aggiuntivo non appena gli utenti Windows inizieranno a collaborare.

Inoltre, la prima opzione consente l'installazione scritta in Python prima di avviare l'app effettiva.

Questo permette ad esempio

  • per analizzare gli argomenti della riga di comando in Python
  • per configurare la registrazione prima di eseguire l'app

Sembrano promuovere che è possibile aggiungere comandi personalizzati. Non riesco a capire perché sia ​​meglio che scrivere semplici script Python, opzionalmente esposti attraverso punti di ingresso.

Esempio di output della registrazione quando si utilizza un logger configurato utilizzando lo script di esecuzione Python:

$ ./run.py 
   DEBUG 21:51:22 main.py:95) Configured logging
    INFO 21:51:22 _internal.py:87)  * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
    INFO 21:51:22 _internal.py:87)  * Restarting with inotify reloader
   DEBUG 21:51:22 main.py:95) Configured logging
 WARNING 21:51:22 _internal.py:87)  * Debugger is active!
    INFO 21:51:22 _internal.py:87)  * Debugger pin code: 263-225-431
   DEBUG 21:51:25 inotify_buffer.py:61) in-event <InotifyEvent: src_path=b'my_app/main.py', wd=272, mask=IN_MODIFY, cookie=0, name=b'main.py'>
   DEBUG 21:51:25 inotify_buffer.py:61) in-event <InotifyEvent: src_path=b'my_app/main.py', wd=272, mask=IN_MODIFY, cookie=0, name=b'main.py'>
    INFO 21:51:25 _internal.py:87)  * Detected change in 'my_app/main.py', reloading
    INFO 21:51:26 _internal.py:87)  * Restarting with inotify reloader
   DEBUG 21:51:26 main.py:95) Configured logging
 WARNING 21:51:26 _internal.py:87)  * Debugger is active!
    INFO 21:51:26 _internal.py:87)  * Debugger pin code: 263-225-431

Esempio di output della registrazione quando si utilizza un logger configurato utilizzando l'interfaccia della riga di comando :, notare che il logger di root non può essere configurato abbastanza presto nel processo.

$ ./run.sh 
 * Serving Flask app "appsemble.api.main:app"
 * Forcing debug mode on
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with inotify reloader
   DEBUG 21:51:33 main.py:95) Configured logging
 * Debugger is active!
 * Debugger pin code: 187-758-498
   DEBUG 21:51:34 main.py:95) Configured logging
   DEBUG 21:51:37 inotify_buffer.py:61) in-event <InotifyEvent: src_path=b'my_app/main.py', wd=272, mask=IN_MODIFY, cookie=0, name=b'main.py'>
   DEBUG 21:51:37 inotify_buffer.py:61) in-event <InotifyEvent: src_path=b'my_app/main.py', wd=272, mask=IN_MODIFY, cookie=0, name=b'main.py'>
 * Detected change in 'my_app/main.py', reloading
    INFO 21:51:37 _internal.py:87)  * Detected change in 'my_app/main.py', reloading
 * Restarting with inotify reloader
    INFO 21:51:38 _internal.py:87)  * Restarting with inotify reloader
 * Debugger is active!
 * Debugger pin code: 187-758-498
   DEBUG 21:51:38 main.py:95) Configured logging

La mia vera domanda è semplicemente:

Perché la CLI di pallone è consigliata Flask.run?

Risposte:


11

Nei documenti del server di sviluppo, affermano che ci sono problemi con la chiamata a run () e il caricamento automatico del codice:

Questo funziona bene per il caso comune ma non funziona bene per lo sviluppo, motivo per cui da Flask 0.11 in poi si consiglia il metodo di pallone. La ragione di ciò è che a causa del funzionamento del meccanismo di ricarica ci sono alcuni bizzarri effetti collaterali (come eseguire due volte un certo codice, a volte schiantarsi senza messaggio o morire quando si verifica una sintassi o un errore di importazione).

Sostengono che la CLI non soffre di questo problema.

Il primo commit che sembra toccare questo problema è questo: https://github.com/pallets/flask/commit/3bdb90f06b9d3167320180d4a5055dcd949bf72f

E lì Armin Ronacher scrisse:

Non è consigliabile utilizzare questa funzione per lo sviluppo con ricaricamento automatico poiché non è supportato. Invece dovresti usare il supporto flaskdello script da riga di comando runserver.

Come menzionato da Aaron Hall, sembra che l'uso di run () potrebbe essere problematico a causa del fatto che tutti gli oggetti che sono istanze di classi definite nei moduli che vengono sostituiti non verranno reintegrati e ogni volta che un modulo viene ricaricato, il i moduli che importa non vengono ricaricati.

I dettagli al riguardo sono disponibili per Python 3 all'indirizzo: https://docs.python.org/3/library/importlib.html?highlight=importlib#module-importlib

Afferma:

Come con tutti gli altri oggetti in Python, i vecchi oggetti vengono recuperati solo dopo che i loro conteggi di riferimento scendono a zero.

Altri riferimenti ai vecchi oggetti (come nomi esterni al modulo) non sono rimbalzati per fare riferimento ai nuovi oggetti e devono essere aggiornati in ogni spazio dei nomi dove si verificano se lo si desidera.

Quando un modulo viene ricaricato, il suo dizionario (contenente le variabili globali del modulo) viene mantenuto. Le ridefinizioni dei nomi sovrascriveranno le vecchie definizioni, quindi questo non è generalmente un problema. Se la nuova versione di un modulo non definisce un nome definito dalla versione precedente, la definizione precedente rimane.

Quindi, creando un nuovo processo e uccidendo quello vecchio, si eliminano naturalmente tutti i riferimenti obsoleti.

Inoltre, la CLI di Flask utilizza il modulo 'click', rendendo molto semplice l'aggiunta di comandi personalizzati, ma soprattutto, oltre a correggere il bug di ricarica, la CLI offre un modo standardizzato per eseguire applicazioni e aggiungere comandi personalizzati. Sembra un'ottima cosa, perché rende la familiarità con Flask più trasferibile tra diversi team e applicazioni, piuttosto che avere più modi per fare la stessa cosa.

Sembra un modo genuino per rendere Flask più conforme allo Zen di Python:

Dovrebbe esserci uno - e preferibilmente solo un - modo obsoleto di farlo.


2
Ecco cosa penso che Armin significhi "mal supportato": in Python, ricaricare un modulo non ricarica i moduli che quel modulo importa, né riassocia i nomi in altri moduli dal puntare a oggetti vecchi a quelli nuovi dal nuovo modulo - lo scambio a caldo di un nuovo modulo nello stesso processo è problematico. È molto meglio iniziare un nuovo processo quando si desidera apportare una modifica al codice.
Aaron Hall,

Ora che me lo dici, ricordo il comportamento che hai descritto, grazie per il chiarimento! Modificherò la risposta di conseguenza.
Martin Jungblut Schreiner il

ok, più 1 per avermi citato. :)
Aaron Hall

L'aggiunta di Aaron Hall l'ha chiarito per me. Grazie. :)
Remco Haszing,

7
Perché dobbiamo usare la variabile d'ambiente FLASK_APP? È intrinseco a come funziona? Sono curioso di sapere perché flask runnon accetta lo stesso argomento, il che renderebbe più semplice l'onboarding dei nuovi arrivati. Grazie.
John Wheeler,
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.