it-swarm.com.de

Warum wird flask CLI über Flask.run empfohlen?

In Flask 0.11 wurde eine flask CLI eingeführt. Sowohl in den Dokumenten als auch im Änderungsprotokoll wird dies empfohlen.

Development Server-Dokumente :

Beginnend mit Flask 0.11 gibt es mehrere integrierte Möglichkeiten, einen Entwicklungsserver auszuführen. Die beste ist die Flasche Befehlszeilenprogramm, Sie können jedoch auch weiterhin die Methode Flask.run() verwenden.

Befehlszeile

Das Befehlszeilenskript flask (Command Line Interface) wird für die Entwicklung dringend empfohlen, da es aufgrund des Ladens der Anwendung eine hervorragende Erfahrung beim erneuten Laden bietet. Die grundlegende Verwendung ist wie folgt:

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

Changelog :

  • flask und das Modul flask.cli Wurden hinzugefügt, um den lokalen Debug-Server über das Click-CLI-System zu starten. Dies wird gegenüber der alten Methode flask.run() empfohlen, da sie aufgrund eines anderen Designs schneller und zuverlässiger arbeitet und auch Flask-Script Ersetzt.

Bisher habe ich dieses "überlegene Nachladeerlebnis" nicht bemerkt. Ich sehe keinen Sinn darin, die CLI über ein benutzerdefiniertes Skript zu verwenden.

Wenn ich Flask.run Verwende, schreibe ich einfach eine python Datei:

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


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

Bei Verwendung der CLI müssten Umgebungsvariablen angegeben werden. In den CLI-Dokumenten wird angegeben, dass dies in das Skript activate von virtualenvwrapper integriert werden kann. Persönlich betrachte ich dies als Teil der Anwendung und denke, dass es unter Versionskontrolle sein sollte. Leider wird ein Shell-Skript benötigt:

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

flask run

Dies wird natürlich von einem zusätzlichen Bat-Skript begleitet, sobald Windows-Benutzer mit der Zusammenarbeit beginnen.

Die erste Option ermöglicht auch das Setup, das in Python] geschrieben wurde, bevor die eigentliche App gestartet wird.

Dies ermöglicht zum Beispiel

  • befehlszeilenargumente in Python analysieren
  • zum Einrichten der Protokollierung vor dem Ausführen der App

Sie scheinen zu fördern, dass es möglich ist, benutzerdefinierte Befehle hinzuzufügen. Ich verstehe nicht, warum dies besser ist, als einfache Python -Skripte) zu schreiben, die optional über Einstiegspunkte verfügbar gemacht werden.

Beispiel für eine Protokollausgabe bei Verwendung eines konfigurierten Protokollierers mit dem Ausführungsskript 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

Beispiel für die Protokollausgabe bei Verwendung eines konfigurierten Loggers mithilfe der CLI: Beachten Sie, dass der Root-Logger nicht früh genug eingerichtet werden konnte.

$ ./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

Meine eigentliche Frage ist einfach:

Warum wird flask CLI über Flask.run Empfohlen ?

13
Remco Haszing

In den Entwicklungsserver-Dokumenten wird angegeben, dass beim Aufrufen von run () und beim automatischen Neuladen von Code Probleme auftreten:

Dies funktioniert gut für den allgemeinen Fall, aber nicht für die Entwicklung, weshalb ab Flask 0.11 die Methode flask) empfohlen wird. Der Grund dafür Aufgrund der Funktionsweise des Reload-Mechanismus treten einige bizarre Nebenwirkungen auf (z. B. zweimaliges Ausführen bestimmter Codes, manchmal Absturz ohne Meldung oder Absterben, wenn ein Syntax- oder Importfehler auftritt).

Sie behaupten, dass die CLI nicht unter diesem Problem leidet.

Das erste Commit, das dieses Problem zu berühren scheint, ist das folgende: https://github.com/pallets/flask/commit/3bdb90f06b9d3167320180d4a5055dcd949bf72f

Und dort schrieb Armin Ronacher:

Es wird nicht empfohlen, diese Funktion für die Entwicklung mit automatischem Neuladen zu verwenden, da dies schlecht unterstützt wird. Stattdessen sollten Sie die Unterstützung des Befehlszeilenskripts flaskrunserver verwenden.

Wie von Aaron Hall erwähnt, scheint die Verwendung von run () problematisch zu sein, da alle Objekte, bei denen es sich um Instanzen von Klassen handelt, die in den zu ersetzenden Modulen definiert sind, nicht erneut aktiviert werden und bei jedem erneuten Laden eines Moduls die Module, die importiert werden, werden ebenfalls nicht neu geladen.

Die Details dazu finden Sie unter Python 3 unter: https://docs.python.org/3/library/importlib.html?highlight=importlib#module-importlib)

Es sagt aus:

Wie bei allen anderen Objekten in Python werden die alten Objekte erst zurückgefordert, nachdem ihre Referenzanzahl auf Null gefallen ist.

Andere Verweise auf die alten Objekte (z. B. Namen außerhalb des Moduls) werden nicht zurückgebunden, um auf die neuen Objekte zu verweisen, und müssen in jedem Namespace aktualisiert werden, in dem sie auftreten, wenn dies gewünscht wird.

Wenn ein Modul neu geladen wird, bleibt sein Wörterbuch (das die globalen Variablen des Moduls enthält) erhalten. Neudefinitionen von Namen überschreiben die alten Definitionen, sodass dies im Allgemeinen kein Problem darstellt. Wenn die neue Version eines Moduls keinen Namen definiert, der von der alten Version definiert wurde, bleibt die alte Definition erhalten.

Wenn Sie also einen neuen Prozess erstellen und den alten beenden, beseitigen Sie natürlich alle veralteten Referenzen.

Außerdem verwendet die CLI von Flask das "Klick" -Modul, wodurch das Hinzufügen benutzerdefinierter Befehle sehr einfach ist. Vor allem aber bietet die CLI neben der Behebung des Neuladefehlers eine standardisierte Möglichkeit, Anwendungen auszuführen und benutzerdefinierte Befehle hinzuzufügen. Das klingt nach einer sehr guten Sache, da es die Vertrautheit mit Flask) zwischen verschiedenen Teams und Anwendungen übertragbarer macht, anstatt mehrere Möglichkeiten zu haben, dasselbe zu tun.

Es scheint ein echter Weg zu sein, Flask mehr nach dem Zen von Python zu machen:

Es sollte einen - und vorzugsweise nur einen - offensichtlichen Weg geben, dies zu tun.