web-dev-qa-db-ja.com

flask CLIがFlask.runよりも推奨されるのはなぜですか?

Flask 0.11でflask CLIが導入されました。ドキュメントと変更ログの状態の両方で、これをお勧めします。

開発サーバーのドキュメント

Flask 0.11から始めて、開発サーバーを実行するための組み込みの方法が複数あります。最良の方法はflaskです。コマンドラインユーティリティですが、Flask.run()メソッドを引き続き使用することもできます。

コマンドライン

flaskコマンドラインスクリプト(コマンドラインインターフェイス)は、アプリケーションのロード方法により優れたリロードエクスペリエンスを提供するため、開発に強く推奨されます。基本的な使い方は次のとおりです:

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

変更ログ

  • flaskおよび_flask.cli_モジュールを追加して、クリックCLIシステムからローカルデバッグサーバーを起動します。これは、以前のflask.run()メソッドよりも推奨されます。これは、デザインが異なるために高速で信頼性が高く、_Flask-Script_も置き換えられるためです。

これまでのところ、この「優れたリロード体験」に気づきませんでした。カスタムスクリプトでCLIを使用するポイントがわかりません。

_Flask.run_を使用する場合、pythonファイルを作成するだけです。

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


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

CLIを使用する場合、環境変数を指定する必要があります。 CLIのドキュメントには、virtualenvwrapperのactivateスクリプトに統合できると記載されています。個人的には、これはアプリケーションの一部であると考えており、バージョン管理下にあるべきだと思います。悲しいかな、シェルスクリプトが必要です。

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

flask run
_

もちろん、これには、Windowsユーザーが共同作業を開始するとすぐに、追加のbatスクリプトが付随します。

また、最初のオプションでは、実際のアプリを起動する前にPythonで記述されたセットアップを許可します。

これにより、たとえば

  • pythonでコマンドライン引数を解析する
  • アプリを実行する前にログを設定する

彼らはカスタムコマンドを追加することが可能であることを促進しているようです。なぜこれが単純なPython=スクリプトを作成するよりも優れているのか、オプションでエントリポイントを介して公開される)がわかりません。

Python run scriptを使用して構成されたロガーを使用する場合のログ出力の例:

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

CLIを使用して構成されたロガーを使用する場合のログ出力の例:ルートロガーをプロセスの早い段階でセットアップできなかったことに注意してください。

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

私の実際の質問は単純です:

flask CLIが_Flask.run_よりも推奨されるのはなぜですか?

13
Remco Haszing

開発サーバーのドキュメントでは、run()の呼び出しとコードの自動再読み込みに問題があると述べています。

これは一般的なケースではうまく機能しますが、Flask 0.11以降はflaskメソッドが推奨されます。リロードメカニズムの仕組みにより、奇妙な副作用がいくつかあります(特定のコードを2回実行したり、メッセージなしでクラッシュしたり、構文エラーまたはインポートエラーが発生したときに終了したりするなど)。

彼らは、CLIはこの問題に悩まされていないと主張しています。

この問題に触れると思われる最初のコミットはこれです: https://github.com/pallets/flask/commit/3bdb90f06b9d3167320180d4a5055dcd949bf72f

そしてそこにアーミン・ロナッチャーは書いた:

自動リロードがサポートされていないため、自動リロードを伴う開発でこの関数を使用することは推奨されません。代わりに、flaskコマンドラインスクリプトのrunserverサポートを使用する必要があります。

アーロンホールによって言及されたように、置換されるモジュールで定義されたクラスのインスタンスであるすべてのオブジェクトはインスタンス化されず、モジュールがリロードされるたびに、run()の使用が問題になる可能性がありますそれがインポートするモジュールもリロードされません。

これに関する詳細は、Python 3 at: https://docs.python.org/3/library/importlib.html?highlight=importlib#module-importlib

それは述べています:

Pythonにある他のすべてのオブジェクトと同様に、古いオブジェクトは、参照カウントがゼロになって初めて回収されます。

古いオブジェクトへの他の参照(モジュールの外部の名前など)は、新しいオブジェクトを参照するために再バインドされないため、必要に応じて、それらが発生する各ネームスペースで更新する必要があります。

モジュールがリロードされると、そのディクショナリ(モジュールのグローバル変数を含む)が保持されます。名前の再定義は古い定義を上書きするので、これは通常問題にはなりません。モジュールの新しいバージョンが古いバージョンで定義された名前を定義していない場合、古い定義が残ります。

したがって、新しいプロセスを作成して古いプロセスを強制終了することにより、古い参照をすべて自然に排除できます。

また、FlaskのCLIは「クリック」モジュールを使用しているため、カスタムコマンドを簡単に追加できますが、最も重要なのは、リロードのバグを修正するだけでなく、CLIはアプリケーションを実行してカスタムコマンドを追加するための標準化された方法を提供します。同じことを行う複数の方法を用意するよりも、異なるチームやアプリケーション間でFlaskに慣れ親しむことができるため、これは非常に良いことのように思えます。

ZenのPythonに従ってFlaskをさらに作成する本物の方法のようです。

それを行うには、明白な方法が1つ(できれば1つだけ)あるはずです。