Pipenv の Pipfile と steup.py の依存関係定義の比較・同期する方法

## 注意

現在、Python のパッケージングに関する設定は `setup.py` には定義せず、
`pyproject.toml` に定義することが主流になりつつあります。

Python 3.6 以下をサポートするなどの理由で
どうしても `setup.py` にパッケージングの設定を定義しなければいけない、など
特別な事情がない限りは、パッケージングの設定は `pyproject.toml` に移行することをお奨めします。

ただし、2023-04-17 現在、
`Pipfile` と `pyproject.toml` の依存関係の設定を同期したり確認したりする方法は見つけられませんでした。
`Pipfile` を更新する都度、手作業で `pyproject.toml` に設定を書き写す必要があることに注意します。

また、上記のような理由で、今後の Python パッケージの新バージョンは急速に Python 3.6 以下に非対応になっていく可能性があります。
万一、まだ Python 3.6 以下を利用している場合は、早急に Python のバージョンアップを行うことをお奨めします。

## 事前の設定

[pipenv-setup] を使います:

[pipenv-setup · PyPI]

```console
pipenv install --dev pipenv-setup
```

`pipenv-setup` には `Pipfile` や `Pipfile.lock` の設定を `setup.py` に同期する機能があります。(後述)
この機能は同時に `setup.py` のフォーマット (自動整形) も行います。
そのときに使うフォーマッターを [black] か [autopep8] から選択して、依存関係として一緒にインストールすることができます:

```console
pipenv install --dev "pipenv-setup[black]"  # または: pipenv-setup[autopep8]
```

コーディング規約などで特段の定めがない限り、[black] を使うことをお勧めします。

参考: 2023-04-17 現在の GitHub Star 数の比較:

フォーマッター|GitHub Star 数
---|---
[black]|32,021+
[autopep8]|4,321+

## 手順

### 1\. まず、ローカルで `Pipfile` と `setup.py` を比較します

```console
pipenv run pipenv-setup check --strict
```

#### ポイント: `--strict` で同一のバージョン要件のみを許可します

デフォルトでは、`pipenv-setup` チェックは、
`setup.py` が指定するバージョンが `Pipfile` の範囲内である場合にパスします。
たとえば、次がそのようなケースです:

- `Pipfile`: `django~=1.1`
- `setup.py`: `django==1.2`

`--strict` を指定すると、同一の要件のみを許可します。
つまり、上記のように `Pipfile`: `django~=1.1` の場合、`setup.py` は `django>=1.1,<2.0` となっている必要があります。

### 2\. 問題がある場合は同期します

```console
pipenv run pipenv-setup sync --pipfile
```

#### ポイント: `--pipfile` で `Pipfile.lock` ではなく、`Pipfile` に合わせて `setup.py` を更新します

デフォルトでは、`pipenv-setup` は `Pipfile.lock` に合わせて `setup.py` を更新します。
`--pipfile` を指定すると、`Pipfile` に合わせて `setup.py` を更新します。
要件に合わせて選択していただく必要がありますが、
`setup.py` に依存関係を定義するということは、多くの場合、パッケージ開発が目的であり、
依存関係にはある程度の幅を持たせたいと考えられますので、
`--pipfile` の指定が必要となる場合が多いと考えられます。

### 3\. CI にチェックを追加します

GitHub Actions を例に解説します。

#### GitHub Actions の基本

GitHub Actions では、CI のためのワークフローを、
リポジトリーのプロジェクト内の `.github/workflows/` に YAML ファイルとして定義します。

参考: [ワークフローについて - GitHub Docs]

#### ワークフロー定義の例

例えば、`.github/workflows/` に `check_setup.yml` を作成し、次のようなワークフローを定義します:

```yaml:check_setup.yml
on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main
jobs:
  check_setup:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-python@v4
        with:
          python-version: '3.11'
      - run: python -m pip install pipenv
      - run: python -m pipenv sync --dev
      - run: python -m pipenv run pipenv-setup check --strict
```

参考: [スクリプトを使ってランナーでコードをテストする - GitHub Docs]

## 長いコマンドを毎回入力するのが面倒な場合

本格的に開発のショートカット集を作る場合、[Invoke] などを使うのが良いのですが、
「ひとまず、さっと定義してしまいたい」ような場合、`Pipfile` にショートカットを定義できます。

例えば、次の定義を行います:

```toml:Pipfile
[scripts]
sync_setup = "pipenv-setup sync --pipfile"
check_setup = "pipenv-setup check --strict"
```

こうすると、コマンドが幾分短くなります:

```console
pipenv run sync_setup
pipenv run check_setup
```


[pipenv-setup]: https://pypi.org/project/pipenv-setup/
[pipenv-setup · PyPI]: https://pypi.org/project/pipenv-setup/
[black]: https://pypi.org/project/black/
[autopep8]: https://pypi.org/project/autopep8/
[ワークフローについて - GitHub Docs]: https://docs.github.com/ja/actions/using-workflows/about-workflows
[スクリプトを使ってランナーでコードをテストする - GitHub Docs]: https://docs.github.com/ja/actions/examples/using-scripts-to-test-your-code-on-a-runner
[Invoke]: https://pypi.org/project/invoke/