Notebookの差分をhtmlで出力するGithub Actionsを作った

diff-notebooks

Notebookの差分をArtifactとして生成するdiff-notebooksをGithub Actionsとして公開しました。

github.com

想定する使い方はpull_requestをトリガーとするGithub Actionsへの組み込みです。

実行すると画面のようにNotebookの差分結果がArtifactとして保存されます。

中身はhtmlになっておりブラウザ上で開くとこのように差分を確認できるので、プルリクを受け取ったときのNotebookの差分チェックがGithub上の操作で完結します。

nbdiff-notebooksの中身

このGithub Actionsの中では、nbdiff-webで生成した差分のhtmlをファイルとして出力する自作ツールnbdiff-web-exporterを実行しています。

github.com

nbdiff-web-exporterは後で触れるnbdiff-webのラッパーです。nbdiff-webのオプションのほとんどをそのままサポートしています。

nbdiff-webはブラウザ上でNotebookの差分を確認できるツールです。ブラウザのボタン操作で差分ファイルをダウンロードできるのですが、差分ファイルをダウンロードには1ファイルごとにボタン操作が必要になります。

nbdiff-web-exporterはそれらの手間を省くためのラッパーになっており、baseとremoteを指定して実行すると差分結果のhtmlをローカルに保存するシンプルなCLIです。

Github Actionsで複数のNotebookの差分結果をArtifactとして保存するためにはブラウザの操作を除外する必要があったので、nbdiff-webを実行してからのブラウザの操作をseleniumで自動化しました。

なぜツールを作ったのか

Githubのレビュー画面ではNotebookの差分が分かりづらい

Jupyterで書かれたNotebookのプルリクを受け取ると、Github上でレビューしようとしても差分がよく分からないことがほとんどです。

Notebookの実態がjsonなのでGithubのchanged filesを開くと以下のようにjsonの差分として表示されてしまいます。下の例ではコードとプロットされた画像が変わっているのですが、どこが本質的な変更なのか画面からは分かりません。

既存のツールではあと一歩が足りない(個人の好みによる)

これ以降はnbdiff-web-exporterを作る前に既存ツールを調べてなぜそれらを使わなかったかをまとめています。

nbdimeと内部ツール

nbdime Notebook Extension

nbdimeをNotebook ExtensionとしてインストールするとJupyter上で差分を確認できます。

ただし、毎回Jupyterを立ち上げてgit fetchしてExtensionを起動するというステップが必要です。

nbdiff CLI

nbdimeに組み込まれたnbdiffを使うとターミナル上でdiffを実行するのと同じ使い勝手で差分を見れます。nbdiffならば差分確認のためにJupyterを立ち上げる手間は必要ありません。

$ nbdiff notebook/test.ipynb notebook/test2.ipynb 
nbdiff notebook/test.ipynb notebook/test2.ipynb
--- notebook/test.ipynb  2022-10-10 10:16:24.487987
+++ notebook/test2.ipynb  2022-10-10 10:16:24.489169
## modified /cells/1/source:
@@ -1,2 +1,2 @@
-X = np.linspace(-10, 10, 1000)
+X = np.linspace(-100, 100, 1000)
 y = np.sin(X)


## inserted before /cells/2/outputs/0:
+  output:
+    output_type: display_data
+    data:
+      image/png: iVBORw0K...<snip base64, md5=56df3dbb7c0efb80...>
+      text/plain: <Figure size 640x480 with 1 Axes>

## deleted /cells/2/outputs/0:
-  output:
-    output_type: display_data
-    data:
-      image/png: iVBORw0K...<snip base64, md5=43dd28726681bf24...>
-      text/plain: <Figure size 640x480 with 1 Axes>

ただし、こちらもJupyterを起動せずに済むこと以外はnbdime Notebook Extensionと同じくgitの操作の手間がかかります。また、画像の差分が分かりづらいためレビューに向いているとは言いづらいです。

nbdiff-web

nbdiffよりもリッチな画面で差分を見たいならnbdiff-webを使えばブラウザ上で差分を確認できます。

$ nbdiff-web origin/main notebook/test.ipynb 
[I nbdimeserver:422] Listening on 127.0.0.1, port 50532
[I webutil:29] URL: http://127.0.0.1:50532/difftool

一見これでもよさそうですが、レビューのたびにコマンドを実行しなければならず面倒です。

また、先ほどお話したようにhtmlをファイルとして取得するにはブラウザの操作が必要になります。nbdiff-webでブラウザを操作することなくhtmlを出力する機能の要望は挙がっているものの開発が途中で止まっているようです。

Add nbdiff-web-export to export HTML diff using just command line by trams · Pull Request #552 · jupyter/nbdime · GitHub

VSCodePython Extension

VSCodePython Extentionはipynb形式のファイルのレンダリングをサポートしており差分の確認もできます。普段から VSCodeでレビューをしていれば他のコードと同じようにレビューできます。

機能には満足していますが、個人的にはブラウザ上で作業が完結する方がうれしいこともあります。

ReviewNB

ReviewNBはまさにGithubのPR画面にNotebookの差分を表示してレビューするためのツールです。

私は使ったことがないのですが、差分箇所を指定してコメントをつけたり変更点をSuggestしたりとGithubのPR画面でできることはほぼできるように見えます。

プルリクを受け取ってGithubのPRを開くと必要な情報が揃っており、個人的には理想的なツールです。

ただしRebiewNBはOSSやアカデミックな分野以外で利用しようとすると有料になります。そのため手軽に試すには敷居が高いです。

まとめ

複数のツールを使い分けることなく無料でNotebooksのレビューができるGithub Actionsを作りました。

レビューだけならばVSCodeでも十分ですが、diff-notebooksを使えばpushごとの差分を常にArtifactとして記録できるメリットもあります。