自動でjupyter notebookのsnippetを作成する! 

この記事では,jupyter notebookでのsnippetの使い方と,コードから自動的にsnippet用のテキストを作成するコードを紹介する. 
Mac ユーザー向けです.Windowsで動かす場合は,適宜,コードを書き換えて使用してください.コメントに依頼があれば,windows版も作成するかもしれないです.

動機としては,snippetは登録すれば便利なのにjupyter notebookのsnippetは,最後にカンマやらセミコロンやらの設定ミスで上手く回らなくて,時間が吸い取られる.だったら,自動作成用のコードを作っておこう,というものです. 
コードは,git clone https://github.com/akitoshiblog/blogsiteでauto_snippetの下にある.

仕様

今回は以下の手順でsnippetが作成出来るようにした.

・src ディリクトリー以下にsnippet用の “~.py”ファイルを用意する.
・snippetの名前とコードを結びつける辞書を設定する.
・コードを回すと,jupyter notebookのsnippet設定用のテキストが用意される.
・後は,そのテキストを該当箇所に貼り付ければ,snippetの設定完了.

出来ないこととしては, 
・二階層以上のメニューの作成
・シングルクオーテーションマーク(’)が入っているのコードを使用
が挙げられる.

環境

・MacOS mojave ver. 10.14.6
・python 3.7.2.
・仮想環境として pyenvを使用. 

jupyter notebookのsnippetについて

jupyter notebookのsnippet機能は,jupyter notebookのnbextensionsの拡張機能の一つ.何度も繰り返し使うコードを登録して,一気に貼り付けてくれる. 

jupyter notebookのsnippetの仕様については,nbextensionsの設定の下に出てくるreadme.mdが分かりやすいです.このサイトですね.
https://jupyter-contrib-nbextensions.readthedocs.io/en/latest/nbextensions/snippets_menu/readme.html
他にも,日本語で解説しているサイトがあるのでそちらを調べてみてください. 
ただ,このサイトのコードを使うならば,そこらへん分かんなくても設定可能.

snippetは,~/.jupyter/custom/custom.js に設定することだけ把握すること. 
見つからなかったら,ホームディレクトリーから,”find . -name cutsom.js” と打てば,見つかるかも.無かったら,customもcustom.jsも作成すればok.

jupyter notebookのsnippetについて詳細を知りたい場合は,他サイトを参照してください. 

下準備

今回使用する例は,以下のようなディレクトリー構成となっている. 
各コードについては,最後に挙げてある. 

├── snippetGenerator.py
└── src
    ├── default_import.py
    ├── hide_script.py
    ├── hoge1.py
    └── hoge2.py

使い方

使い方は,極めて簡単. 
まず,srcディレクリー以下に,スニペット用のコードを用意する. 
次にsnippetGenerator.pyを開いて,structureに辞書を渡す. 
キーには,snippetのメニューに設定したい名前を,値にはコードの名前を入力すること. 
この時に,sub-menu を作りたい場合は,辞書の中に辞書を渡すこと.三階層のsub-menuはこれでは作成出来ないため,注意すること.

今回では,mainは以下のような設定となる.

def main():
    structure = {"default_import":"default_import.py",
             "hide_script":"hide_script.py",
              "hoges":{
                 "hoge1" : "hoge1.py",
                 "hoge2" : "hoge2.py"
                }
              }
    autoSnippetGenerator(structure)

後は,これを保存して,snippetGenerator.pyを起動すると,resディリクトリー下に,config.jsが作成される.
このテキストを該当箇所に貼り付けて(僕の場合は,~/.jupyter/custom/custom.js ),保存すれば終了.jupyter notebookを起動してsnippetのタブを見れば該当のコードが登録されている.

注意事項としては,
*snippetの登録の際にデフォルトで用意されるもののうち,PythonとMarkdownは消去している.これは,snippetGenerator.pyの87行目の”snippets_menu.default_menus[0][‘sub-menu’].splice(0, 8);n” を調整することで自分好みのものにしてほしい.

以上! 何か分からないことがあったらコメントよろしくです.

コード

注:”\n”のバックスラッシュ部分が消えて,”n”だけになっているので,コードをダウンロードして確認してください.

snippetGenerator.py

import json
import glob
import os
import subprocess

def main():
    structure = {"default_import":"default_import.py",
             "hide_script":"hide_script.py",
              "hoges":{
                 "hoge1" : "hoge1.py",
                 "hoge2" : "hoge2.py"
                }
              }
    autoSnippetGenerator(structure)


def str2Snippet(data_,indent_ = 2):
    '''convert strings into snippet codes. 
    
    Args:
        data_(str) : code that want to be converted. 
        indent_(int) : # of indents that are inserted before each line.
    Return:
        str : strings that can be used for snippet 
    '''
    if "'" in data_ :
        raise ValueError("Error : single quotation mark exists. remove or replace with double quotation mark.")
    dataLis = data_.split("n")
    s_ = ""
    sIndent = "    "*indent_
    for d in dataLis:
        s_ += "%s'%s',n" % (sIndent,d)
    return(s_)

def oneSnippet(path_,indent_= 2 , name_ = False,end =";" ):
    '''generate one snippet set

    Args:
        path_(str) : path for code.
        indent_(int) : number of indent. 
        name_ (str) : if you want to add specific file name, use this variable.
        end (str) : default is ";". If code is used for sub-menu, use ",".
    Return:
        str : one snippet set 
    '''
    if not name_ : 
        fileName = path_.split("/")[-1]
        name_ = fileName[:-3]
        
    with open(path_,"r") as f:
        data = f.read()
        
    content = str2Snippet(data, indent_ = indent_ + 2 )
    sInd = '    '*indent_
    sInd2 = '    '*indent_ + '    '
    
    snippet = '%s{n' % sInd + 
            '%s"name" : "%s",n' % (sInd2, name_) + 
            '%s"snippet" : [n' % (sInd2) + 
            content + 
            '%s],n%s}%sn' %(sInd2,sInd,end)
            
    return(snippet)
    
def autoSnippetGenerator(structure):

    res = "require(['nbextensions/snippets_menu/main'], function (snippets_menu) {n
    console.log('Loading `snippets_menu` customizations from `custom.js`');n"

    for k, v in structure.items():
        if type(v) == str:
            res += "    var %s = n" % k
            path = "src/" + v
            res += oneSnippet(path)
        if type(v) == dict:
            res += "    var %s = {n" % k
            res += '        "name" : "%s",n'% k
            res += '        "sub-menu" : [n'
            
            for kk,vv in v.items():
                path = "src/" + vv
                res += oneSnippet(path,indent_=3,end=",")
            res += '        ],n'
            res += '    };n'
                
        
    res +=     "    snippets_menu.options['menus'] = snippets_menu.default_menus;n
    snippets_menu.default_menus[0]['sub-menu'].splice(0, 8);n"
    
    for k in structure.keys():
         res += "    snippets_menu.options['menus'][0]['sub-menu'].push(%s);n" % k
    res +=  "    console.log('Loaded `snippets_menu` customizations from `custom.js`');n});"
    
    if not os.path.exists("res"):
        subprocess.check_call(["mkdir","res"])
        
    with open("res/custom.js","w") as f:
        f.write(res)
    print("The snippet is correctly generated!! ")
    print("Snippets structrue is as follows.")
    print(json.dumps(structure,indent=4))
     
    return(0)



if __name__=="__main__":
    main()

default_import.py

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns
sns.set(context="paper" , style ="whitegrid",rc={"figure.facecolor":"white"})

hide_script.py

from IPython.display import HTML

HTML("""



""")

hoge1.py

def helloWorld():
    print("hello world!!)

hoge2.py

def helloWorld2(s_):
    print("hello world!!" + s_)

今回の例で出来上がったcustom.js .

require(['nbextensions/snippets_menu/main'], function (snippets_menu) {
    console.log('Loading `snippets_menu` customizations from `custom.js`');
    var default_import = 
        {
            "name" : "default_import",
            "snippet" : [
                'import pandas as pd',
                'import numpy as np',
                'import matplotlib.pyplot as plt',
                '%matplotlib inline',
                'import seaborn as sns',
                'sns.set(context="paper" , style ="whitegrid",rc={"figure.facecolor":"white"})',
                '',
            ],
        };
    var hide_script = 
        {
            "name" : "hide_script",
            "snippet" : [
                'from IPython.display import HTML',
                '',
                'HTML("""',
                '',
                '',
                '',
                '""")',
                '',
            ],
        };
    var hoges = {
        "name" : "hoges",
        "sub-menu" : [
            {
                "name" : "hoge1",
                "snippet" : [
                    'def helloWorld():',
                    '    print("hello world!!)',
                    '',
                ],
            },
            {
                "name" : "hoge2",
                "snippet" : [
                    'def helloWorld2(s_):',
                    '    print("hello world!!" + s_)',
                    '',
                ],
            },
        ],
    };
    snippets_menu.options['menus'] = snippets_menu.default_menus;
    snippets_menu.default_menus[0]['sub-menu'].splice(0, 8);
    snippets_menu.options['menus'][0]['sub-menu'].push(default_import);
    snippets_menu.options['menus'][0]['sub-menu'].push(hide_script);
    snippets_menu.options['menus'][0]['sub-menu'].push(hoges);
    console.log('Loaded `snippets_menu` customizations from `custom.js`');
});

コメント

  1. […] たが,次からは,moduleにこのclassを定義しといて,importして用いる形にしていこうと思う.jupyter notebookのsnippetに関しては,自動で作成がおすすめ.自動でjupyter notebookのsnippetを作成する! […]

  2. […] snippetsに関しては,自動でjupyter notebookのsnippetを作成する! で作成したものを .jupyter/custom/custom.js に置く.  […]

タイトルとURLをコピーしました