複数のPoetry管理のプロジェクトをJupyterで使う

初めまして。二年目になります。
普段はSQL書いてます。たまに機械学習みたいなこともします。

## 使いやすいpythonでの開発環境を目指して
私は最近pythonで開発環境の管理にpyenv+Poetryを使ってます、でもやっぱりJupyterも使いたい。
プロジェクトごとに分散した仮想環境をJupyterで扱うために、最初は仮想環境ごとにJupyterをいれていました。
しかし冷静に考えて毎回いれるのはめんどくさいのでsystemのpythonにJupyterをいれてそこからプロジェクトの仮想環境を呼べるようにしてみました。

### やること

```
~/
└ pyproject/
　 ├ project1/
　 │ ├ .venv
　 │ ├ src/
　 │ ├ pyproject.toml
　 │ └ ⋮
　 ├ project2/
　 │ └ ⋮
　 └ ⋮
```
以上のようなディレクトリ構成でpythonのプロジェクトを作成するとして、プロジェクト個々の仮想環境(.venv)をJupyterのカーネルに自動追加した状態でJupyterを立ち上げる。

## 構築
今回はubuntu18.04で作業を行います。インストールするパッケージなどが変わりますが他のディストリビューションでも同じ流れで頑張ればできると思います。別にローカルでもリモートでも構いません。リモートの場合はsshでポートをローカルフォワードするなりしてJupyterと繋げてください。以下はEC2で18.04のイメージで行いました。。


### pyenv
https://github.com/pyenv/pyenv#installation
公式に従いgit cloneして環境変数やらを.profileに登録するだけ。

```bash
git clone https://github.com/pyenv/pyenv.git ~/.pyenv 
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.profile
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.profile
echo -e 'if command -v pyenv 1>/dev/null 2>&1; then\n  eval "$(pyenv init -)"\nfi' >> ~/.profile
exec "$SHELL"
```

pythonのビルドに必要なパッケージをいれる

```bash
sudo apt-get install \
    build-essential \
    libsqlite3-dev \
    sqlite3 \
    bzip2 \
    libbz2-dev \
    zlib1g-dev \
    libssl-dev \
    openssl \
    libgdbm-dev \
    libgdbm-compat-dev \
    liblzma-dev \
    libreadline-dev \
    libncursesw5-dev \
    libffi-dev \
    uuid-dev
```

pythonのインストール

```bash
# 使いたいpythonのバージョンを確認
pyenv install --list
# install (今回は3.7.5)
pyenv install 3.7.5
pyenv install 2.7.17
# pythonコマンド時に呼び出されるバージョンを指定
pyenv global 3.7.5 2.7.17
# 確認
python -V
python2 -V
```

### Poetry
https://github.com/sdispater/poetry#installation
こちらも公式に従う

```bash
curl -sSL https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py | python
# preview版
# curl -sSL https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py | POETRY_PREVIEW=1 python
```

プロジェクトディレクトリ内に環境を作成する設定
以下を行うとpyproject.tomlと同じ階層に.venvディレクトリが作成されるようになる

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

試しにプロジェクトを作ってみる

```bash
mkdir ~/pyproject
cd ~/pyproject
poetry new --src project1
```
これでproject1というプロジェクトが作成される

```bash
cd project1
poetry install
```

これで.venvがproject1の中にできれば成功！

**ただし、Jupyterのカーネルとして追加するためにプロジェクト毎の環境に`ipykernel`をインストール必要があるで注意！**

```bash
poetry add -D ipykernel
```

### Jupyter
systemのpythonにJupyterをいれる

```bash
sudo apt install python3-pip
sudo pip3 install jupyterlab
```

起動設定
`~/.jupyter/jupyter_notebook_config.py`で設定できます。
私は以下のように設定しています。tokenは適宜変更してください。

```~/.jupyter/jupyter_notebook_config.py
c.NotebookApp.open_browser = False
c.NotebookApp.port = 8888
c.NotebookApp.token = 'HYPER_DIFFICULT_TOKEN'
c.NotebookApp.ip = '0.0.0.0'
c.NotebookApp.notebook_dir = '/home/ubuntu/pyproject'
```

環境登録用のスクリプト
以下の処理をJupyter立ち上げ前に毎回行う

```/home/ubuntu/jupyter.sh
#!/bin/bash

PROJECT_DIR=/home/ubuntu/projects
INSTALLE_DIR=/home/ubuntu/.local/share/jupyter/kernels

projects=($(ls ${PROJECT_DIR}))
installs=($(ls ${INSTALLE_DIR}))

# 一旦全部消す
for install in ${installs[@]}; do
    rm -rf ${INSTALLE_DIR}/${install}
done

for project in ${projects[@]}; do
    ${PROJECT_DIR}/${project}/.venv/bin/python -m ipykernel install --name ${project} --user
done
```

サービスとして登録
EC2を使ったのでユーザーがubuntuになっていますので環境に合わせて適宜変更してください。

```/etc/systemd/system/jupyter.service
[Unit]
Description=Jupyter Daemon

[Service]
ExecStartPre=/home/ubuntu/jupyter.sh
ExecStart=/usr/local/bin/jupyter lab
ExecStop=/bin/kill ${MAINPID}
Restart=always
Type=simple
User=ubuntu
Group=ubuntu

[Install]
WantedBy=multi-user.target
```

```bash
sudo systemctl start jupyter
# 起動時にJupyterが起動するようにサービスを登録
sudo systemctl enable jupyter
```