チームでの開発環境を整える

# 始めに

複数人数でPythonを用いた小規模開発をすることになりました。
今まではデータ集計/分析のために一人でPythonを用いていただけなので、Python/ライブラリバージョン、書き方の統一について意識していませんでした。
ということで、上記事項について調べて実行してみました。



# PC環境

- OS : Windows 10 Home 64bit
- WSL2 : Ubuntu 20.04
- IDE : VSCode

**VSCode**を用いて**WSL2上のUbuntu 20.04**で**Python3**を使った開発を行うことを目指します。



# Pythonバージョン

[pyenv](https://github.com/pyenv/pyenv)であらゆるPythonバージョンへ切り替えられるように設定します。

## pyenv導入


まず初めに[正常なビルド環境の為の推奨コマンド](https://github.com/pyenv/pyenv/wiki#suggested-build-environment)を実行
```bash
sudo apt-get update ; sudo apt-get install make build-essential libssl-dev zlib1g-dev \
libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm \
libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev
```

### インストール

インストールしたいディレクトリで[コマンド](https://github.com/pyenv/pyenv#basic-github-checkout)を実行（ホームディレクトリ直下が好ましいとのこと）

```
git clone https://github.com/pyenv/pyenv.git ~/.pyenv
```

以下を実行するとpyenvを高速化できるみたいです。

```
cd ~/.pyenv && src/configure && make -C src
```

次に以下のコマンドを実行

```
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(pyenv init --path)"' >> ~/.bashrc
echo 'eval "$(pyenv init -)"' >> ~/.bashrc
```

再起動して`pienv -v`

```
pyenv 2.2.5-11-gf0f2cdd1
```
バージョンが表示されたらOK



### Pythonバージョンインストール

3.7.12と3.9.11を入れてみます。

```
pyenv install 3.9.11
pyenv install 3.7.12
```

pyenvで使用できるpythonのバージョン一覧を見る

```
pyenv versions
```

pyenvで使用するpythonのバージョンを選択する

```
pyenv local 3.9.11
```
![SnapCrab_NoName_2022-4-16_13-37-41_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635079/9b7d0158-3978-698a-0ccd-018f59c7e4a3.png)
切り替えできました

# ライブラリバージョン

[poetry](https://python-poetry.org/)でPythonライブラリのバージョンを管理します。
## poetry導入

### インストール
[公式マニュアル](https://python-poetry.org/docs/)

以下のコマンドを実行してインストール

```
curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python -
```

再起動して`poetry —version`

```
Poetry version 1.1.13
```


### プロジェクトの設定

[公式マニュアル](https://python-poetry.org/docs/basic-usage/)

プロジェクトのディレクトリ下で、poetry.tomlを作成する為以下のコマンドを打ちます。

```bash
poetry init
```

途中、バージョン・説明・著者・ライセンス・適応したPythonバージョンを記載できます。


```bash
Version [0.1.0]:  
Description []:  
Author [None, n to skip]: 
License []:  
Compatible Python versions [^3.9]: 
```

「ライブラリに関する依存関係について、今定義したいですか？」

```bash
Would you like to define your main dependencies interactively? (yes/no) [yes] 
```

「開発用ライブラリに関する依存関係について、今定義したいですか？」

```bash
Would you like to define your development dependencies interactively? (yes/no) [yes]
```

「記入した内容で作成しますが良いですか？」

```bash
Do you confirm generation? (yes/no) [yes]
```

yesを押すと`pyproject.toml`ファイルが作成されます。

![SnapCrab_NoName_2022-4-16_14-25-43_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635079/0c291dba-70d1-fa75-9369-ff3570bfb3c1.png)


`poetry add`でpyproject.tomlに要求したパッケージを追加し、インストールできます。

```bash
poetry add tweepy
```

その他コマンドについては[こちら](https://cocoatomo.github.io/poetry-ja/cli/#_1)

### 仮想環境ディレクトリ設定

poetryの仮想環境をプロジェクトディレクトリ直下に作成するように設定を変更します。

- 参考にしたページ
    - [PoetryをVSCode向けに設定する](https://blog.mktia.com/poetry-configuration-for-vscode/)
    - [Poetry の virtualenv を VSCode に認識させる](https://zenn.dev/takanori_is/articles/let-poetry-create-virtualenv-under-project-folder)

まずはプロジェクトディレクトリから以下を打ち込み環境名をチェック

```bash
poetry env list
```

次に以下のコマンドを打ち込む

```bash
poetry config virtualenvs.in-project true --local
```

「環境名」に`poetry env list`で出てきた環境名を打ち込んで実行

```bash
poetry env remove 環境名
```

再度環境をインストール

```bash
poetry install
```

すると、プロジェクトディレクトリ直下に仮想環境データが置かれるようになります。
`.gitignore`ファイルも自動で作られるため、Gitのトラッキングからは除外されます。

![SnapCrab_NoName_2022-4-17_20-16-0_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635079/735826cd-706e-55f5-19d9-926ebe57beb4.png)

# フォーマッター


- 参考にしたページ
    - [Pythonのコードフォーマッターについての個人的ベストプラクティス](https://qiita.com/sin9270/items/85e2dab4c0144c79987d)

## black,isort

[black](https://github.com/psf/black)と[isort](https://github.com/PyCQA/isort)を使ってみます

### インストール

```bash
poetry add black
poetry add isort
```

### pyproject.toml設定

1行の最大文字数設定を88から119へ変更したいので設定します。
[blackとisortを同じく使う時](https://pycqa.github.io/isort/docs/configuration/black_compatibility.html)は、競合を避けるためpyproject.tomlに`profile = “black”`と記入します。

```
[tool.black]
line-length = 119

[tool.isort]
profile = "black"
```

# リンター

- 参考にしたページ
    - [Pythonのコードフォーマッターについての個人的ベストプラクティス](https://qiita.com/sin9270/items/85e2dab4c0144c79987d)
    - [flake8の設定をpyproject.tomlに統合する](https://qiita.com/que9/items/7cf9f992b8decb4265c1)
[フォーマッター](#フォーマッター)と同じ記事を参考にしました

## flake8

[flake8](https://github.com/PyCQA/flake8)を使ってみます。
flake8の設定をpyproject.tomlへ統合するには[pyproject-flake8](https://github.com/csachs/pyproject-flake8)を使うと良いみたいです。


### インストール

`-D`コマンドで開発用の依存関係としてパッケージを追加します。

```
poetry add -D pyproject-flake8
```

### pyproject.toml設定

[blackとflake8を使う場合](https://black.readthedocs.io/en/stable/guides/using_black_with_other_tools.html#flake8)は、以下のように設定します。

- `max-line-length`はblackの`line-length`と合わせる
- `exclude = “.venv”`
    - poetryの仮想環境データの内容はチェックしないようにするため。


```
[tool.flake8]
max-line-length = 119
extend-ignore = E203
exclude = ".venv"
```

※`exclude = “.venv”`にチェックを入れずにGithub Actionsでflake8のチェックを走らせてしまった図（とても時間掛かります）
![SnapCrab_NoName_2022-4-17_16-22-44_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635079/51c2dab1-efca-a43c-37d6-e8c96704f2dc.png)


### VSCode settings.json設定

VSCodeのsettings.jsonを以下のように編集します。
[後述](#vscode)しますRemote-WSLの`settings.json`が対象です。

![SnapCrab_NoName_2022-4-17_20-2-37_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635079/a579d5cf-6dd2-dbe7-78f7-b4b75156e14d.png)

```:json
{
    "python.linting.enabled": true,
    "python.linting.pylintEnabled": false,
    "python.linting.flake8Enabled": true,
    "python.linting.lintOnSave": true,
    "python.formatting.provider": "black",
    "python.formatting.blackArgs": [
        "--line-length",
        "119"
    ],
    "editor.formatOnSave": true,
    "editor.codeActionsOnSave": {
        "source.organizeImports": true
    }
}
```

isortについては[VS Codeの標準のimport並べ替え用パッケージとして組み込まれている](https://code.visualstudio.com/docs/python/editing#_sort-imports)との事です。
`editor.formatOnSave`と`editor.codeActionsOnSave`の項目がisortについての保存時にisortを自動実行する設定です。

# CI

CIツールとして[Github Actions](https://docs.github.com/ja/actions/quickstart)を使い、特定のブランチへのPUSH時にチェックが入るようにします。


## Github Actions
[公式マニュアル](https://docs.github.com/ja/actions/using-workflows/workflow-syntax-for-github-actions#)

`.github/workflows/`にymlファイルを作りGithub Actionsの内容を記載します。



```:yml
name: プッシュ時フォーマットチェック
on:
  push:
    branches:
      - main
  pull_request:
    types: [opened, reopened, synchronize]

jobs:
  format-check:
    runs-on: ubuntu-20.04
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-python@v3
        with:
          python-version: '3.9'
      - run: pip install poetry
      - run: poetry install
      - run: poetry run isort . --check-only
      - run: poetry run black . --check
      - run: poetry run pflake8
      - run: poetry run python -m py_compile main.py
```

チェックが入る条件としては以下です。

- mainブランチへのプッシュ時
- プルリクエストを発行した時
- クローズされたプルリクエストが再度オープンした時
- プルリクエストを発行したプルされる側のブランチに対するプッシュをした時

`types: synchronize`については[こちらのページ](https://jpdebug.com/p/1080318)を参考に調べました

チェック内容としては以下

- isortによるチェック
- blackによるチェック
    - `—check`で[blackによるフォーマットチェックを書けた場合どうなるのかを判断](https://black.readthedocs.io/en/stable/usage_and_configuration/the_basics.html#writeback-and-reporting)
        - 0が返ってきた場合何も変更する場所はない
        - 1が返ってきた場合再フォーマットされる場所がある
        - 123は内部エラー
- pflake8によるチェック
    - [pflakeを呼び出す](https://github.com/csachs/pyproject-flake8)
    - 警告一覧は[こちら](https://flake8.pycqa.org/en/2.6.0/warnings.html)

mainブランチへのプッシュを実行したところ、きちんと走らせることができました
![SnapCrab_NoName_2022-4-17_20-32-29_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635079/85c1134e-744e-5cca-1b4a-04d3243ec9cb.png)


blackのフォーマットチェックが問題ない場合、ケーキが出てくるのがかわいい

![SnapCrab_NoName_2022-4-17_20-33-35_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635079/2c165b64-da37-5a93-4add-3d0359577d89.png)


## Template Repository
- 参考にしたページ
    - [GitHubのTemplate Repository機能のすゝめ](https://qiita.com/ryo2132/items/08f0561804c798012146)



Githubでリポジトリを立てる際のテンプレートを作ることができます。

1.対象のリポジトリの「Settings」→「Template repository」にチェック
![SnapCrab_NoName_2022-4-20_22-49-39_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635079/a32c93de-6408-6ffe-cfbb-68a906661f03.png)
2.Create a new repositoryで「Repository template」からテンプレートを選択
    
![SnapCrab_NoName_2022-4-20_22-51-34_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635079/a39d7d52-a7e2-5db9-4460-e2317d8d65e2.png)

最初からコーディングのチェック環境が整ったリポジトリで作業を始められます。

![SnapCrab_NoName_2022-4-20_22-53-44_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635079/f689f0e3-87c2-4a04-ad93-16fda12eec32.png)

# VSCode

## ターミナル

### Remote-WSL

VSCodeの拡張機能「[Remote-WSL](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-wsl)」を使います。

- 参考にしたページ
    - [Windows上のVS CodeでRemote-WSLを使い。WSL2のUbuntu 20.04へアクセスする。](https://zenn.dev/s_ryuuki/articles/4b9631674adea4)

Remote-WSLを入れると


1.ターミナルでWSL2を開くことができるようになる
![SnapCrab_NoName_2022-4-17_13-46-52_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635079/e8168932-72f2-99ba-56bd-6cec4211dab4.png)


2.WSL2のpoetry仮想環境をインタープリターから選択できるようになる
※左下の環境が「WSL: Ubuntu-20.04」になっていることを確認したうえで、「インタープリターを選択」をチェックするとWSL2のpoetryの環境が選択できるようになります。
![SnapCrab_NoName_2022-4-17_20-22-16_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635079/5fa0bce4-06d3-472c-79d2-9c82238b87c8.png)
(左下の環境)
![SnapCrab_NoName_2022-4-20_23-33-4_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635079/c46e6930-b6db-f222-d9a8-7837d1d48748.png)



この設定は重要で、行わないと

- [VSCode settings.json設定](#vscode-settingsjson設定)で施した**blackの保存時フォーマット変更がされない**
- **flake8での適切なリンターがされない**
    - poetry環境ではインストールしているのに、選択したインタープリターではインストールしていないライブラリについて「[reportMissingImports](https://github.com/microsoft/pylance-release/blob/main/DIAGNOSTIC_SEVERITY_RULES.md#diagnostic-severity-rules)」が出てくる

以上のような状態になってしまいます。


ちなみに、[Remote-WSL](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-wsl)を入れずに、Windows側から「インタープリターを選択」をすると、
**exeファイルのpythonしか選択肢に出てこない**ので、WSL2上のpython環境を読めません。
![SnapCrab_NoName_2022-4-17_14-54-12_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635079/350dc411-f852-92dd-f501-a4eca7231d21.png)


## WSL2からVSCode起動

- 参考にしたページ
    - [WSL2からVSCodeが起動しない場合の対処方法](https://snowsystem.net/other/windows/vscode-wsl-run-error/)

WSL2コンソールから

```bash
code .
```

と打つと、**最初からUbuntu20.04とリモート接続した状態でVSCodeを起動できます**

ですが、特に設定していないと、`Command 'code' not found`と出てしまうので、
Windows側のVSCodeのパスをWSL2の.barhrcに記載する必要があります。

デフォルトのVSCodeインストールパスは
`C:\Users\[ユーザ名]\AppData\Local\Programs\Microsoft VS Code\bin`
このようになっていると思うので、これを追加してパスを通します。

WSL2のホームディレクトリへ移動して.bashrcを開きます

```bash
cd ~
vim .bashrc
```

「i」ボタンをおして編集モードにして

```bash
export PATH=$PATH:'/mnt/c/Users/[ユーザ名]/AppData/Local/Programs/Microsoft VS Code/bin'
```

と記載し、`Esc`→`:wq`で保存して閉じる

と、`code .`でWSL2リモート接続状態のVSCodeを開くことができます。

# さいごに
セットアップ大変だなと思いました・・・一度やれば次は楽なので、頑張って覚えていこうと思います。
今後は一人でもこれらを意識していきます。

今回は、[@tfandkusu](https://qiita.com/tfandkusu)さんからの指導と自分自身の探索を纏めて記事にさせて頂きました。
本当にありがとうございます :bow:


[今回作成した環境](#ci)をGithubリポジトリにしています。
https://github.com/nijigen-plot/python_repository_template
もしよければ見てもらえると嬉しいです。