29.5. "warnings" --- 警告の制御
*******************************

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

======================================================================

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

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

警告メッセージは通常 "sys.stderr" に出力されますが、その処理方法は柔軟
に変更することができます。すべての警告を無視することも、警告を例外に変
更することもできます。警告の処理方法は警告カテゴリ (以下参照)、警告メ
ッセージテキスト、そして警告を発したソースコード上の場所に基づいて変更
することができます。ソースコード上の同じ場所に対して特定の警告が繰り返
された場合、通常は抑制されます。

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

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

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

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


29.5.1. 警告カテゴリ
====================

警告カテゴリを表現する組み込み例外は数多くあります。このカテゴリ化は警
告をグループごとフィルタする上で便利です。現在以下の警告カテゴリクラス
が定義されています:

+------------------------------------+-------------------------------------------------+
| Class                              | 説明                                            |
|====================================|=================================================|
| "Warning"                          | すべての警告カテゴリクラスの基底クラスです。    |
|                                    | "Exception" のサブクラス です。                 |
+------------------------------------+-------------------------------------------------+
| "UserWarning"                      | "warn()" の標準のカテゴリです。                 |
+------------------------------------+-------------------------------------------------+
| "DeprecationWarning"               | その機能が廃止されていることを示す警告カテゴリ  |
|                                    | の基底クラスです (デフォ ルトでは無視されます)  |
|                                    | 。                                              |
+------------------------------------+-------------------------------------------------+
| "SyntaxWarning"                    | その文法機能があいまいであることを示す警告カテ  |
|                                    | ゴリの基底クラスです。                          |
+------------------------------------+-------------------------------------------------+
| "RuntimeWarning"                   | そのランタイム機能があいまいであることを示す警  |
|                                    | 告カテゴリの基底クラスで す。                   |
+------------------------------------+-------------------------------------------------+
| "FutureWarning"                    | その構文の意味付けが将来変更される予定であるこ  |
|                                    | とを示す警告カテゴリの基 底クラスです。         |
+------------------------------------+-------------------------------------------------+
| "PendingDeprecationWarning"        | 将来その機能が廃止されることを示す警告カテゴリ  |
|                                    | の基底クラスです(デフォ ルトでは無視されます)。 |
+------------------------------------+-------------------------------------------------+
| "ImportWarning"                    | モジュールのインポート処理中に引き起こされる警  |
|                                    | 告カテゴリの基底クラスで す(デフォルトでは無視  |
|                                    | されます)。                                     |
+------------------------------------+-------------------------------------------------+
| "UnicodeWarning"                   | Unicode に関係した警告カテゴリの基底クラスです  |
|                                    | 。                                              |
+------------------------------------+-------------------------------------------------+
| "BytesWarning"                     | "bytes" や "bytearray" に関連した警告カテゴリの |
|                                    | 基底クラスです。                                |
+------------------------------------+-------------------------------------------------+
| "ResourceWarning"                  | リソースの使用に関連した警告カテゴリの基底クラ  |
|                                    | スです。                                        |
+------------------------------------+-------------------------------------------------+

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

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


29.5.2. 警告フィルタ
====================

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

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

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

  +-----------------+------------------------------------------------+
  | 値              | 処理方法                                       |
  |=================|================================================|
  | ""error""       | 一致した警告を例外に変えます                   |
  +-----------------+------------------------------------------------+
  | ""ignore""      | 一致した警告を出力しません                     |
  +-----------------+------------------------------------------------+
  | ""always""      | 一致した警告を常に出力します                   |
  +-----------------+------------------------------------------------+
  | ""default""     | 一致した警告のうち、警告の原因になったソースコ |
  |                 | ード上の場所ごとに、最 初の警告のみ出力します  |
  +-----------------+------------------------------------------------+
  | ""module""      | 一致した警告のうち、警告の原因になったモジュー |
  |                 | ルごとに、最初の警告の み出力します            |
  +-----------------+------------------------------------------------+
  | ""once""        | 一致した警告のうち、警告の原因になった場所にか |
  |                 | かわらず最初の警告のみ 出力します              |
  +-----------------+------------------------------------------------+

* *message* は正規表現を含む文字列で、警告メッセージの先頭はこのパター
  ンに一致しなければなりません。正規表現は常に大小文字の区別をしないよ
  うにコンパイルされます。

* *category* はクラス ("Warning" のサブクラス) です。警告クラスはこの
  クラスのサブクラスに一致しなければなりません。

* *module* は正規表現を含む文字列で、モジュール名はこのパターンに一致
  しなければなりません。正規表現は常に大小文字の区別をしないようにコン
  パイルされます。

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

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

警告フィルタは Python インタプリタのコマンドラインに渡される "-W" オプ
ションで初期化されます。インタプリタは "-W" オプションに渡されるすべて
の引数を "sys.warnoptions" に変換せずに保存します; "warnings" モジュー
ルは最初に "import" された際にこれらの引数を解釈します (無効なオプショ
ンは "sys.stderr" にメッセージを出力した上で無視されます)。


29.5.2.1. デフォルトの警告フィルタ
----------------------------------

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

* "DeprecationWarning", "PendingDeprecationWarning", "ImportWarning"
  は無視されます。

* "-b" オプションが1度か2度指定されない限り、 "BytesWarning" は無視さ
  れます。 "-b" の時は警告が表示され、 "-bb" の時は例外になります。

* "ResourceWarning" はPythonがデバッグモードでビルドされていなければ無
  視されます。

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


29.5.3. 一時的に警告を抑制する
==============================

廃止予定の関数など、警告を発生させることが分かっているコードを利用する
場合に、そのような警告を表示したくなければ、 "catch_warnings" コンテキ
ストマネージャーを使って警告を抑制することができます:

   import warnings

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

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

このサンプルのコンテキストマネージャーの中では、すべての警告が無視され
ています。これで、他の廃止予定のコードを含まない(つもりの)部分まで警告
を抑止せずに、廃止予定だと分かっているコードだけ警告を表示させないよう
にすることができます。注意: これが保証できるのはシングルスレッドのアプ
リケーションだけです。 2つ以上のスレッドが同時に "catch_warnings" コン
テキストマネージャーを使用した場合、動作は未定義です。


29.5.4. 警告のテスト
====================

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

コンテキストマネージャーが終了したら、警告フィルタはコンテキストマネー
ジャーに入る前のものに戻されます。これは、テスト中に予期しない方法で警
告フィルタが変更され、テスト結果が中途半端になる事を予防します。このモ
ジュールの "showwarning()" 関数も元の値に戻されます。注意: これが保証
できるのはシングルスレッドのアプリケーションだけです。 2つ以上のスレッ
ドが同時に "catch_warnings" コンテキストマネージャを使用した場合、動作
は未定義です。

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


29.5.5. コードを新しいバージョンの Python のために更新する
==========================================================

開発者にしか興味の無い警告はデフォルトでは無視されるようになりました。
なので、通常、コードをテストするときには無視されている例外を表示するよ
うにするべきです。これは "-Wd <-W>" コマンドライン引数 ("-W default"
の省略形) をインタプリタに指定することで可能です。これはデフォルトでは
無視されているものも含めた全ての警告に対して、デフォルトの動作を有効に
します。この動作を変更するためには、 "-W" への引数を変更します。例えば
、 "-W error" のようにします。何が可能かについての詳細は、 "-W" フラグ
を参照してください。

プログラムから "-Wd" と同じ事をするには、次のようにします:

   warnings.simplefilter('default')

このコードは可能な限り早く実行してください。そうすることで、どの警告を
発生させるかの登録が、将来の警告がどう扱われるかについて思わぬ影響を与
えることを避けることができます。

いくつかの警告がデフォルトで無視されているのは、開発者向けの警告をユー
ザーに見せることを避けるためです。ユーザーがどのインタプリタを使ってコ
ードを実行するのかを必ずしも制御できるわけではないので、自分のコードの
リリースサイクルの間に新しいバージョンの Python がリリースされるかもし
れません。新しいインタプリタは、古いインタプリタが出さなかった新しい警
告を発生させるかもしれません。例えば、利用しているモジュールに対して
"DeprecationWarning" が発生されることがあります。開発者としては、廃止
予定のモジュールを利用していることに対する通知は有益ですが、一般ユーザ
ーにとってはこの情報はノイズでしか無く、何の役にも立ちません。

"unittest" モジュールは 、テストを実行する際に "'default'" フィルタを
使用するように更新されました。


29.5.6. 利用可能な関数
======================

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

   警告を発するか、無視するか、あるいは例外を送出します。 *category*
   引数が与えられた場合、警告カテゴリクラスでなければなりません (上記
   を参照してください); 標準の値は "UserWarning" です。 *message* を
   "Warning" インスタンスで代用することもできますが、この場合
   *category* は無視され、 "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* が文字列のとき、 *category* は "Warning" の
   サブクラスでなければなりません。また *message* は "Warning" のイン
   スタンスであってもよく、この場合 *category* は無視されます。

   *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()" の呼び出しによる影響はすべて無効化されます。


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

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

   警告フィルタと "showwarning()" 関数をコピーし、終了時に復元するコン
   テキストマネージャーです。 *record* 引数が "False" (デフォルト値)だ
   った場合、コンテキスト開始時には "None" を返します。もし *record*
   が "True" だった場合、リストを返します。このリストにはカスタムの
   "showwarning()" 関数(この関数は同時に "sys.stdout" への出力を抑制し
   ます)によってオブジェクトが継続的に追加されます。リストの中の各オブ
   ジェクトは、 "showwarning()" 関数の引数と同じ名前の属性を持っていま
   す。

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

   注釈:

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