10
14

More than 1 year has passed since last update.

JupyterLab App について真面目に考える

Last updated at Posted at 2021-10-07

JupyterLab App について真面目に考える

以前、JupyterLab は複数の(分析)プロジェクトをまたがって使う共通環境なのだから、pipx に入れても良いんじゃないか、という話をした。
その後に JupyterLab App リリースされたという記事が出て、ようやく世間が俺に追いついたな、と。(何様)
ある程度 JupyterLab App を触って分かってきたので、JupyterLab App 関連についてまとめたいと思う。

JupyterLab App とは

JupyterLab App の GitHub repository の Description には "A desktop application for JupyterLab, based on Electron" ってあるけど、これは JupyterLab App の半分しか言っていない。
上記の記事では "It is a self-contained desktop application which bundles a Python environment with several popular Python libraries" って言ってて、これは正しい。

すなわち JupyterLab App には何が入っているのかというと、

  • Electron で作られた(シンプルな)Web Browser
  • JupyterLab が入っている conda ベースの Python 仮想環境(venv)

の2つが入っている。

で、これをインストールした人は、全く Python の環境が無くても、いきなり JupyterLab が専用アプリとして使えてしまう。
これは便利っちゃあ便利。

便利な点

  • インストールがめちゃ簡単
    • GitHub repository のトップページ にあるリンクをクリックしてインストーラーをダウンロードし、それをダブルクリックしてインストールすれば、いきなりすぐに Jupyter が使える。
  • 専用アプリで快適
    • JupyterLab は、起動するとブラウザが立ち上がり、そのプラウザ上で入力したり結果を見たりするものなので、Jupyter しながら Web で検索するみたいな時には、ちょっと面倒くさかったりする
    • その点、 JupyterLab App は専用アプリ(専用ブラウザ)なので、余計なものが入っていなく、シンプルで快適
    • ブラウザを閉じたら、うっかり JupyterLab も一緒に閉じちゃった、なんてことも無い

不便な点

リリースされたばかりなので、これから改善するのかもしれないが、現時点(2021/10/06)では以下の不便な点がある。

  • 既存のパッケージや拡張機能で(すぐには)使えないものがある
    • 突然「専用の特別な conda ベースの venv」というものが導入されてしまったので、特に別コマンド・別サーバを叩きに行く拡張機能は、そのままでは使えない
  • パッケージを追加することが難しい
    • "Python environment with several popular Python libraries" って言ってるけど、NumPyMatplotlib すら入っておらず、JupyterLab を動かすための最小限のパッケージしか入っていない
    • だから JupyterLab で普通に分析をしようと思ったら、上記 NumPy, Matplotlib を始め、ほぼすべてを scratch からインストールしなければならない
    • しかし、パッケージを追加する方法は公式には提供されておらず、実際にちょっとメンドイ

特に後者は結構致命的で、Issues を見ても、これ関係が多いように思う。

JupyterLab App でのパッケージ管理

解決策を示しておく。

JupyterLab App でインストールされる venv は以下の場所にある。

  • MacOS X
    • /Applications/JupyterLab.app/Contents/Resources/jlab_server
  • Linux (Ubuntu)
    • /opt/JupyterLab/resources/jlab_server

なので、この .../jlab_server の下の bin/pipbin/conda を叩いてパッケージのインストールやアンインストール、インストール済パッケージリストの表示をすれば良い。

例)MaxOSX に入れた JupterLab App で、pip を使ってインストール済みパッケージのリストを表示する
> /Applications/JupyterLab.app/Contents/Resources/jlab_server/bin/pip list

注意点

この時、絶対に注意しなければならないのは、上記 JupyterLab App 内の pip / conda を使ってパッケージをインストール/アンインストールする時は、必ず sudo を付けて、管理者権限でしなければならない、ということである。

そもそも JupyterLab App は、上記の venv の場所を見ても分かる通り、システム領域にインストールされるので、そこにパッケージをインストールする時は管理者権限で行わなければならない。

もしも管理者権限ではなくユーザー権限で pip を叩いた場合は、そのパッケージは ${HOME}/.local の下にインストールされる。当然、JupyterLab App には認識されず、使えない。
でも管理者権限で pip を叩くと、pip から「管理者権限で pip するのはオススメできないでゴザル」とか言われてしまうので、常になんだかなぁという気持ちになる。
conda も同様。

正解は何なのかは未だに分からない。

JupterLab on pipx

JupyterLab はインストールが簡単で専用アプリで快適、だけどパッケージ管理がしんどいということが分かった。

では pipx に JupyterLab を入れるのはどうか。

同じくらい簡単。

  • pipx のインストール
    • MacOS の場合
      • > brew install pipx
      • > pipx ensurepath
    • Linux (Ubuntu) の場合
      • > /bin/python3 -m pip install --user pipx
      • > /bin/python3 -m pipx eusurepath
  • pipx の設定
    • PATH 環境変数に ${HOME}/.local/bin を追加する
  • pipx に JupyterLab をインストールする
    • > pipx install jupyterlab

これだけ。こっちも簡単じゃない?

こいつを JupyterLab on pipx と呼ぶことにする。私にネーミングセンスが無いのは勘弁。

で、JupyterLab App と、JupyterLab on pipx は何がどう違うかというと、まぁ状況はほとんど同じ。

JupyterLab App も、JupyterLab on pipx も、通常の venv とは管理方法が違うので、そのままじゃ動かない拡張機能がある。

ただし、pipx はユーザー領域(${HOME}/.local/pipx)に入るので、パッケージを入れたり消したりする罪悪感は無い。JupyterLab 自体を作ったり消したりするのも JupyterLab App よりずっと簡単。

ということで、私は JupyterLab App より JupyterLab on pipx の方を推したい。推しメン。

でも、以下の問題を解決しなきゃならない。

  • JupyterLab 専用アプリが無いので、快適じゃない
    • JupyterLab on pipx が JupyterLab App より劣っている点
  • JupyerLab の拡張機能が一部動かない
    • JupyterLab on pipx と JupyterLab App で共通する問題点

JupyterLab on pipx でのパッケージ管理

JupyterLab on pipx の問題点はちょっと脇に置き、まずは JupyterLab on pipx でのパッケージ管理。

以下の2種類の方法がある。

  • pipx inject を使う
  • pipx runpip を使う

まずは pipx inject で、pipx が作った JupyterLab 用の venv に pip を入れる。

> pipx inject jupyterlab pip

この inject は普通に使えて、ただ入れるだけならドンドコ inject すれば良い。

inject で pip を入れたら、今度は runpip が使える。これはもうまるっきり pip と同じ。

だから SHELL の設定に alias pipj="pipx runpip jupyterlab" を追加すると便利じゃないかな。個人的意見。

このようにパッケージ管理が JupyterLab App より簡単でスッキリしてるので、JupyterLab on pipx の方が良いんじゃないかな。個人的意見。

JupyterLab 専用アプリ

JupyterLab on pipx は、専用アプリが無くて快適じゃないというただ1点で JupyterLab App より劣っているので、何とかこれを解決したい。

一番簡単な解決方法は、Chrome のショートカットを作ること。

普通に jupyter-lab (JupyterLab server の起動コマンド)を叩いたらブラウザが立ち上がるので、その Chrome のメニューから「その他ツール」>「ショートカットを作成」と選び、JupyterLab という名前で「ウィンドウとして開く」にチェックを入れてショートカットを作れば、あたかも JupyterLab 専用アプリケーションのように使うことが出来る。
(Chrome 以外のブラウザの場合は、知らない(Google 信者))

chrome_jupyterlab.png

これで万事解決な気がする。でも騙されてはいけない。こいつは偽装しているだけで立派な Chrome だ。
左上に「戻る」や「リロード」ボタンが有るし、右上には「拡張機能」ボタンが有る。なので、このアプリ自体が Chrome 拡張機能の影響を受ける(Keep Last Two Tabs とか)。まぁそのお蔭で Stylus を使って JupyterLab の見た目を変えることも出来るんだけど。

もうひとつの方法は、JupyterLab App と同じように、Electron で専用アプリを作ってしまうこと。

ブラウザから JupyterLab を使う時は、ブラウザから http://localhost:8888/lab にアクセスすることで JupyterLab を使えるようになる。よって、単純に http://localhost:8888/lab にアクセスするだけのブラウザがあれば良い。

同じことを考える人はいるもので、adammenges/JupyterLabApp は私の欲しい物ずばりそのものだった。

Electron は、Electron の簡単なサンプルとして electron/electron-quick-start というものを提供していて、これは単純に中に含まれている index.html を表示するだけのブラウザである。
この中に含まれている HTML ファイルを表示する Electron の関数、electron.BrowserWindow().loadFIle('index.html') を、URL を表示する関数である electron.BrowserWindow().loadURL('http://localhost:8888/lab')に置き換えれば、私の欲しい物になる。
これをやったのがまさに上記のレポジトリ。

まぁ、Electron は Node.js + Chromium なので、Chrome ショートカットと実質ほぼ同じもの。でも通常のブラウジングに使うアプリと JupyterLab 専用に使うアプリが別になるのは喜ばしいことだ。

・・・これ、俺でも作れるんじゃねぇかな。

オリジナルの JupyterLab クライアント

ということで、作った。

最初は jupyter って名前を付けるのは怒られるかもしれないなぁと思って、"YapyterLab" とか付けてたけど、もうどうでも良くなったんで開き直って "JupyterLab" ってそのまんまの名前にした。

ちなみにアイコンは、JuputerLab のアイコンはダサくて嫌なので、Jupyter のロゴを使っている。

さらにちなみに、Node.js や yarn の設定をして install.sh を叩くと、build, install から以下に述べている設定まで全部一気にやるようになっている。

しっかし、Electron 超すごい。Node.js を40行も書いてないのに Web アプリが出来ちまった。ほぼ electron-quick-start のパクリだけど。
アイコンを作ったり electron-builder の設定をする方が時間かかったわ。
でも、全部あわせても半日で出来た。

ビルドの仕方、インストールの仕方、使い方は全部 repository の README に書いたから、見てね。

JupyterLab 設定

まずは Jupyter はどこの設定ファイルを読み込むのか知らなければならない。

Jupyter on pipx の venv は ${HOME}/.local/pipx/venvs/jupyterlab にあるので、次のようにすると各種パスが分かる。

> ~/.local/pipx/venvs/jupyterlab/bin/jupyter --paths
config:
    /Users/[username]/.jupyter
    /Users/[username]/.local/pipx/venvs/jupyterlab/etc/jupyter
    /usr/local/etc/jupyter
    /etc/jupyter
data:
    /Users/[username]/Library/Jupyter
    /Users/[username]/.local/pipx/venvs/jupyterlab/share/jupyter
    /usr/local/share/jupyter
    /usr/share/jupyter
runtime:
    /Users/[username]/Library/Jupyter/runtime

他の方法で Jupyter を動かしたくなったら困るので、Jupyter on pipx だけに影響する設定をしたい。ということで、${HOME}/.local/pipx/venvs/jupyterlab/etc/jupyter/ の下に設定ファイルを置くの一択である。

そして設定をするのだが、JupyterLab のドキュメントはほとんど存在せず、設定の項目を探るのにすら苦労した。
結局どうしたかというと、以下をやってパラメータを色々試し、実現できるまで頑張るしかない。

  • > ~/.local/pipx/venvs/jupyterlab/bin/jupyter lab --generate-config で生成される ${HOME}/.jupyter_lab_config.py を読んでウンウン考える
  • > ~/.local/pipx/venvs/jupyterlab/bin/jupyter lab --help の出力を参考にする
  • ググってJupyter Notebook 時代の設定を探し、それに似た名前の設定項目をいじってみる

最終的に、以下の内容のファイルを ${HOME}/.local/pipx/venvs/jupyterlab/etc/jupyter/jupyter_lab_config.py として置くことで、JupyterLab App と同じように、JupyterLab on pipx + オリジナルJupyterLab を動かすことが出来るようになった。

c.ServerApp.use_redirect_file = False
# For Mac OSX
c.ServerApp.browser = '/Applications/YapyterLab.app/Contents/MacOS/JupyterLab %s'
# For Linux
c.ServerApp.browser = '/snap/bin/jupyterlab %s'

c.ServerApp.browser は分かるだろう。
ブラウザが JupyterLab にアクセスするためには2種類の方法があって、ひとつが http://localhost:8888/lab にトークンを付けてアクセスすること、もうひとつが JupyterLab が生成する runtime 以下の html ファイルにアクセスすること。
デフォルトの挙動は後者(c.ServerApp.user_redirect_file = True)。
Mac OSX の場合はどちらでも大丈夫なんだけど、Linux の場合には runtime 以下のファイルへのアクセスが Permission denied されてしまう。良く分からん。
なのでこいつを False にして、URL + token でアクセスするようにすれば良い。

JupyterLab Extension

最近の JupyterLab は、最初からそこそこ機能が付いている(デフォルトで公認の Extension が入っている)ので、そのままでも十分に使える。
でも、どうしてもひとつだけ入れたい Extension がある。

krassowski/jupyterlab-lsp である。

これが出来ることは以下。

  • node navigation: 関数を使っている所から関数の定義にジャンブ出来る
  • hover suggestion: 関数などをマウスで hover すると、定義がポップアップする
  • linter: 文法がおかしい所(PEP8 違反など)の自動チェック
  • autocompletion: 補完
  • rename: 変数名の一括変換

特に linter と autocompletion は必須。もうこれが無いとコーディングなんて出来ない。

jupyterlab-lsp の他の選択肢としては、kiteco/jupyterlab-kite というものが有るらしいが、外部の Kite Engine が必要。
でも俺はあまり AI って信用してないんだ(笑)。
何よりも現時点(2021/10/07)では、Kite Engine をダウンロードしようとすると "Kite is temporarily unavailable" って出て、ダウンロードできない。

ということで、話を進める。

まず JupyterLab Extension を使うには、色んな所で Node.js が必要になるので、まずはこれを入れる。アプリのビルドにも必要だし。
最近は、言語のバージョン管理は env 系を使うことがデファクトスタンダードになりつつあるので、nodenv を使う。(ちょっと前までは nodebrew とか色々あった)

  • nodenv のインストール
    • > git clone git://github.com/nodenv/nodenv.git ~/.nodenv
  • node-build のインストール
    • > git clone https://github.com/nodenv/node-build.git ~/.nodenv/plugins/node-build
  • node-build-update-defs のインストール
    • > git clone https://github.com/nodenv/node-build-update-defs.git ~/.nodenv/plugins/node-build-update-defs
  • nodenv の設定(~.zshrc とかで)
    • PATH${HOME}/.nodenv/bin を加える
    • eval "$(nodenv init -)" をする
  • Node.js のインストールと設定
    • > nodenv install --list
      • インストールできるバージョンの一覧表示
    • > nodenv install x.x.x
      • 特定のバージョンをインストール
    • > nodenv global x.x.x
      • どこでもそのバージョンの Node.js を使えるようにする

JupyterLab App の人も、conda で Node.js を入れた方が良いと思う。

> sudo (path-to-jlab_server)/bin/conda -c conda-forge nodejs

jupyterlab-lsp

そしたらいよいよ jupyterlab-lsp のインストール。
jupyterlab-lsp は JupyterLab に上記の機能を提供するガワであり、Python だけじゃなくて色々な言語(の Language Server)に対応している。
だから Python の Language Server である python-lsp-server も入れなければならない。

  • > pipx runpip jupyterlab install jupyterlab-lsp
  • > pipx runpip jupyterlab install "python-lsp-server[all]"

python-lsp-server に [all] を付けることによって、関連するパッケージ(flake8 とか)を全部いっぺんに入れちゃえる。

JupyterLab App の人は、pipx runpip jupyterlab install の代わりに sudo (path-to-jlab_server)/bin/pip install ってやるんじゃないかと思う。多分。

余談だが、Python の Language Server としては python-language-server というものもある。しかしこれは開発がストップしていて、これを fork してコミュニティで開発しているのが python-lsp-server らしい。昔は python-language-server しか無かった。老人のつぶやき。

python-language-server から python-lsp-server への乗り換えは、python-language-server の設定の pyls となっている所をすべて pylsp に置き換えることで可能。

余談が過ぎたが、python-lsp-server, jupyterlab-lsp が無事にインストール出来たからといって、これが動くかというと、ほぼ動くが、ほんのちょっとだけ動かない所がある。

jupyterlab-lsp の設定

python-lsp-server の設定項目は、python-lsp-server/CONFIGURATION.md に一覧がある。

この中で明らかに設定が必要なのは、pylsp.plugins.flake8.executable

jupyterlab-lsp から python-lsp-server を叩くのは、jupyterlab-lsp が入っている仮想環境の Python モジュールとして叩くので、両者が同じ仮想環境に入っていれば良い。
しかし、flake8 は pylsp のプラグインだけじゃなく普通のコマンドとしても使うので、python-lsp-server はPATH を通じて flake8 を探してしまう。しかし JupyterLab on pipx(もしくは JupyterLab App)の仮想環境という特殊な所に入っているので、flake8 が見つからない、もしくは変な所の flake8 を見てしまう。

よって、flake8 の絶対パスを jupyterlab-lsp の設定として書き、それを python-lsp-server に渡せば良い。
JupyterLab を起動し、メニューから Settings > Advanced Setting Editor を選び、左ペインから Language Server を選んで設定を記入する。

私の設定をサンプルとして示す。

{
  "language_servers": {
    "pylsp": {
      "serverSettings": {
        // disabed services
        "pylsp.plugins.pycodestyle.enabled": false,
        "pylsp.plugins.pyflakes.enabled": false,
        "pylsp.plugins.rope_completion.enabled": false,
        "pylsp.plugins.yapf.enabled": false,
        // flake8
        "pylsp.plugins.flake8.enabled": true,
        "pylsp.plugins.flake8.executable":
          "${HOME}/.local/pipx/venvs/jupyterlab/bin/flake8",
        // ignoring errors
        // E402: allows imports which are not on the very top
        // E703: allows terminating ";" (for matplotlib plots)
        "pylsp.plugins.flake8.ignore": ["E402", "E703"],
        // maxLineLength = 79 (default)
        "pylsp.plugins.flake8.maxLineLength": null
      }
    }
  }
}

すると、こんな感じになる。

yapyterlab.png

スクリーンショットじゃ、あんまり違いは分からないね・・・

まとめ

JupyterLab App を触ってみたけど、あんまり気に入らなかったんで、自分でアプリ作ったり環境作ったりした。

そこそこ良いものになったんじゃないかと思う。

みなさんも宜しければ是非。

10
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
14