Pythonモジュールの一覧化方法いろいろ

# 1.この記事の内容

Pythonモジュール及びそのライセンスの一覧化を考える機会があり，調べた内容を記事に残します．  
Pythonモジュールの一覧化と一言で言っても，pipでインストールしたパッケージを一覧化する方法や，importされたモジュールを一覧化する方法，モジュール間の依存関係を図示する方法など，様々なやり方があることを知りました．

# 2.Pythonモジュールを一覧化する方法

実行環境含む参考コードは下記に登録しています．

https://github.com/ryoma-jp/samples/tree/master/python/module_list

本記事では，一覧化の方法と実行例，留意点等の概略を記載します．

## 2-1.pipでインストールしたモジュールの一覧化

```pipdeptree```でpipでインストールしたモジュールを依存関係を含めて一覧表示できます．

```pip```でインストールできます．

```
$ pip install pipdeptree
```

https://pypi.org/project/pipdeptree/

以下は実行結果の表示例です．

```
altair==4.2.0
  - entrypoints [required: Any, installed: 0.4]
  - jinja2 [required: Any, installed: 3.1.2]
    - MarkupSafe [required: >=2.0, installed: 2.1.1]
  - jsonschema [required: >=3.0, installed: 4.6.0]
    - attrs [required: >=17.4.0, installed: 21.4.0]
    - pyrsistent [required: >=0.14.0,!=0.17.2,!=0.17.1,!=0.17.0, installed: 0.18.1]
  - numpy [required: Any, installed: 1.22.4]
  - pandas [required: >=0.18, installed: 1.4.3]
    - numpy [required: >=1.21.0, installed: 1.22.4]
    - python-dateutil [required: >=2.8.1, installed: 2.8.2]
      - six [required: >=1.5, installed: 1.16.0]
    - pytz [required: >=2020.1, installed: 2022.1]
  - toolz [required: Any, installed: 0.11.2]
backports.functools-lru-cache==1.6.4
blinker==1.4
bokeh==2.4.3
  - Jinja2 [required: >=2.9, installed: 3.1.2]
    - MarkupSafe [required: >=2.0, installed: 2.1.1]
  - numpy [required: >=1.11.3, installed: 1.22.4]
  - packaging [required: >=16.8, installed: 21.3]
    - pyparsing [required: >=2.0.2,!=3.0.5, installed: 3.0.9]
  - pillow [required: >=7.1.0, installed: 9.1.1]
  - PyYAML [required: >=3.10, installed: 6.0]
  - tornado [required: >=5.1, installed: 6.1]
  - typing-extensions [required: >=3.10.0, installed: 4.2.0]
```

## 2-2.pipでインストールしたモジュールのライセンス一覧化

```pip-licenses```コマンドでモジュールのバージョン及びライセンスを一覧表示できます．

```pip```でインストールできます．

```
$ pip install pip-licenses
```

https://pypi.org/project/pip-licenses/

以下は実行結果の表示例です．

```
Name                           Version    License                                                          
 Babel                          2.10.3     BSD License                                                      
 Bottleneck                     1.3.4      BSD License                                                      
 Cython                         0.29.30    Apache Software License                                          
 HeapDict                       1.0.1      BSD License                                                      
 Jinja2                         3.1.2      BSD License                                                      
 Mako                           1.2.0      MIT License                                                      
 MarkupSafe                     2.1.1      BSD License                                                      
 Pillow                         9.1.1      Historical Permission Notice and Disclaimer (HPND)               
 PyJWT                          2.4.0      MIT License                                                      
 PySocks                        1.7.1      BSD                                                              
 PyWavelets                     1.3.0      MIT License                                             
```

## 2-3.Pythonコード実行中のimport済みモジュールの確認

```sys.modules```にimport済みのモジュールが辞書型で格納されます．

```
import sys
sys.modules
```

Pythonコード中で，```'<module名>' in sys.modules```とするなどで，特定のモジュールがimport済みであることを判定できます．


## 2-4.指定したPythonファイル内で使用されるモジュールの一覧化

Python標準の```modulefinder```モジュールで，importされるモジュールの一覧を取得することができます．  
ただし，原因は不明ですが，pandasやscikit-learnなど，読み込めないモジュールも存在するようです．  
読み込めないモジュールに対してmofulefinderを実行した場合は，AttributeErrorを出力して動作が停止します．

modulefinderの使用例は公式ドキュメントがわかりやすいです．

https://docs.python.org/ja/3/library/modulefinder.html#example-usage-of-modulefinder

## 2-5.指定したPythonファイルまたはディレクトリ内で使用されるモジュールの一覧化

```pydeps```コマンドを用いて，特定のPythonファイルまたはディレクトリを指定して，使用されるモジュールをグラフィカル表示できます．  
modulefinderと同様に，表示できないモジュールも存在するようです．

```pip```でインストールできます．

```
$ pip install pydeps
```

複雑な依存関係を持つPythonファイルに対しては動作確認していませんが，下記のようなグラフを生成することができます．

* 実行コマンド例
  ```
  $ pydeps --noshow -T png -o test_numpy.png lib/sample_module/test_numpy.py
  ```
* 実行結果
![test_numpy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/983907/70772040-0b29-8f3b-5e1e-5242ef6385a0.png)


なお，ディレクトリを指定する場合は，指定したディレクトリ内に```__init__.py```が必要なようです．


# 3.関連リンク

* [【Python】制作物を商用利用・配布する場合のライセンスの取り扱い](https://office54.net/python/license/python-license-psfl)
* [Pythonパッケージの依存関係とライセンスを確認する](https://dev.classmethod.jp/articles/python-pipdeptree_licenses/)
* [pythonモジュールがimport済みかどうかを確認する方法](https://qiita.com/genchi-jin/items/b72d62ffef3091ee86e7)
* [pythonの依存関係解析ツール、pydepsを使う](https://tech.mntsq.co.jp/entry/2021/03/19/120325)
* [modulefinder --- スクリプト中で使われているモジュールを検索する](https://docs.python.org/ja/3/library/modulefinder.html)