warnings --- 警告の制御

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


警告メッセージは一般に、ユーザに警告しておいた方がよいような状況下にプログラムが置かれているが、その状況は (通常は) 例外を送出したりそのプログラムを終了させるほどの正当な理由がないといった状況で発されます。例えば、プログラムが古いモジュールを使っている場合には警告を発したくなるかもしれません。

Python プログラマは、このモジュールの warn() 関数を使って警告を発することができます。(C 言語のプログラマは PyErr_WarnEx() を使います; 詳細は 例外処理 を参照してください)。

警告メッセージは通常 sys.stderr に出力されますが、すべての警告を無視したり、警告を例外にしたりと、その処理を柔軟に変更することができます。 警告の処理は warning category 、警告メッセージのテキスト、警告が発行されたソースの位置に基づいて変化します。 同じソースの位置で特定の警告が繰り返された場合、通常は抑制されます。

警告制御には 2 つの段階 (stage) があります: 第一に、警告が発されるたびに、メッセージを出力すべきかどうかの決定が行われます; 次に、メッセージを出力するなら、メッセージはユーザによって設定が可能なフックを使って書式化され印字されます。

警告メッセージを出力するかどうかの決定は、 警告フィルタ によって制御されます。警告フィルタは一致規則 (matching rule)と動作からなるシーケンスです。 filterwarnings() を呼び出して一致規則をフィルタに追加することができ、 resetwarnings() を呼び出してフィルタを標準設定の状態にリセットすることができます。

警告メッセージの印字は showwarning() を呼び出して行うことができ、この関数は上書きすることができます; この関数の標準の実装では、 formatwarning() を呼び出して警告メッセージを書式化しますが、この関数についても自作の実装を使うことができます。

参考

logging.captureWarnings() を使うことで、標準ロギング基盤ですべての警告を扱うことができます。

警告カテゴリ

警告カテゴリを表現する組み込み例外は数多くあります。このカテゴリ化は警告をグループごとフィルタする上で便利です。

これらは厳密に言えば 組み込み例外 ですが、概念的には警告メカニズムに属しているのでここで記述されています。

標準の警告カテゴリをユーザの作成したコード上でサブクラス化することで、さらに別の警告カテゴリを定義することができます。警告カテゴリは常に Warning クラスのサブクラスでなければなりません。

現在以下の警告カテゴリクラスが定義されています:

クラス

説明

Warning

Base class for warning categories. It is a subclass of Exception.

UserWarning

Base class for warnings generated by user code. The default category for warn().

DeprecationWarning

Base class for warnings about deprecated features when those warnings are intended for other Python developers (ignored by default, unless triggered by code in __main__).

PendingDeprecationWarning

Base class for warnings about features that will be deprecated in the future (ignored by default).

SyntaxWarning

Base class for warnings about dubious syntax (typically emitted when compiling Python source code, and hence may not be suppressed by runtime filters).

RuntimeWarning

Base class for warnings about dubious runtime behavior.

FutureWarning

Base class for warnings about deprecated features when those warnings are intended for end users of applications that are written in Python.

ImportWarning

Base class for warnings triggered during the process of importing a module (ignored by default).

UnicodeWarning

Base class for warnings related to Unicode.

EncodingWarning

Base class for warnings related to encodings. See EncodingWarning の有効化 for details.

BytesWarning

Base class for warnings related to bytes and bytearray.

ResourceWarning

Base class for warnings related to resource usage (ignored by default).

バージョン 3.7 で変更: 以前は、機能を完全に削除するか、動作を変更するかに基づいて DeprecationWarning と FutureWarning を区別していました。 現在は、警告の対象となる利用者と、デフォルトの警告フィルタでの扱いに基づいて区別しています。

警告フィルタ

警告フィルタは、ある警告を無視すべきか、表示すべきか、あるいは (例外を送出する) エラーにするべきかを制御します。

概念的には、警告フィルタは複数のフィルタ仕様からなる順番リストを維持しています; 何らかの特定の警告が生じると、一致するものが見つかるまでリスト中の各フィルタとの照合が行われます; 一致したフィルタ仕様がその警告の処理方法を決定します。フィルタの各エントリは (action, message, category, module, lineno) からなるタプルです。ここで:

  • action は以下の文字列のうちの一つです:

    値

    処理方法

    "default"

    警告の発生箇所 (モジュールと行番号) ごとに、一致する警告の最初の一回を出力します

    "error"

    一致した警告を例外に変えます

    "ignore"

    一致した警告を出力しません

    "always"

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

    "module"

    警告が発生するモジュールごとに、行番号にかかわらず、一致する警告の最初の一回を出力します

    "once"

    一致した警告のうち、警告の原因になった場所にかかわらず最初の警告のみ出力します

  • message is a string containing a regular expression that the start of the warning message must match, case-insensitively. In -W and PYTHONWARNINGS, message is a literal string that the start of the warning message must contain (case-insensitively), ignoring any whitespace at the start or end of message.

  • category はクラス (Warning のサブクラス) です。 警告が一致するには、その警告カテゴリが category のサブクラスでなければなりません。

  • module is a string containing a regular expression that the start of the fully qualified module name must match, case-sensitively. In -W and PYTHONWARNINGS, module is a literal string that the fully qualified module name must be equal to (case-sensitively), ignoring any whitespace at the start or end of module.

  • lineno は整数で、警告が発生した場所の行番号に一致しなければなりません。0 の場合はすべての行と一致します。

Warning クラスは組み込みの Exception クラスから派生しているので、警告をエラーに変換するには単に category(message) を raise します。

発せられた警告が登録済みのどのフィルタにも一致しない場合は、その名のとおり "default" アクションが適用されます。

警告の繰り返しを抑制する基準

警告の繰り返しを抑制するフィルタは、次の基準で警告が繰り返しかどうかを判断します:

  • "default": (message, category, module, lineno) がすべて同じ場合に限り、警告を繰り返しと見なします。

  • "module": 行番号を無視し、(message, category, module) が同じであれば、警告を繰り返しと見なします。

  • "once": モジュールと行番号を無視し、(message, category) が同じであれば、警告を繰り返しと見なします。

警告フィルタの指定方法

The warnings filter is initialized by -W options passed to the Python interpreter command line and the PYTHONWARNINGS environment variable. The interpreter saves the arguments for all supplied entries without interpretation in sys.warnoptions; the warnings module parses these when it is first imported (invalid options are ignored, after printing a message to sys.stderr).

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

action:message:category:module:line

各フィールドの意味は 警告フィルタ で説明しています。 PYTHONWARNINGS のように複数のフィルタを一行に並べる場合は、フィルタをカンマで区切ります。 後に記述したフィルタが、それより前に記述したフィルタより優先されます (左から右へ適用され、後から適用したフィルタが先に適用したものより優先されるためです)。

よく使う警告フィルタは、すべての警告、特定のカテゴリの警告、または特定のモジュールやパッケージが発する警告に適用するものです。 例を示します。

default                      # すべての警告を表示する (デフォルトで無視されるものも含む)
ignore                       # すべての警告を無視する
error                        # すべての警告をエラーにする
error::ResourceWarning       # ResourceWarning のメッセージをエラーとして扱う
default::DeprecationWarning  # DeprecationWarning のメッセージを表示する
ignore,default:::mymodule    # "mymodule" が発する警告だけを表示する
error:::mymodule             # "mymodule" の警告をエラーにする

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

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

通常のリリースビルドでは、デフォルトの警告フィルタに次のエントリーが優先順に含まれています。

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

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

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

バージョン 3.7 で変更: __main__ 内のコードが直接発する DeprecationWarning は、再びデフォルトで表示されるようになりました。

バージョン 3.7 で変更: BytesWarning がデフォルトのフィルタリストから除かれ、代わりに -b を二回指定したときに sys.warnoptions を通じて設定されるようになりました。

デフォルトのフィルタの上書き

Python で書いたアプリケーションの開発者は、Python レベルの すべての 警告をデフォルトでは利用者に表示せず、テストやその他の開発作業のときだけ表示したい場合があります。 フィルタ設定をインタープリタに渡すための sys.warnoptions 属性を、警告を無効にすべきかどうかの目印に使えます。

import sys

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

一方、Python コードのテストランナーを開発する場合は、次のようなコードを使い、テスト対象のコードについてはデフォルトで すべての 警告を表示することを推奨します。

import sys

if not sys.warnoptions:
    import os, warnings
    warnings.simplefilter("default") # このプロセス内のフィルタを変更する
    os.environ["PYTHONWARNINGS"] = "default" # 子プロセスにも反映する

Finally, developers of interactive shells that run user code in a namespace other than __main__ are advised to ensure that DeprecationWarning messages are made visible by default, using code like the following (where user_ns is the module used to execute code entered interactively):

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()

While within the context manager all warnings will simply be ignored. This allows you to use known-deprecated code without having to see the warning while not suppressing the warning for other code that might not be aware of its use of deprecated code. Note: this can only be guaranteed in a single-threaded application. If two or more threads use the catch_warnings context manager at the same time, the behavior is undefined.

警告のテスト

コードが警告を発生させることをテストするには、 catch_warnings コンテキストマネージャーを利用します。このクラスを使うと、一時的に警告フィルタを操作してテストに利用できます。例えば、次のコードでは、発生したすべての警告を取得してチェックしています:

import warnings

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

with warnings.catch_warnings(record=True) as w:
    # すべての警告を常に発生させる。
    warnings.simplefilter("always")
    # 警告を発生させる。
    fxn()
    # いくつかの項目を検証する
    assert len(w) == 1
    assert issubclass(w[-1].category, DeprecationWarning)
    assert "deprecated" in str(w[-1].message)

always の代わりに error を利用することで、すべての警告で例外を発生させることができます。1つ気をつけないといけないのは、一度 once/default ルールによって発生した警告は、フィルタに何をセットしているかにかかわらず、警告レジストリをクリアしない限りは 2度と発生しません。

Once the context manager exits, the warnings filter is restored to its state when the context was entered. This prevents tests from changing the warnings filter in unexpected ways between tests and leading to indeterminate test results. The showwarning() function in the module is also restored to its original value. Note: this can only be guaranteed in a single-threaded application. If two or more threads use the catch_warnings context manager at the same time, the behavior is undefined.

同じ種類の警告を発生させる複数の操作をテストする場合、各操作が新しい警告を発生させている事を確認するのは大切な事です (例えば、警告を例外として発生させて各操作が例外を発生させることを確認したり、警告リストの長さが各操作で増加していることを確認したり、警告リストを各操作の前に毎回クリアする事ができます)。

依存先の新しいバージョンに合わせたコードの更新

主に Python 開発者向けの警告カテゴリ (Python で書かれたアプリケーションのエンドユーザー向けではないもの) は、デフォルトで無視されます。

特に、この「デフォルトで無視する」リストには、__main__ 以外のすべてのモジュールの DeprecationWarning が含まれます。 そのため開発者は、通常は無視される警告を表示するようにしてコードをテストする必要があります。 そうすれば、標準ライブラリやサードパーティのパッケージで将来行われる、互換性を損なう API の変更を早めに把握できます。

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

そうした環境が整っていない場合でも、Python インタープリタに -Wd (-W default の省略形) を渡すか、環境変数 PYTHONWARNINGS=default を設定すれば、アプリケーションが非推奨のインターフェースを使っていないか確認できます。 これにより、デフォルトでは無視される警告も含め、すべての警告にデフォルトの処理が適用されます。 警告が発生したときの動作を変えるには、-W に渡す引数を変更します (例: -W error)。 設定できる内容の詳細は -W フラグを参照してください。

利用可能な関数

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

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

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

これにより、警告は deprecated_api 自体のソースではなく、deprecated_api の呼び出し元を指すようになります (関数自体を指しては警告メッセージの目的を果たせないためです)。

キーワード引数 skip_file_prefixes では、スタックレベルを数える際に無視するスタックフレームを指定できます。 一定の stacklevel ではすべての呼び出し経路に対応できない場合や、その値の保守が難しい場合に、常にパッケージの外の呼び出し箇所を警告の発生箇所とするのに役立ちます。 指定する場合は文字列のタプルでなければなりません。 接頭辞を指定すると、stacklevel は暗黙に max(2, stacklevel) に置き換えられます。 現在のパッケージの外から呼び出した箇所に警告を対応させるには、次のように書けます。

# example/lower.py
_warn_skips = (os.path.dirname(__file__),)

def one_way(r_luxury_yacht=None, t_wobbler_mangrove=None):
    if r_luxury_yacht:
        warnings.warn("Please migrate to t_wobbler_mangrove=.",
                      skip_file_prefixes=_warn_skips)

# example/higher.py
from . import lower

def another_way(**kw):
    lower.one_way(**kw)

This makes the warning refer to both the example.lower.one_way() and example.higher.another_way() call sites only from calling code living outside of example package.

source 引数が与えられた場合、これは ResourceWarning を発生させた破壊されたオブジェクトです。

バージョン 3.6 で変更: source 引数を追加しました。

バージョン 3.12 で変更: skip_file_prefixes が追加されました。

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

This is a low-level interface to the functionality of warn(), passing in explicitly the message, category, filename and line number, and optionally other arguments. message must be a string and category a subclass of Warning or message may be a Warning instance, in which case category will be ignored.

module, if supplied, should be the module name. If no module is passed, the filename with .py stripped is used.

registry, if supplied, should be the __warningregistry__ dictionary of the module. If no registry is passed, each warning is treated as the first occurrence, that is, filter actions "default", "module" and "once" are handled as "always".

module_globals は、もし与えられるならば、警告が発せられるコードが使っているグローバル名前空間でなければなりません (この引数は zipfile やその他の非ファイルシステムのインポート元の中にあるモジュールのソースを表示することをサポートするためのものです)。

source 引数が与えられた場合、これは ResourceWarning を発生させた破壊されたオブジェクトです。

バージョン 3.6 で変更: source 引数を追加しました。

warnings.showwarning(message, category, filename, lineno, file=None, line=None)

警告をファイルに書き込みます。標準の実装では、 formatwarning(message, category, filename, lineno, line) を呼び出し、返された文字列を file に書き込みます。 file は標準では sys.stderr です。この関数は warnings.showwarning に任意の呼び出し可能オブジェクトを代入して置き換えることができます。 line は警告メッセージに含めるソースコードの1行です。 line が与えられない場合、 showwarning() は filename と lineno から行を取得することを試みます。

warnings.formatwarning(message, category, filename, lineno, line=None)

警告を通常の方法で書式化します。返される文字列内には改行が埋め込まれている可能性があり、かつ文字列は改行で終端されています。 line は警告メッセージに含まれるソースコードの1行です。 line が渡されない場合、 formatwarning() は filename と lineno から行の取得を試みます。

warnings.filterwarnings(action, message='', category=Warning, module='', lineno=0, append=False)

警告フィルタ仕様 のリストにエントリを一つ挿入します。標準ではエントリは先頭に挿入されます; append が真ならば、末尾に挿入されます。この関数は引数の型をチェックし、 message および module の正規表現をコンパイルしてから、これらをタプルにして警告フィルタのリストに挿入します。二つのエントリが特定の警告に合致した場合、リストの先頭に近い方のエントリが後方にあるエントリに優先します。引数が省略されると、標準ではすべてにマッチする値に設定されます。

warnings.simplefilter(action, category=Warning, lineno=0, append=False)

単純なエントリを 警告フィルタ仕様 のリストに挿入します。引数の意味は filterwarnings() と同じですが、この関数により挿入されるフィルタはカテゴリと行番号が一致していればすべてのモジュールのすべてのメッセージに合致しますので、正規表現は必要ありません。

warnings.resetwarnings()

警告フィルタをリセットします。これにより、 -W コマンドラインオプションによるもの simplefilter() 呼び出しによるものを含め、 filterwarnings() の呼び出しによる影響はすべて無効化されます。

@warnings.deprecated(message, /, *, category=DeprecationWarning, stacklevel=1)

クラス、関数、またはオーバーロードが非推奨であることを示すデコレータです。

このデコレータをオブジェクトに適用すると、そのオブジェクトを使ったときに実行時に非推奨の警告が発せられることがあります。 静的型チェッカー も、非推奨のオブジェクトの使用に対して診断メッセージを出します。

使い方:

from warnings import deprecated
from typing import overload

@deprecated("Use B instead")
class A:
    pass

@deprecated("Use g instead")
def f():
    pass

@overload
@deprecated("int support is deprecated")
def g(x: int) -> int: ...
@overload
def g(x: str) -> int: ...

非推奨のオブジェクトを使ったときに、category で指定した警告を実行時に発します。 関数の場合は呼び出し時、クラスの場合はインスタンス化時とサブクラスの作成時に発します。 category が None の場合、実行時の警告は発しません。 stacklevel は警告の発生箇所を決めます。 1 (デフォルト) の場合、非推奨のオブジェクトを直接呼び出した箇所で警告を発します。 値を大きくすると、スタック上でより上位の箇所になります。 category と stacklevel 引数は、静的型チェッカーの動作には影響しません。

The deprecation message passed to the decorator is saved in the __deprecated__ attribute on the decorated object. If applied to an overload, the decorator must be after the @~typing.overload decorator for the attribute to exist on the overload as returned by typing.get_overloads().

Added in version 3.13: PEP 702 を参照してください。

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

class warnings.catch_warnings(*, record=False, module=None, action=None, category=Warning, lineno=0, append=False)

A context manager that copies and, upon exit, restores the warnings filter and the showwarning() function. If the record argument is False (the default) the context manager returns None on entry. If record is True, a list is returned that is progressively populated with objects as seen by a custom showwarning() function (which also suppresses output to sys.stderr). Each object in the list is guaranteed to have the following attributes:

  • message: the warning message (an instance of Warning)

  • category: the warning category (a subclass of Warning)

  • filename: the file name where the warning occurred (str)

  • lineno: the line number in the file (int)

  • file: the file object used for output (if any), or None

  • line: the line of source code (if available), or None

  • source: the original object that generated the warning (if available), or None

バージョン 3.6 で変更: The source attribute was added.

The type of these objects is not specified and may change; only the presence of these attributes is guaranteed.

module 引数は、保護したいフィルタを持つモジュールを取ります。 warnings を import して得られるモジュールの代わりに利用されます。この引数は、主に warnings モジュール自体をテストする目的で追加されました。

action 引数が None でない場合、残りの引数を simplefilter() に渡し、コンテキストに入った直後に呼び出した場合と同じ処理を行います。

category と lineno パラメータの意味は 警告フィルタ を参照してください。

注釈

The catch_warnings manager works by replacing and then later restoring the module's showwarning() function and internal list of filter specifications. This means the context manager is modifying global state and therefore is not thread-safe.

バージョン 3.11 で変更: action、category、lineno、append パラメータが追加されました。