pytestで無害なwarningsを隠してオールグリーンとする手続きを備忘録として書いてみた

pytestにて大量にwarningsがでた場合に、利用しているモジュールが発生させていて且つ害がなく対処不要というケースもあります。放置するのもありですが、オールグリーンにしたかったのでフィルタを掛けてみました。
2021.08.03

テストケースは出来る限りグリーンを保ちたいところですが、利用しているライブラリの実装によっては頭を抱えることもあります。例えば以下のケース。

python3.7/site-packages/flake8/plugins/manager.py:254: DeprecationWarning: SelectableGroups dict interface is deprecated. Use select.
    eps = importlib_metadata.entry_points().get(self.namespace, ())

 -- Docs: https://docs.pytest.org/en/stable/warnings.html

flake8内で実行している関数がDeprecatedになっており、且つテストでは常に呼び出されるために、テスト用ライブラリ自身がwarningsを大量に生み出します。

% pytest --flake8 --cache-clear -vv
..
============== 44 passed, 32 warnings in 3.64s =========

無視しても問題ないと分かっているwarningsは出来る限りテスト結果から除外したいものです。出力されたwarningsを除外する手続きについて備忘録として書いてみました。

warningsの出どころを確認する

まずは出どころとなるモジュールを確認しましょう。リポジトリ内を検索することは勿論、ものによってはrelease noteに注意書きが掲載されていることもあります。

上記の importlib_metadata の場合は以下の記載にて対処方法も併記されています。

Use of Mapping (dict) interfaces on SelectableGroups is now flagged as deprecated. Instead, users are advised to use the select interface for future compatibility. Suppress the warning with this filter: ignore:SelectableGroups dict interface.

除外すべきか判断する

基本は解消すべきです。長く更新されていないライブラリであればforkして修正するのも手です。ものによっては後継ライブラリを使うことで解消される場合もあります。

ただ、Deprecatedになっているが利用していても問題はなく、且つ代替手段が提供されていないのであれば除外するのもありでしょう。

除外方法

pytestを実行してエラーログを確認します。

flake8/plugins/manager.py:254: DeprecationWarning: SelectableGroups dict interface is deprecated. Use select.

次にエラーの出力元を探し出してメッセージを抜き出します。今回は以下の処理。メッセージは除外処理に正規表現として判定されるため、メッセージ末尾が微妙に異なるパターンを纏めて除外したい場合は前方一致にするのも手です。

    _warn = functools.partial(
        warnings.warn,
        "SelectableGroups dict interface is deprecated. Use select.",
        DeprecationWarning,
        stacklevel=pypy_partial(2),

SelectableGroups dict interface is deprecated. Use select.

除外アクションとして ignore: を付けます。pytest内でフィルタとして判定される構成に従い、ignore:<MESSAGE> となります

    parts = arg.split(":")
    if len(parts) > 5:
        raise warnings._OptionError(f"too many fields (max 5): {arg!r}")
    while len(parts) < 5:
        parts.append("")
    action_, message, category_, module, lineno_ = (s.strip() for s in parts)

ignore:SelectableGroups dict interface

pytest.iniに追記する際にメッセージを括る必要はありません。複数の異なるログを対象にしたい場合は複数行の記載となります。

[pytest]
filterwarnings =
  ignore:SelectableGroups dict interface
  ignore:Test
% pytest --flake8 --cache-clear -vv
..
================= 44 passed in 3.97s ===============

あとがき

フィルタを掛けることで目にする機会がなくなる分、気づかぬうちにwarningsによる二次被害の発生もありえます。単に対処が面倒という理由でのフィルタは避けましょう。