Pythonの依存パッケージとダウンロード先URL一覧をゲットする方法

# はじめに

仕事で Python パッケージの依存パッケージ一覧と、そのパッケージのダウンロード先URL一覧が必要になったのですが、取り出す方法がなかなか見つからなかったので、(もっといい方法がありそうですが...) 方法をメモします。

例として Python 3.8 の pandas の場合、依存パッケージは下記で

```
numpy==1.24.2
pandas==1.5.3
python-dateutil==2.8.2
pytz==2022.7.1
six==1.16.0
```

ダウンロード先は下のようになりました。

```
https://files.pythonhosted.org/packages/bf/8c/3d36cef521739bd481e9a5b30e5c0f9faf8b7fe7b904238368908a9d149d/numpy-1.24.2-cp38-cp38-win_amd64.whl
https://files.pythonhosted.org/packages/ca/4e/d18db7d5ff9d28264cd2a7e2499b8701108f0e6c698e382cfd5d20685c21/pandas-1.5.3-cp38-cp38-win_amd64.whl
https://files.pythonhosted.org/packages/36/7a/87837f39d0296e723bb9b62bbb257d0355c7f6128853c78955f57342a56d/python_dateutil-2.8.2-py2.py3-none-any.whl
https://files.pythonhosted.org/packages/2e/09/fbd3c46dce130958ee8e0090f910f1fe39e502cc5ba0aadca1e8a2b932e5/pytz-2022.7.1-py2.py3-none-any.whl
https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl
```

# 方法

## 1. requirements.txt を準備する

インストールしたいパッケージ名を書いた、requirements.txt を準備します。今回は例として、pandas と matplotlib とします。

```text:requirements.txt
pandas
matplotlib
```

## 2. venv環境を構築する

パッケージの依存関係を手っ取り早く把握するために、パッケージを一度インストールします。ローカル環境の Python に直接インストールすると、依存関係がよくわからなくなるので、venv の仮想環境を作成します。

```shell
$ python -m venv .venv
```

**注意**
Pythonはマイナーバージョン（例えば3.8と3.9など）が異なっているとインストールできないパッケージがあるため、パッケージを使用する環境のPythonバージョンを使用してください。複数のバージョンの Python がインストールされている場合は、以下のように使用するバージョンを切り替えることができます。

```shell
$ py -3.8 -m venv .venv
```

## 3. パッケージをインストールする

まず venv 環境の中に入ります（使っているターミナル環境によって、コマンドが違うので注意）。

Windows コマンドプロンプト

```cmd
> .venv\Scripts\activate.bat
```

Linux, Mac, Git-Bash

```shell
$ source .venv/Scripts/activate
```

venv 環境に入ったあと `pip freeze` でなにもインストールされていないことを確認してから、

```shell
$ pip freeze
# なにも表示されない
```

`pip install` でパッケージをインストールします。

```shell
$ pip install -r requirements.txt
```

この時点で、依存関係のあるパッケージが自動的にインストールされます。

```shell
$ pip freeze
contourpy==1.0.7
cycler==0.11.0
fonttools==4.38.0
kiwisolver==1.4.4
matplotlib==3.6.3
numpy==1.24.2
packaging==23.0
pandas==1.5.3
Pillow==9.4.0
pyparsing==3.0.9
python-dateutil==2.8.2
pytz==2022.7.1
six==1.16.0
```

## 4. ダウンロード先URL一覧を取得する

ここから `https://pypi.org/pypi/` のAPIからダウンロード先一覧を取得しますが、その際にパッケージファイル名が必要なので、パッケージファイルをダウンロードします。

```shell
$ pip freeze > packages.txt
$ pip download -d src -r packages.txt
```

これで、パッケージ一覧 (`packages.txt`) とパッケージファイル一式 (`src`) が得られたので、以下のスクリプトを叩いてください。

**注意**
venv 環境に requests が入っていない場合、ここでエラーが出るので、一度 `deactivate` で venv 環境を出てrequestsをインストールしたローカル環境で実行するか、あらかじめ 1.で作成する requirements.txt に requests を入れた状態で再度実行してください。

```python
import requests
import json
import os

with open('packages.txt') as f:
    packages = f.read().split('\n')

# パッケージファイル名を取得する
file_names = os.listdir('./src')

with open('urls.txt', 'w') as f:
    for package in packages:
        # numpy==1.24.2 などと入ってくるので、パッケージ名、バージョンに分ける
        data = package.split('==')
        if len(data) < 2:
            # バージョンが指定されていないと正しく取り出せないのでエラー
            break
        # pypi.org からパッケージ情報を取り出す
        pypi_url = f'https://pypi.org/pypi/{data[0]}/{data[1]}/json'
        response = requests.get(pypi_url)
        # url情報を取り出す
        response_json = json.loads(response.text)
        urls = response_json['urls']
        for url in urls:
            # ファイル名の並び順が違う場合があるので、順番にチェック
            for file in file_names:
                if url['filename'] == file:
                    # ファイル名が一致した場合のurl情報を取り出す
                    print(url['url'])
                    f.write(url['url']+ '\n')
```

これで url一覧が書かれた，`urls.txt` ファイルが生成されます。

## 5. 最後に

途中で作成した `src` と `.venv` フォルダを削除してください（残っていると、次に調べるときに余計なパッケージが混ざります）。

## 参考

* [venv: Python 仮想環境管理](https://qiita.com/fiftystorm36/items/b2fd47cf32c7694adc2e)