pythonからmarkdown経由でhtmlを簡単に生成できるライブラリを作ってみた

## TL;DR

+ Pythonによるデータ分析結果(のみ)を、お客様向けにhtmlで簡単に出力できるようにするために https://github.com/knknkn1162/mdrec 作った
+ pythonのオブジェクト(`pandas.DataFrame`も含むよ) 突っ込んだら、markdown形式にしてくれる & 生成したmarkdownファイルのhtml化もワンラインでOK!

## 動機

お仕事でデータ解析していて、データ検証の際にJupyter notebook使っています。その時、結果をお客様向けに表や図などを提出する必要性に迫られる時があります(たまーにですけど)。そのときに、markdown形式のファイルでなくて、html形式のファイルとして提出する必要があります。で、もちろんCSSもrenderしたい。

つまり、やりたいことは2つあって、

+ pythonから、簡単にmarkdown形式のものを生成したい(例えば、DataFrameのオブジェクトを突っ込めばmarkdown形式のtableが出力されたり、listを突っ込めば、markdownの箇条書きが得られたりとか)
+ markdownを簡単にhtmlにconvertしたい

です。

後者に関しては、結果的に[grip](https://github.com/joeyespo/grip)を使うことで解決しました[^mot]

前者なんですが、私が探した限りではなさそうだったので[^dataframe]、後者をドッキングしたうえで作っちゃおう、と思ったのがきっかけです。[^first]

[^first]: なにげにpublic repository でライブラリを公開するの初めてですので、アドバイスいただけるとありがたいですm(_ _)m


[^mot]: 最初は、jupyter notebook自体をhtmlに変換すれば、いいかと思っていたのですが、対お客様用にお店する資料のため、Codeが混じっている状態ではいけないです。また、仮にコード部分のみを消したとしても、jupyter notebookの出力結果ににlogやゴミなどが出力結果に残ってしまっては、クオリティを担保できないので、このやり方は早々にボツになりました..  次にpandocとか使ってみたんですが、cssのレンダリングがめんどかったり、GitHub Flavored Markdownなどの拡張markdownに一部対応していなかったり、微調整するのに労力を使ってしまう状態でした。


[^dataframe]: 正確に言えば、dataframeに関しては、[pytablewriter](https://github.com/thombashi/pytablewriter)があったんですが、今回はDataFrame型に限らず、出来る限りいろいろな型に対応したmarkdown形式のtext吐き出し君を作りたかった。pytablewriterは内部で使ってます。

## インストール方法

pipでインストールできるようにしました。

```bash
pip install mdrec
```


## 使い方

+ GitHub Flavored Markdown形式の見出し、箇条書き、DataFrame, link, image, quote, 水平線、およびhtmlにexportする機能を装備してます[^link]。コード例と、出力結果は、
https://github.com/knknkn1162/mdrec#example に載せましたが、雰囲気的には、こんな感じで使います：

```python
from mdrec import MDRec
from pandas import DataFrame


# set markdown file. (save_file argument is optional)
save_file = "./out/test_txt.md"
r = MDRec(save_file=save_file)

# suppoort header.
r.rec("testtest", h=2)
r.rec("short example")

# support DataFrame or Series
df = DataFrame([[12, 2, 4, 3], [3, 3, 3, 4]], columns=list("abcd"), index=["AB", "BB"])

# display table with title
r.rec(df, title="test", h=3)

# image with markdown syntax (also support link)
# By default the image file is copied on `${md_dir}/img` directory.
r.img(src="./test.png", title="test", text="sample")

# export markdown file to html via github API. (You can set your username and password in ~/.grip/settings.py.)
r.to_html()
```

とすると、以下のようなmarkdownファイルとhtmlファイルが生成されます:

```md
## testtest

short example

### test
|   |  a  |  b  |  c  |  d  |
|---|----:|----:|----:|----:|
|AB |   12|    2|    4|    3|
|BB |    3|    3|    3|    4|


![sample](img/test.png "test")

```

htmlファイル：

<img width="887" alt="スクリーンショット 2017-10-01 23.37.37.png" src="https://qiita-image-store.s3.amazonaws.com/0/133922/37a9daf8-1eb4-095b-6f7d-b16771b8d687.png">

jupyter notebook上で実行すると...

<img width="666" alt="スクリーンショット 2017-10-02 0.00.00.png" src="https://qiita-image-store.s3.amazonaws.com/0/133922/7c34f2db-080c-4691-4bf8-8315a33585b9.png">

こんな感じになります:rice:



---

+ 強調とか、取り消し線とかinnerな機能は`rec("test **em**")`みたいな感じで、明示的に書いてください。 blockquote( `> `)は使えます.

+ jupyter notebookを用いる際は、上のコードを実行すると、上のようにデフォルトでdisplayされます。(つまり、`MDRec`クラスのメソッドは`IPython.display.display_markdown`相当の機能を持ってます). ただし、この機能は、`raw`引数を`False`にすることでoffにもできます。


---

+ htmlにexportする際は、[grip](https://github.com/joeyespo/grip)を暗に用いております。`grip`自体はmarkdownのhtml化にGitHub APIを用いているのですが、ユーザー名やパスワードを設定なしの状態ではGitHub APIの制限がきついため、複数のmarkdownファイルをexportするときは注意が必要です。
その時は、`~/.grip/settings.py`に

```~/.grip/settings.py
USERNAME = 'your-username'
PASSWORD = 'your-personal-access-token-or-password'
```

と設定すれば制限をいくらか解除してくれます (https://github.com/joeyespo/grip#configuration も参照)

-----

こうやったらいいよとか、こういう機能欲しいとかあれば、qiitaのコメントやgithubのissueに投下してくだされば嬉しいです:relaxed:

[^link]: もちろん、markdown fileに対応して、相対パスを書き込むようになってる

## 感想

+ 自作ライブラリ公開したけど、反応がなくって寂しい笑

+ Pathlib使ってみた。`Path.relative_to`が`os.path.relpath`の挙動でなかったことにちょっとがっかりした.

+ PyPi登録初体験だったけど、公開までの一連の方法がわかって良かった ( 普通に最初は、公式ドキュメント https://packaging.python.org/tutorials/distributing-packages/ を見ましょう。日本語ならば、https://qiita.com/icoxfog417/items/edba14600323df6bf5e0 がmimimumな説明でよいです)

+ gitの使い方に関して、setupを修正したり、masterにmergeしたりする部分がすごくいい加減なので、どうしたらいいかなぁ、って思いました(改めてgitの使い方見直すかぁ)

+ 自作ライブラリを自分のためだけに作っていたときは意識していなかったのですが、実現できることの割に依存ライブラリ多すぎですね.. `pip freeze`して確認したら、大小55個の依存ライブラリがinstallされてた

+ CIあんまり使ったことないので、今度試したい