警告—警告制御—Pythonドキュメント

提供:Dev Guides
< PythonPython/docs/3.8/library/warnings
移動先:案内検索

警告 —警告制御

ソースコード: :source: `Lib / warnings.py`



警告メッセージは通常、プログラム内のある状態をユーザーに警告するのに役立つ状況で発行されます。この状態では、(通常は)例外を発生させてプログラムを終了する必要はありません。 たとえば、プログラムが廃止されたモジュールを使用しているときに警告を発行したい場合があります。

Pythonプログラマーは、このモジュールで定義されている warn()関数を呼び出すことによって警告を発行します。 (Cプログラマーは PyErr_WarnEx()を使用します。詳細については、例外処理を参照してください)。

警告メッセージは通常 sys.stderr に書き込まれますが、すべての警告を無視することから例外に変えることまで、その処理を柔軟に変更できます。 警告の処理は、警告カテゴリ、警告メッセージのテキスト、および警告が発行される送信元の場所によって異なります。 通常、同じソースの場所に対する特定の警告の繰り返しは抑制されます。

警告制御には2つの段階があります。最初に、警告が発行されるたびに、メッセージを発行する必要があるかどうかが決定されます。 次に、メッセージを発行する場合は、ユーザーが設定可能なフックを使用してフォーマットおよび印刷します。

警告メッセージを発行するかどうかの決定は、警告フィルターによって制御されます。これは、一致するルールとアクションのシーケンスです。 filterwarnings()を呼び出すことでルールをフィルターに追加し、 resetwarnings()を呼び出すことでデフォルトの状態にリセットできます。

警告メッセージの出力は、 showwarning()を呼び出すことによって実行されますが、これはオーバーライドされる可能性があります。 この関数のデフォルトの実装は、 formatwarning()を呼び出すことによってメッセージをフォーマットします。これは、カスタム実装でも使用できます。

も参照してください

logging.captureWarnings()を使用すると、標準のロギングインフラストラクチャですべての警告を処理できます。


警告カテゴリ

警告カテゴリを表す組み込みの例外がいくつかあります。 この分類は、警告のグループを除外できるようにするのに役立ちます。

これらは技術的には組み込みの例外ですが、概念的には警告メカニズムに属しているため、ここで説明します。

ユーザーコードは、標準の警告カテゴリの1つをサブクラス化することにより、追加の警告カテゴリを定義できます。 警告カテゴリは、常に Warning クラスのサブクラスである必要があります。

現在、次の警告カテゴリクラスが定義されています。

クラス 説明
Warning これは、すべての警告カテゴリクラスの基本クラスです。 Exception のサブクラスです。
UserWarning warn()のデフォルトカテゴリ。
DeprecationWarning 非推奨の機能に関する警告が他のPython開発者を対象としている場合の警告の基本カテゴリ(__main__のコードによってトリガーされない限り、デフォルトでは無視されます)。
SyntaxWarning 疑わしい構文機能に関する警告の基本カテゴリ。
RuntimeWarning 疑わしいランタイム機能に関する警告の基本カテゴリ。
FutureWarning 非推奨の機能に関する警告の基本カテゴリ。これらの警告は、Pythonで記述されたアプリケーションのエンドユーザーを対象としています。
PendingDeprecationWarning 将来非推奨になる機能に関する警告の基本カテゴリ(デフォルトでは無視されます)。
ImportWarning モジュールのインポートプロセス中にトリガーされる警告の基本カテゴリ(デフォルトでは無視されます)。
UnicodeWarning Unicodeに関連する警告の基本カテゴリ。
BytesWarning bytes および bytearray に関連する警告の基本カテゴリ。
ResourceWarning リソースの使用に関連する警告の基本カテゴリ。

バージョン3.7での変更:以前の DeprecationWarningFutureWarning は、機能が完全に削除されているか、動作が変更されているかに基づいて区別されていました。 これらは、対象読者と、デフォルトの警告フィルターによる処理方法に基づいて区別されるようになりました。


警告フィルター

警告フィルターは、警告を無視するか、表示するか、エラーに変えるか(例外を発生させるか)を制御します。

概念的には、警告フィルターはフィルター仕様の順序付きリストを維持します。 特定の警告は、一致するものが見つかるまで、リスト内の各フィルター仕様と順番に照合されます。 フィルタは一致の処理を決定します。 各エントリは、( actionmessagecategorymodulelineno )の形式のタプルです。どこ:

  • action は、次のいずれかの文字列です。

    価値

    配置

    "default"

    警告が発行された場所(モジュール+行番号)ごとに一致する警告の最初の発生を出力します

    "error"

    一致する警告を例外に変える

    "ignore"

    一致する警告を出力しない

    "always"

    常に一致する警告を出力します

    "module"

    警告が発行された各モジュールの一致する警告の最初の発生を出力します(行番号に関係なく)

    "once"

    場所に関係なく、一致する警告が最初に発生した場合にのみ出力します

  • message は、警告メッセージの先頭が一致する必要がある正規表現を含む文字列です。 式は常に大文字と小文字を区別しないようにコンパイルされます。

  • category はクラス( Warning のサブクラス)であり、一致するには警告カテゴリがサブクラスである必要があります。

  • module は、モジュール名が一致する必要がある正規表現を含む文字列です。 式では、大文字と小文字が区別されるようにコンパイルされています。

  • lineno は、警告が発生した行番号が一致する必要がある整数、または0がすべての行番号と一致する必要がある整数です。

Warning クラスは組み込みの Exception クラスから派生しているため、警告をエラーに変えるには、単にcategory(message)を発生させます。

警告が報告され、登録されているどのフィルターとも一致しない場合は、「デフォルト」アクションが適用されます(そのためその名前が付けられています)。

警告フィルターの説明

警告フィルターは、Pythonインタープリターコマンドラインに渡される -W オプションと PYTHONWARNINGS 環境変数によって初期化されます。 インタプリタは、提供されたすべてのエントリの引数を、 sys.warnoptions に解釈せずに保存します。 warnings モジュールは、最初にインポートされたときにこれらを解析します( sys.stderr にメッセージを出力した後、無効なオプションは無視されます)。

個々の警告フィルターは、コロンで区切られた一連のフィールドとして指定されます。

action:message:category:module:line

これらの各フィールドの意味は、警告フィルターで説明されているとおりです。 1行に複数のフィルターをリストする場合( PYTHONWARNINGS の場合)、個々のフィルターはコンマで区切られ、後でリストされるフィルターが前にリストされるフィルターよりも優先されます(左から右に適用され、最後に適用されたフィルターが以前のフィルターよりも優先されます)。

一般的に使用される警告フィルターは、すべての警告、特定のカテゴリーの警告、または特定のモジュールまたはパッケージによって発生する警告のいずれかに適用されます。 いくつかの例:

default                      # Show all warnings (even those ignored by default)
ignore                       # Ignore all warnings
error                        # Convert all warnings to errors
error::ResourceWarning       # Treat ResourceWarning messages as errors
default::DeprecationWarning  # Show DeprecationWarning messages
ignore,default:::mymodule    # Only report warnings triggered by "mymodule"
error:::mymodule[.*]         # Convert warnings to errors in "mymodule"
                             # and any subpackages of "mymodule"

デフォルトの警告フィルター

デフォルトでは、Pythonはいくつかの警告フィルターをインストールします。これらは、 -W コマンドラインオプション、 PYTHONWARNINGS 環境変数、およびの呼び出しによってオーバーライドできます。 filterwarnings()

通常のリリースビルドでは、デフォルトの警告フィルターには次のエントリがあります(優先順位順)。

default::DeprecationWarning:__main__
ignore::DeprecationWarning
ignore::PendingDeprecationWarning
ignore::ImportWarning
ignore::ResourceWarning

デバッグビルドでは、デフォルトの警告フィルターのリストは空です。

バージョン3.2で変更: PendingDeprecationWarning に加えて、 DeprecationWarning がデフォルトで無視されるようになりました。


バージョン3.7で変更: DeprecationWarning は、__main__のコードによって直接トリガーされると、デフォルトで再び表示されます。


バージョン3.7で変更: BytesWarning はデフォルトのフィルターリストに表示されなくなり、代わりに -b が2回指定します。


デフォルトのフィルターをオーバーライドする

Pythonで記述されたアプリケーションの開発者は、デフォルトで all Pythonレベルの警告をユーザーから非表示にし、テストの実行時またはアプリケーションでの作業時にのみ表示することをお勧めします。 フィルタ構成をインタプリタに渡すために使用される sys.warnoptions 属性は、警告を無効にする必要があるかどうかを示すマーカーとして使用できます。

import sys

if not sys.warnoptions:
    import warnings
    warnings.simplefilter("ignore")

Pythonコードのテストランナーの開発者は、代わりに、次のようなコードを使用して、テスト対象のコードに対して all 警告がデフォルトで表示されるようにすることをお勧めします。

import sys

if not sys.warnoptions:
    import os, warnings
    warnings.simplefilter("default") # Change the filter in this process
    os.environ["PYTHONWARNINGS"] = "default" # Also affect subprocesses

最後に、__main__以外の名前空間でユーザーコードを実行するインタラクティブシェルの開発者は、次のようなコードを使用して、 DeprecationWarning メッセージがデフォルトで表示されるようにすることをお勧めします(user_nsは、インタラクティブに入力されたコードを実行するために使用されるモジュールです):

import warnings
warnings.filterwarnings("default", category=DeprecationWarning,
                                   module=user_ns.get("__name__"))

警告を一時的に抑制する

非推奨の関数などの警告が発生することがわかっているコードを使用しているが、警告を表示したくない場合(コマンドラインで警告が明示的に構成されている場合でも)、を使用して警告を抑制することができます。 catch_warnings コンテキストマネージャー:

import warnings

def fxn():
    warnings.warn("deprecated", DeprecationWarning)

with warnings.catch_warnings():
    warnings.simplefilter("ignore")
    fxn()

コンテキストマネージャ内では、すべての警告は単に無視されます。 これにより、非推奨のコードの使用を認識していない可能性のある他のコードの警告を抑制せずに、警告を表示せずに既知の非推奨のコードを使用できます。 注:これは、シングルスレッドアプリケーションでのみ保証されます。 2つ以上のスレッドが catch_warnings コンテキストマネージャーを同時に使用する場合、動作は定義されていません。


警告のテスト

コードによって発生した警告をテストするには、 catch_warnings コンテキストマネージャーを使用します。 これを使用すると、警告フィルターを一時的に変更して、テストを容易にすることができます。 たとえば、次の手順を実行して、発生したすべての警告をキャプチャして確認します。

import warnings

def fxn():
    warnings.warn("deprecated", DeprecationWarning)

with warnings.catch_warnings(record=True) as w:
    # Cause all warnings to always be triggered.
    warnings.simplefilter("always")
    # Trigger a warning.
    fxn()
    # Verify some things
    assert len(w) == 1
    assert issubclass(w[-1].category, DeprecationWarning)
    assert "deprecated" in str(w[-1].message)

alwaysの代わりにerrorを使用して、すべての警告を例外にすることもできます。 once / defaultルールが原因ですでに警告が発生している場合は、どのフィルターが設定されていても、警告が表示されない限り、警告は再度表示されないことに注意してください。警告に関連するレジストリがクリアされました。

コンテキストマネージャが終了すると、警告フィルタはコンテキストが入力されたときの状態に復元されます。 これにより、テスト間で予期しない方法でテストが警告フィルターを変更し、テスト結果が不確定になるのを防ぎます。 モジュール内の showwarning()関数も元の値に復元されます。 注:これは、シングルスレッドアプリケーションでのみ保証されます。 2つ以上のスレッドが catch_warnings コンテキストマネージャーを同時に使用する場合、動作は定義されていません。

同じ種類の警告を発する複数の操作をテストする場合、各操作が新しい警告を発していることを確認する方法でそれらをテストすることが重要です(例: 例外として発生する警告を設定し、操作で例外が発生することを確認するか、各操作後に警告リストの長さが増加し続けることを確認するか、新しい操作の前に警告リストから前のエントリを削除します。


新しいバージョンの依存関係のコードを更新する

(Pythonで記述されたアプリケーションのエンドユーザーではなく)主にPython開発者が関心を持つ警告カテゴリは、デフォルトでは無視されます。

特に、この「デフォルトで無視される」リストには、 DeprecationWarning__main__を除くすべてのモジュール)が含まれます。つまり、開発者は、受信するために、通常無視される警告を表示してコードをテストする必要があります。将来の重大なAPI変更のタイムリーな通知(標準ライブラリまたはサードパーティパッケージのいずれか)。

理想的なケースでは、コードに適切なテストスイートがあり、テストランナーは、テストの実行時にすべての警告を暗黙的に有効にします( unittest モジュールによって提供されるテストランナーがこれを行います)。

あまり理想的ではないケースでは、 -Wd をPythonインタープリター(これは-W defaultの省略形)に渡すか、PYTHONWARNINGS=defaultを設定することで、非推奨のインターフェイスの使用をアプリケーションで確認できます。環境。 これにより、デフォルトで無視される警告を含む、すべての警告のデフォルト処理が有効になります。 発生した警告に対して実行されるアクションを変更するには、 -W に渡される引数を変更できます(例: -W error)。 可能なことの詳細については、 -W フラグを参照してください。


利用可能な機能

warnings.warn(message, category=None, stacklevel=1, source=None)

警告を発行するか、無視するか、例外を発生させます。 category 引数を指定する場合は、警告カテゴリクラスである必要があります。 デフォルトは UserWarning です。 または、メッセージ警告インスタンスにすることもできます。その場合、カテゴリは無視され、message.__class__が使用されます。 この場合、メッセージテキストはstr(message)になります。 この関数は、発行された特定の警告が警告フィルターによってエラーに変更された場合に例外を発生させます。 stacklevel 引数は、次のようにPythonで記述されたラッパー関数で使用できます。

def deprecation(message):
    warnings.warn(message, DeprecationWarning, stacklevel=2)

これにより、警告はdeprecation()自体のソースではなく、deprecation()の呼び出し元を参照するようになります(後者は警告メッセージの目的を無効にするため)。

source は、指定されている場合、 ResourceWarning を発行した破棄されたオブジェクトです。

バージョン3.6で変更: source パラメーターが追加されました。

warnings.warn_explicit(message, category, filename, lineno, module=None, registry=None, module_globals=None, source=None)

これは、 warn()の機能への低レベルのインターフェイスであり、メッセージ、カテゴリ、ファイル名、行番号、およびオプションでモジュール名とレジストリ(__warningregistry__モジュールの辞書)。 モジュール名のデフォルトは、.pyが削除されたファイル名です。 レジストリが渡されない場合、警告は抑制されません。 message は文字列である必要があり、 categoryWarning または message のサブクラスは Warning インスタンスである可能性があります。この場合、カテゴリは無視されます。

module_globals が指定されている場合は、警告が発行されるコードで使用されているグローバル名前空間である必要があります。 (この引数は、zipファイルまたはその他のファイルシステム以外のインポートソースにあるモジュールのソースの表示をサポートするために使用されます)。

source は、指定されている場合、 ResourceWarning を発行した破棄されたオブジェクトです。

バージョン3.6で変更: source パラメーターを追加します。

warnings.showwarning(message, category, filename, lineno, file=None, line=None)
ファイルに警告を書き込みます。 デフォルトの実装はformatwarning(message, category, filename, lineno, line)を呼び出し、結果の文字列を file に書き込みます。これは、デフォルトで sys.stderr になります。 warnings.showwarningに割り当てることで、この関数を呼び出し可能な関数に置き換えることができます。 line は、警告メッセージに含まれるソースコードの行です。 line が指定されていない場合、 showwarning()filename および lineno で指定された行を読み取ろうとします。
warnings.formatwarning(message, category, filename, lineno, line=None)
警告を標準的な方法でフォーマットします。 これは、埋め込まれた改行を含み、改行で終わる文字列を返します。 line は、警告メッセージに含まれるソースコードの行です。 line が指定されていない場合、 formatwarning()filename および lineno で指定された行を読み取ろうとします。
warnings.filterwarnings(action, message=, category=Warning, module=, lineno=0, append=False)
警告フィルター仕様のリストにエントリを挿入します。 エントリはデフォルトで先頭に挿入されます。 append がtrueの場合、最後に挿入されます。 これにより、引数のタイプがチェックされ、メッセージおよびモジュールの正規表現がコンパイルされ、警告フィルターのリストにタプルとして挿入されます。 両方が特定の警告に一致する場合、リストの先頭に近いエントリは、リストの後半のエントリを上書きします。 省略された引数は、デフォルトですべてに一致する値になります。
warnings.simplefilter(action, category=Warning, lineno=0, append=False)
警告フィルター仕様のリストに簡単なエントリを挿入します。 関数パラメーターの意味は filterwarnings()と同じですが、挿入されたフィルターは、カテゴリーと行番号が一致する限り、どのモジュールのどのメッセージとも常に一致するため、正規表現は必要ありません。
warnings.resetwarnings()
警告フィルターをリセットします。 これにより、 -W コマンドラインオプションや simplefilter()の呼び出しを含む、 filterwarnings()への以前のすべての呼び出しの効果が破棄されます。


利用可能なコンテキストマネージャー

class warnings.catch_warnings(*, record=False, module=None)

警告フィルターと showwarning()関数をコピーし、終了時に復元するコンテキストマネージャー。 record 引数が False (デフォルト)の場合、コンテキストマネージャーはエントリ時に None を返します。 recordTrue の場合、カスタム showwarning()関数(sys.stdout)。 リスト内の各オブジェクトには、 showwarning()の引数と同じ名前の属性があります。

module 引数は、フィルターが保護される warnings をインポートしたときに返されるモジュールの代わりに使用されるモジュールを取ります。 この引数は、主に警告モジュール自体をテストするために存在します。

ノート

catch_warnings マネージャーは、モジュールの showwarning()関数とフィルター仕様の内部リストを置き換え、後で復元することで機能します。 これは、コンテキストマネージャーがグローバル状態を変更しているため、スレッドセーフではないことを意味します。