Emacs + IPythonでmoduleをautoreloadする設定

# 概要
Emacsで`(setq python-shell-interpreter "ipython")`してる人は，IPythonのconfig.pyをいじってない限り，次のコードを`init.el`に書いておくと良い．

```elisp:init.el
(let* (
       (profile-name "profile_for_emacs")
       (folder-name-getter `(substring (shell-command-to-string (concat "ipython locate profile " ,profile-name)) 0 -1))
       )
    (unless (file-directory-p (eval folder-name-getter))
      (shell-command (concat "ipython profile create " profile-name))
      (let ((ipython-config-folder (eval folder-name-getter)))
        (shell-command (concat "echo \"\n\nc.InteractiveShellApp.extensions.append(\\\"autoreload\\\")\nc.InteractiveShellApp.exec_lines.append(\\\"%autoreload 2\\\")\" >> " ipython-config-folder "/ipython_config.py"))
        )
      )
    (set-variable 'python-shell-interpreter-args (concat "--profile=" profile-name " " python-shell-interpreter-args))
    )
```

# 問題定義
みなさん，Emacs使ってますか？

Emacs内でPythonを書いているとき，`C-c C-c (python-shell-send-buffer)`でコードを実行する機会は多いと思います．
しかし，何も設定していない場合，一度`import`されたmoduleはインタプリタを閉じるまで再ロードされません．

すなわち，

1. 複数ファイルに渡るPythonコードを書く．
2. `C-c C-c`でバッファの内容をインタプリタに送り，実行する．
3. 自前のmodule内でエラーが出たので，**エラー箇所を修正する**．
4. 再び実行する．
5. **修正したはずなのに，同じエラーが出る．**

ということが起こります（起こりました）．

これは，2. の段階で`import`されたmoduleが，3. で修正されたあとも再importされないことによって起こっています．
この問題を解決しましょう．

# 解決案

## 解決案1 Pythonファイルに直接書く

[引用元](https://emacs.stackexchange.com/questions/13476/how-to-force-a-python-shell-to-re-import-modules-when-running-a-buffer "引用元")

pythonファイルで，以下のように`import`します:

```python:foo.py
import mymodule
import importlib
importlib.reload(mymodule)
```

ソースコードの方に，毎回リロードを強制するように書く，という案です．
moduleが多いと大変だし，Emacsの設定不足をソースコードに押し付けているという点でちょっとダサいです．

## 解決案2 Pythonプロセスを毎回killする

[引用元](http://lgmoneda.github.io/2017/02/19/emacs-python-shell-config-eng.html "引用元")

`init.el`に以下を追記します:

```elisp:init.el
;; Run python and pop-up its shell.
;; Kill process to solve the reload modules problem.
(defun my-python-shell-run ()
  (interactive)
  (when (get-buffer-process "*Python*")
     (set-process-query-on-exit-flag (get-buffer-process "*Python*") nil)
     (kill-process (get-buffer-process "*Python*"))
     ;; Uncomment If you want to clean the buffer too.
     ;;(kill-buffer "*Python*")
     ;; Not so fast!
     (sleep-for 0.5))
  (run-python (python-shell-parse-command) nil nil)
  (python-shell-send-buffer)
  ;; Pop new window only if shell isnt visible
  ;; in any frame.
  (unless (get-buffer-window "*Python*" t) 
    (python-shell-switch-to-shell)))

(defun my-python-shell-run-region ()
  (interactive)
  (python-shell-send-region (region-beginning) (region-end))
  (python-shell-switch-to-shell))

(eval-after-load "python"
  '(progn
     (define-key python-mode-map (kbd "C-c C-c") 'my-python-shell-run)
     (define-key python-mode-map (kbd "C-c C-r") 'my-python-shell-run-region)
     (define-key python-mode-map (kbd "C-h f") 'python-eldoc-at-point)))
```

`python-shell-send-buffer`を自前で用意して，Pythonコードを実行するタイミングで`*python*`バッファに`Ctrl-D`を送り，インタプリタを再起動しています．
問題は解決していますが，複数のコードを順番に実行したいときや，インタプリタに少し書き込んでからバッファを実行したいときに困ってしまいます．

moduleの再インポートがしたいだけなので，もっと副作用の少ない方法が望ましいです．

## 解決案3 IPythonを使い，%autoreloadする

[引用元](https://qiita.com/Accent/items/f6bb4d4b7adf268662f4 "引用元")

インタプリタとして`IPython`を使います．そのために，`init.el`に以下を追記します:

```elisp:init.el
(setq python-shell-interpreter "ipython")
```

`C-c C-c`を最初にしたときに，インタプリタ上で以下を実行します:

```python:IPython-interpreter
In [1]: %load_ext autoreload
In [2]: %autoreload 2
```

これで，このバッファが閉じるまではmoduleが自動的にリロードされるようになり，問題は解決します．

これでも良いですが，一度Emacsを閉じるとまたこのコマンドを打たなければならず，やっぱりダサいです．

## 解決案4 IPython config fileを使い，起動時自動的に%autoreloadする

[引用元](https://stackoverflow.com/questions/14760196/how-to-reload-python-modules-on-python-shell-send-buffer-in-emacs "引用元")

解決案3の自動化です．
インタプリタとして`IPython`を使います．

まず，shellで以下のようにconfigファイルを作成します:

```sh:bash
$ ipython profile create foo
[ProfileCreate] Generating default config file: u'/home/username/.config/ipython/profile_foo/ipython_config.py'
```

作成した`ipython_config.py`の場所を教えてくれるので，そのconfigファイルに以下を追記します:

```python:ipython_config.py
c.InteractiveShellApp.extensions = ['autoreload']
c.InteractiveShellApp.exec_lines = ['%autoreload 2']
```

最後に，`init.el`に以下を追記します:

```elisp:init.el
(setq
   python-shell-interpreter "ipython"
   python-shell-interpreter-args "--profile=foo"
)
```

この方法では，一度Profileを作ってしまえば，起動時に自動的にそのProfileを読んでくれるので，かなり手間を省くことができます．


これでいいじゃん と思う方もおられるかと思いますが，Emacs教のいち信者としては，Emacsの設定なのにshellを触らなければならないのはダサいです．

理想はやはり，**まっさらな環境に最小構成の`.emacs.d`を持ってきて，チョンと`Emacs`を起動するとドコドコ必要な設定がインストールされていつものエディタが立ち上がる**，という感じではないでしょうか．

# 提案手法

以上を踏まえて，解決案4を`emacs lisp`だけで書いたのがこちらです．

```elisp:init.el
(setq python-shell-interpreter "ipython")
(let* (
       (profile-name "profile_for_emacs")
       (folder-name-getter `(substring (shell-command-to-string (concat "ipython locate profile " ,profile-name)) 0 -1))
       )
    (unless (file-directory-p (eval folder-name-getter))
      (shell-command (concat "ipython profile create " profile-name))
      (let ((ipython-config-folder (eval folder-name-getter)))
        (shell-command (concat "echo \"\n\nc.InteractiveShellApp.extensions.append(\\\"autoreload\\\")\nc.InteractiveShellApp.exec_lines.append(\\\"%autoreload 2\\\")\" >> " ipython-config-folder "/ipython_config.py"))
        )
      )
    (set-variable 'python-shell-interpreter-args (concat "--profile=" profile-name " " python-shell-interpreter-args))
    )
```

やっていることは解決案4とほぼ同じです．
起動時に`ipython locate profile (profile-name)`を実行して，profileが無かったら作ります．
作ったconfigファイルに`autoreload`設定を直接`echo`でぶち込みます．

これでだいぶ気が楽になりました．

それでは，よいEmacsライフを．