web-dev-qa-db-fra.com

Pourquoi est flask CLI recommandé sur Flask.run?

Dans Flask 0,11, une CLI flask a été introduite. Les documents et le journal des modifications indiquent que cela est recommandé.

documents du serveur de développement :

À partir de Flask 0.11, il existe plusieurs façons intégrées d'exécuter un serveur de développement. La meilleure est l'utilitaire de ligne de commande flask mais vous pouvez également continuer à utiliser le Flask.run() méthode.

Ligne de commande

Le script de ligne de commande flask (interface de ligne de commande) est fortement recommandé pour le développement car il offre une expérience de rechargement supérieure en raison de la façon dont il charge l'application. L'utilisation de base est la suivante:

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

Changelog :

  • Ajout de flask et du module flask.cli Pour démarrer le serveur de débogage local via le système CLI click. Ceci est recommandé par rapport à l'ancienne méthode flask.run() car elle fonctionne plus rapidement et plus fiable en raison d'une conception différente et remplace également Flask-Script.

Jusqu'à présent, je n'ai pas remarqué cette "expérience de rechargement supérieure". Je ne vois pas l'intérêt d'utiliser la CLI sur un script personnalisé.

Si vous utilisez Flask.run, J'écrirais simplement un fichier python:

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


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

Si vous utilisez l'interface CLI, il faudrait spécifier des variables d'environnement. Dans la documentation CLI, il est indiqué que cela peut être intégré dans le script activate de virtualenvwrapper. Personnellement, je considère que cela fait partie de l'application et pense que cela devrait être sous contrôle de version. Hélas, un script Shell est nécessaire:

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

flask run

Bien sûr, cela sera accompagné d'un script bat supplémentaire dès que les utilisateurs de Windows commenceront à collaborer.

La première option permet également une configuration écrite en Python avant de démarrer l'application réelle.

Cela permet par exemple

  • analyser les arguments de ligne de commande en Python
  • pour configurer la journalisation avant d'exécuter l'application

Ils semblent promouvoir qu'il est possible d'ajouter des commandes personnalisées. Je ne vois pas pourquoi c'est mieux que d'écrire de simples scripts Python, éventuellement exposés via des points d'entrée.

Exemple de sortie de journalisation lors de l'utilisation d'un enregistreur configuré à l'aide du script d'exécution 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

Exemple de sortie de journalisation lors de l'utilisation d'un enregistreur configuré à l'aide de l'interface CLI:, notez que l'enregistreur racine n'a pas pu être configuré suffisamment tôt dans le processus.

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

Ma vraie question est simplement:

Pourquoi est flask CLI recommandé sur Flask.run?

13
Remco Haszing

Dans les documents du serveur de développement, ils indiquent qu'il y a des problèmes avec l'appel de run () et le rechargement automatique du code:

Cela fonctionne bien pour le cas commun, mais cela ne fonctionne pas bien pour le développement, c'est pourquoi à partir de Flask 0.11 en avant la méthode flask est recommandée. La raison de ceci est dû au fonctionnement du mécanisme de rechargement, il y a des effets secondaires bizarres (comme exécuter deux fois du code, parfois planter sans message ou mourir lorsqu'une erreur de syntaxe ou d'importation se produit).

Ils affirment que la CLI ne souffre pas de ce problème.

Le premier commit qui semble toucher à ce problème est le suivant: https://github.com/pallets/flask/commit/3bdb90f06b9d3167320180d4a5055dcd949bf72f

Et là, Armin Ronacher a écrit:

Il n'est pas recommandé d'utiliser cette fonction pour le développement avec rechargement automatique car cela est mal pris en charge. À la place, vous devez utiliser la prise en charge flask du script de ligne de commande runserver.

Comme mentionné par Aaron Hall, il semble que l'utilisation de run () pourrait être problématique du fait que tous les objets qui sont des instances de classes définies dans les modules remplacés ne seront pas réinstanciés, et chaque fois qu'un module est rechargé, le les modules qu'il importe ne sont pas rechargés également.

Les détails à ce sujet peuvent être trouvés pour Python 3 à: https://docs.python.org/3/library/importlib.html?highlight=importlib#module-importlib

Il est dit:

Comme avec tous les autres objets de Python les anciens objets ne sont récupérés qu'après que leur nombre de références soit tombé à zéro.

Les autres références aux anciens objets (comme les noms externes au module) ne sont pas rebondies pour faire référence aux nouveaux objets et doivent être mises à jour dans chaque espace de noms où elles se produisent si cela est souhaité.

Lorsqu'un module est rechargé, son dictionnaire (contenant les variables globales du module) est conservé. Les redéfinitions de noms remplaceront les anciennes définitions, donc ce n'est généralement pas un problème. Si la nouvelle version d'un module ne définit pas un nom qui a été défini par l'ancienne version, l'ancienne définition reste.

Ainsi, en créant un nouveau processus et en tuant l'ancien, vous éliminez naturellement toutes les références obsolètes.

En outre, la CLI de Flask utilise le module `` clic '', ce qui facilite l'ajout de commandes personnalisées, mais surtout, en plus de corriger le bogue de rechargement, la CLI offre un moyen standardisé d'exécuter des applications et d'ajouter des commandes personnalisées. Cela semble être une très bonne chose, car cela rend la familiarité avec Flask plus transférable entre différentes équipes et applications, plutôt que d'avoir plusieurs façons de faire la même chose.

Cela semble être un véritable moyen de rendre Flask plus conforme au Zen de Python:

Il devrait y avoir une - et de préférence une seule - manière évidente de le faire.