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


13

Flask 0.11では、flaskCLIが導入されました。docsとchangelogの両方に、これが推奨されています。

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

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

コマンドライン

フラスコ、それは優れたリロード体験を提供するため、コマンドラインスクリプト(コマンドラインインタフェース)が強くにより、アプリケーションをロードする方法を開発することをお勧めします。基本的な使用方法は次のとおりです。

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

変更ログ

  • クリックCLIシステムを介してローカルデバッグサーバーを起動flaskするflask.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ドキュメントでは、これactivateはvirtualenvwrapper のスクリプトに統合できると述べられています。個人的には、これはアプリケーションの一部であると考えており、バージョン管理下にあるべきだと思います。残念ながら、シェルスクリプトが必要です。

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

flask run

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

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

これにより、たとえば

  • Pythonでコマンドライン引数を解析する
  • アプリを実行する前にロギングをセットアップする

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

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

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

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

なぜフラスコCLIが推奨されるのFlask.runですか?

回答:


11

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

これは一般的なケースではうまく機能しますが、開発ではうまく機能しないため、Flask 0.11以降ではフラスコ法が推奨されます。これは、リロードメカニズムの動作により、奇妙な副作用が発生するためです(特定のコードを2回実行したり、メッセージなしでクラッシュしたり、構文エラーやインポートエラーが発生した場合に死んだりするなど)。

彼らは、CLIがこの問題の影響を受けないと主張しています。

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

そこで、Armin Ronacherは次のように書いています。

この機能は、自動リロードを使用した開発に使用することはお勧めできません。これは、サポートが不十分なためです。代わりに、flaskコマンドラインスクリプトのrunserverサポートを使用する必要があります。

Aaron Hallが述べたように、置き換えられるモジュールで定義されたクラスのインスタンスであるすべてのオブジェクトは再インスタンス化されず、モジュールがリロードされるたびに、run()の使用に問題があるようです。インポートするモジュールもリロードされません。

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

状態:

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

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

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

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

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

PythonのZenに準拠してFlaskをより真正にする真の方法のようです。

1つ、できれば1つだけが必要です。


2
Arminの「悪いサポート」の意味は次のとおりです。Pythonでは、モジュールをリロードしても、そのモジュールがインポートするモジュールはリロードされません。そのため、新しいモジュールを同じプロセスにホットスワップすることには問題があります。コードを変更したい場合は、新しいプロセスを開始する方がはるかに適切です。
アーロンホール

あなたがそれについて言及したので、私はあなたが説明した行動を思い出します、明確化に感謝します!それに応じて答えを編集します。
マーティンユングブルートシュライナー

OK、プラス1は私を引用しています。:)
アーロンホール

アーロンホールからの追加により、それが明確になりました。ありがとう。:)
Remco Haszing

7
環境変数を使用する必要があるのはなぜFLASK_APPですか?これは、これがどのように機能するかについて本質的なものですか?私はなぜflask run議論と同じことを受け入れないのか不思議に思っています。ありがとうございました。
ジョンウィーラー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.