実行時に実際に読み込んでいるモジュールを列挙する方法
大きな規模のプロジェクトにはそのまま適応しにくいですが、
(動的インポートを網羅するのは、カバレッジ100%のテストでもないと困難)
何かの役に立てばと思い投稿しておきます。
python
1# logging_loaded_packages.py
2
3import sys
4import atexit
5
6@atexit.register # プログラム終了時に呼び出す
7def logging_laoded_packages():
8 pkg_names = set()
9 for name, module in sys.modules:
10 if hasattr(module, "__file__") and "site-packages" in module.__file__:
11 pkg_names.add(name.split(".")[0])
12 for name in pkg_names:
13 print(name)
14
15
16if __name__ == "__main__":
17 import unused_module
18
19 # 適当な実在しないモジュールです。
20 # 動的に調べる場合、実行されない部分は検出できない。
21 # 例えば、各モジュールの __main__ 内で import がある場合、
22 # 全てのモジュールを実行する必要がある等、手間が増えます。
python
1import logging_loaded_packages
2
3__import__("discord")
4
5# 単純なテキスト検索では検出が難しい例: 複数行にまたがる場合
6# import os, sys, path, \
7# discord
出力結果(例
idna
yarl
aiohttp
attr
discord
websockets
chardet
multidict
async_timeout
discord.pyのrequirements.txt に書かれている
直接依存してるパッケージは2つ。
aiohttp>=3.6.0,<3.7.0
websockets>=6.0,!=7.0,!=8.0,!=8.0.1,<9.0
deptree による依存関係出力
discord==1.0.1 # discord
discord.py==1.3.2 # discord.py>=1.0.1
aiohttp==3.6.2 # aiohttp<3.7.0,>=3.6.0
async-timeout==3.0.1 # async-timeout<4.0,>=3.0
attrs==19.3.0 # attrs>=17.3.0
chardet==3.0.4 # chardet<4.0,>=2.0
multidict==4.7.5 # multidict<5.0,>=4.5
yarl==1.4.2 # yarl<2.0,>=1.0
idna==2.9 # idna>=2.0
multidict==4.7.5 # multidict>=4.0
websockets==8.1 # websockets!=7.0,!=8.0,!=8.0.1,<9.0,>=6.0
動的インポートを調べるのが困難なケース:
- 例えば、開発版とリリース版で異なるデータベースを使っている場合。両方の環境で調べる必要がある。
- GUIプログラムで、プラットフォーム毎に異なる依存がある場合。
他にも考えられますが、
一方で大多数の一般的なパッケージには import 文で利用しているはずなので、
deptree で得られた依存関係の親のパッケージ名(プロジェクトが直接importしているもの)
のみに検索する候補を絞り込み、手作業での作業量を少しでも減らす方法も考えられます。