VScodeでリモートのJupyter Serverに接続したところ、ローカルのファイルを実行でき、ファイル実行中に出力したファイルはリモートにありました。

はじめに

普段私は大学でPythonを使った数値計算の研究をしています。
研究室のPCの計算資源が乏しいので、実行環境は自宅のPCに構築していて、作業は自宅PCで起動したjupyter notebookのローカルポートをの研究室PCの同ポートにフォワーディングしています。イメージは

研究室PC(ホスト名:local)
↓ [local] ssh -L 8888:localhost:8888 remote
自宅PC(ホスト名:remote)
↓ [remote] jupyter notebook
研究室PC
↓ [local] xgd-open http://localhost:8888/?token=

こんな感じです。この方法ではremoteのファイルしかアクセスできません。いや、少なくとも私はそう理解しています。両PCともWindowsなので、remoteで起動するjupyterの作業ディレクトリをOnedriveに設定することで、localとのファイル同期を簡単に行っていました。イメージは

C:/users//onedrive == C:/users//onedrive

こんな感じです。

VScodeの導入

今秋、Visual Studio Codeでjupyter notebookのネイティブサポートが開始されました。

参考:VS CodeのPython拡張がJupyterをネイティブサポートしたそうなので早速使ってみた。

jupyter notebookはインタラクティブな開発環境こそ利点であれど、Atomなど高性能なテキストエディタについてくるような補助機能はなく、またWebアプリケーションであるからUIのスタイルをcssで記述しなければならなく、なにかと面倒です。
VScodeのこのアップデートはリモートjupyter serverに接続する機能もあると聞きつけ、私も乗るしかない、このビッグウェーブにと一念発起しました。しかしまだリリース数ヶ月であるからか、このリモートjupyter serverに接続するという機能に注目した記事がまるでないじゃないですか。手探りで触ってみたところ、「ローカルのファイルをリモートの実行環境で実行できる」という、私の中では真新しい技術に出会いました。しかもその挙動が直感的には理解できないものだったので、記事にして共有してみようと思いました。

実行環境

お試しなので、ローカルPCは前述の研究室PCではなく、手持ちのノートPCを使いました。

ホスト名: remote ;計算資源盛り盛りのマッチョdesktop
win10, python3.6, jupyter

ホスト名: local ;CPUがatomのクロック1GHz程度のガリlaptop
win10, python3.6, jupyter, VScode

VScodeの環境

ネットに転がっていますので、割愛。本体と日本語とpythonアドオン入れただけです。

手探り実験

ローカルなVScodeの作業ディレクトリをlocal_dir、リモートなjupyter serverの作業ディレクトリをremote_dirとします。

まず、ローカルな環境でノートブックを起動します。VScodeのコマンドパレットに下記を打ち、空のノートブックを開きます。

Python: Create New Blank Jupyter Notebook

そして、次のコードをセルに書き、実行します。

#ln[1]
import socket
print(socket.gethostname())

#Out[1]
'local' #ローカルPCのホスト名

ローカルの環境で実行できました。
次に、リモートのjupyter serverに接続します。

Python: Specify local or remote Jupyter server for connections

するとプロンプトが出てくるので、リモートのjupyter notebookのURLを指定します。私の環境では前述の通り、別途sshした前提で

http://localhost:8888/?token=

ですね。
するとlocal_dirには隠しフォルダとファイルが生成されます。

{
    "python.dataScience.jupyterServerURI": http://localhost:8888/?token=<token>
}

この設定ファイルがあるディレクトリでノートブックを開くと、実行環境がリモートに移ります。

#ln[1]
import socket
print(socket.gethostname())

#Out[1]
'remote' #リモートPCのホスト名

実行ファイルの実体はどこにあるのでしょうか。

#ln[2]
import os
print(os.path.abspath(""))

#Out[2]
'<remote_dir>' #jupyter serverの作業ディレクトリ

ローカルのファイルを開いていたつもりが、リモートPCの作業ディレクトリにあるファイルを開いていることになっています。
jupyter notebookを開いたリモートのプロンプトを覗いてみると、何らかのキャッシュが行われている形跡がログに見られました。実際にはjupyter serverの作業ディレクトリにUntitled[0-9]+.ipynbという名前でローカルファイルがキャッシュされ、VScodeを終了するとキャッシュが削除されるようです。
この状態で何らかのファイル出力を試みます。

#ln[3]
import numpy as np
a = np.array([1,2,3])
np.savetxt("whereami.csv", a)

whereami.csvはどこに出力されるでしょうか?

~/remote_dir/whereami.csv

でした。

まとめ

リモートだけど、リモートじゃなかった!

参考

Visual Studio CodeでJupyter Notebookを動かしてみた
https://dev.classmethod.jp/server-side/python/visual-studio-code-jupyter-notebook/

VS CodeのPython拡張がJupyterをネイティブサポートしたそうなので早速使ってみた。
https://qiita.com/simonritchie/items/5d865e72dba47cf8f6c0

bannerAds