🔕

Pythonスクリプト内で動的にライブラリをインストールする際に警告ログを一切出力させない

2023/11/23に公開

確認環境

コード

requestsの例

dynamic_install.py
import importlib
import pip._internal.cli.main as cli_main

name: str = "requests"
version: str = "2.29.0"
try:
    importlib.import_module(name)
except ImportError:
    cli_main(
        [
            "install",
            f"{name}=={version}",
            "-q",
            "--disable-pip-version-check",
            "--no-python-version-warning",
            "--no-warn-script-location",
            "--no-warn-conflicts",
            "--root-user-action",
            "ignore",
        ]
    )

import requests

内容

mainの引数は下記の通り

-q, --quiet
Give less output. Option is additive, and can be used up to 3 times (corresponding to WARNING, ERROR, and CRITICAL logging levels).

--disable-pip-version-check
Don’t periodically check PyPI to determine whether a new version of pip is available for download. Implied with --no-index.

--no-python-version-warning
Silence deprecation warnings for upcoming unsupported Pythons.

--no-warn-script-location
Do not warn when installing scripts outside PATH

--no-warn-conflicts
Do not warn about broken dependencies

--root-user-action <root_user_action>
Action if pip is run as a root user. By default, a warning message is shown.

root-user-actionについては仕様で明記されていなかったが、以下コードで選択肢が定義されている。

site-packages/pip/_internal/cli/cmdoptions.py
root_user_action: Callable[..., Option] = partial(
    Option,
    "--root-user-action",
    dest="root_user_action",
    default="warn",
    choices=["warn", "ignore"],
    help="Action if pip is run as a root user. By default, a warning message is shown.",
)

他に警告ログの出る条件があるかは未確認。都度site-packages/pip/_internalあたりを見れば抑制できるはず。
エラーログについては何もしていない。

importlib.import_moduleの戻り値はtypes.ModuleTypeとなっているが、例えばこの戻り値を変数名「requests」としてしまえばrequestsモジュールとして.post()などを呼ぶことはできる。
ただしこうすると開発時にVSCode等の拡張機能が本当のrequestsモジュールとしては認識してくれずやりにくいため、最後にimport requestsをしている。

pip._internal.cli.mainについて

通常はpip.mainを呼び出すべできであるが、実際にはこの中ではpip._internal.utils.entrypoints._wrapperが呼ばれていて、ここで無条件で強制的に以下のような警告を標準エラーへ出力するような処理が入っている。

WARNING: pip is being invoked by an old script wrapper. This will fail in a future version of pip.
Please see https://github.com/pypa/pip/issues/5599 for advice on fixing the underlying issue.
To avoid this problem you can invoke Python with '-m pip' instead of running pip directly.

この点については上記issueのURLの通りである。詳細未確認。

pip._internal.utils.entrypoints._wrapperの中では実際には現状pip._internal.cli.mainを呼び出しているだけであったため、一切ログを出したくない場合の回避策として直接pip._internal.cli.mainを呼ぶようにしているのが上記コードである。
ただし、よく読んではいないがこの方法はおそらくissueの議論を完全に無視していることになっているはずであり、将来的には変更される可能性も十分あるので適切な方法とは言えない。

Discussion