【Python】pip install できる独自のプライベートリポジトリをお手軽に立てる

Pythonのパッケージ管理に使うpipコマンドはデフォルトでは https://pypi.org/ からパッケージをダウンロードします。しかしpipではこれ以外のリポジトリを追加することができ、この機能を使うことで自分しか使わないパッケージを独自のリポジトリに配置してそこからpipでインストールできるようにすることが可能です。本稿ではその方法を解説します。

独自のリポジトリを作る方法はいろいろあるようですが、単にパッケージ名（とバージョン）を指定して `pip install` できるようにするだけならとても簡単にできます。**必要なものは Nginx 等の静的ウェブサーバだけ** です。

# 1. 配布パッケージを作成する
Pythonのモジュール群を`.tar.gz`で圧縮された配布パッケージにします。この辺りはググれば出てくるので経験がなければ他の記事も参考にしながら行ってください。ここではモジュールのディレクトリ構造や `__init__.py` の話等、触れてないことも多いので。`python setup.py sdist` で行うのが現時点でも主流なのでそのキーワードでググればたくさん出てきます。

ここでは `setup.py sdist` を使わない、これから主流になるであろう新しいやり方でやります。必要なファイルは2つ、`./pyproject.toml` と `./setup.py` です。`./setup.py` は過去の方法との互換性が目的で、いらないかもしれません。それぞれの中身は以下のようにします。

```toml:./pyproject.toml
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"

[project]
name = "packageA"
version = "1.0.0"
description = "パッケージの説明"
dependencies = ["numpy", "requests"]
```

```py:./setup.py
from setuptools import setup

setup()
```

`./setup.py` の中身は固定でいじることはありません。`./pyproject.toml` において編集が必要な重要な項目は `[project]` セクションの中の `name` 、 `version` 、 `dependencies` です。それぞれパッケージの名前、バージョン、依存するパッケージリストです。依存するパッケージのリストはこのパッケージがインストールされる時に同時にインストールしてくれます。

配布パッケージファイルを生成するには `build` というパッケージがいるのでインストールします。

```console
$ pip install build
```

この `build` を使って配布パッケージファイルを生成します。

```console
$ python -m build
```

実行すると `./dist/` ディレクトリ以下に `packageA-1.0.0.tar.gz` というファイルが生成されます。これが配布パッケージファイルです。

# 2. 静的ウェブサーバを用意

NginxでもApacheでもなんでもいいのでウェブサーバを用意し、ローカルのディレクトリ内をHTTPで公開するようにします。そして重要なのはディレクトリ(`/`で終わるURL)にアクセスしたときに、**ディレクトリ内のディレクトリやファイルのリストを自動で生成して返す機能をオンにします**。Nginxなら`autoindex on;`がこれにあたります。Apacheはデフォルトでオンだったと思います。

以下の例ではNginxをDockerで立てており、`./public/`ディレクトリ以下が公開されます。

```yaml:./compose.yaml
services:
  web:
    image: nginx
    volumes:
      - "./nginx-default.conf:/etc/nginx/conf.d/default.conf:ro"
      - "./public/:/usr/share/nginx/html:ro"
    ports:
      - "80:80"
```

```nginx:./nginx-default.conf
server {
    listen       80;

    location / {
        alias   /usr/share/nginx/html/;
	    autoindex on;
    }
}
```

# 3. 配布パッケージを配置
公開したディレクトリ内に規定のディレクトリ構造で配布パッケージを配置します。そうすることで `pip install` で扱えるリポジトリとなります。規定のディレクトリ構造とは **パッケージ名のディレクトリの下に配布パッケージファイルを置く** だけです。例えばpackageAとpackageBという名前のパッケージをバージョンの違いで複数公開するなら、

```:./public/のディレクトリ構造
+ packageA + packageA-1.0.0.tar.gz
|          + packageA-1.0.1.tar.gz
|          + packageA-2.0.0.tar.gz
+ packageB + packageB-1.0.0.tar.gz
           + packageB-1.1.0.tar.gz
```

といった感じです。`.tar.gz`のパッケージファイルの名前は生成した時のまま変えないようにします。

これでリポジトリを立てられました。

# 4. 立てたリポジトリを使って`pip install`
立てたリポジトリ内のパッケージを `pip install` するには `--extra-index-url` オプションを使います。オプションの引数には立てたリポジトリのURLを指定します。例えば `https://example.net/pypi/` 以下に配置されたパッケージ `packageA` のバージョン1.0.1をインストールするなら、

```console
$ pip install --extra-index-url https://example.net/pypi/ packageA==1.0.1
```

のようになります。

上の例はhttpsでしたが、httpだとおそらくエラーになります。その場合は `--trusted-host example.net` のように `--trusted-host` オプションを追加します。

オプションを毎回書くのが面倒な場合は `pip.conf` ファイル内に設定を書いておくこともできます。`pip.conf` の配置場所は仮想環境を使っているなら `$VIRTUAL_ENV/pip.conf` です。

```ini:./env/pip.conf
[global]
extra-index-url = http://example.net/
trusted-host = example.net
```

# あとがき
ググるとなんか複雑なことしてる記事が多かったので書いた記事。おそらく検索とか配布パッケージのアップロードをコマンドラインからやるとかしたいなら、特別なソフトがいるのだと思うが、単にパッケージ名を指定してインストールできれば良いだけならすごく簡単にできるよという話。