金魚亭日常

読書,ガジェット,競技プログラミング

python で Rのdevtools::session_info() 的なやつ

jupyter notebook のはなしです.

rasbt/watermark を使う

https://github.com/rasbt/watermark を使って,

%load_ext watermark
%watermark -u -d -v -p numpy,pandas,matplotlib

とすると

last updated: 2016-10-12 

CPython 3.5.2
IPython 5.1.0

numpy 1.11.1
pandas 0.18.1
matplotlib 1.5.1

というふうに,CPython, IPython,-p で渡したパッケージのバージョンが出力される. magic には $var で変数を渡せるので,モジュール一覧を取得する方法を考える

インポートしたモジュールを取得する

http://stackoverflow.com/questions/20703975/is-there-a-sessioninfo-equivalent-in-python より,

def imports():
    import types
    for name, val in globals().items():
        if isinstance(val, types.ModuleType):
            yield val.__name__
excludes = ['types', 'builtins', 'IPython.core.shadowns']
imported_modules = [module.split(".")[0] for module in imports() if module not in excludes]

とやると一覧がリストになる.

module.split(".")[0]

としているのは,サブモジュールをインポートしている場合があるので.

magic にする

from IPython.core.magic import register_line_magic
@register_line_magic
def imports_(param=''):
    def imports():
        import types
        for name, val in globals().items():
            if isinstance(val, types.ModuleType):
                yield val.__name__
    excludes = ['types', 'builtins', 'IPython.core.shadowns']
    imported_modules = [module.split(".")[0] for module in imports() if module not in excludes]
    return ",".join(imported_modules)

del imports_

と書いて,適当なファイル名で,.ipython/startup に置く(.jupyter ではない). なお,

def imports_(param=’’):

としているのは,引数なしにすると,引数0なのに1個渡された,的なエラーが出たので.

あとは,jupyter notebook 上で,

imports = %imports_
%load_ext watermark
%watermark -u -d -v -p $imports

とする.

別解: ASTから取得

自分の環境では,notebook(.ipynb) を保存すると同時に .py と .html が保存されるようになっているので,.py を ASTにして,Import と ImportFrom を抜き出す,という方法を考えた. 先ほどのmagic を書いたファイルに以下を追加して,

@register_line_magic
def packages_(source):
    import ast
    source = open(source, "r", encoding="utf-8").read()
    tree = ast.parse(source)
    def select_imports(node):
        if isinstance(node, ast.Import):
            return node.names[0].name.split(".")[0]
        elif isinstance(node, ast.ImportFrom):
            return node.module.split(".")[0]
        else:
            return None
    imports = [select_imports(node) for node in ast.walk(tree)]
    packages = ",".join(list(set([i for i in imports if i is not None])))
    return packages

最後のdel を変更する.

del packages_, imports_

実行

packages = %packages_ notebook.py
%load_ext watermark
%watermark -u -d -v -p $packages