読者です 読者をやめる 読者になる 読者になる

sphinxでtsv-tableできなかった!(後編)

sphinx

sphinxでtsv-tableできなかった!(前編) - think it over

で、csv-tableと同等の機能を持つtsv-tableの作成までできました。
後編では断念するまでの経緯をまとめておこうかと。

csv-tableの実装を確認

前編でも触れましたが、

/usr/lib/python2.7/site-packages/docutils-0.10-py2.7.egg/docutils/parsers/rst/directives/tables.py

のソースを確認すると、

「parse_csv_data_into_rows」

というわかりやすい名前の関数があります。

    def parse_csv_data_into_rows(self, csv_data, dialect, source):
        # csv.py doesn't do Unicode; encode temporarily as UTF-8
        csv_reader = csv.reader([self.encode_for_csv(line + '\n')
                                 for line in csv_data],
                                dialect=dialect)
        rows = []
        max_cols = 0
        for row in csv_reader:
            row_data = []
            for cell in row:
                # decode UTF-8 back to Unicode
                cell_text = self.decode_from_csv(cell)
                cell_data = (0, 0, 0, statemachine.StringList(
                    cell_text.splitlines(), source=source))
                row_data.append(cell_data)
            rows.append(row_data)
            max_cols = max(max_cols, len(row))
        return rows, max_cols

実際にCSV形式のコンテンツの読み込みを行っているのは「csv.reader」であることがわかります。

csvっていいながらも区切り文字を指定できるんでしょ、と調べると以下に辿り着く。
13.1. csv — CSV ファイルの読み書き — Python 2.7ja1 documentation

そこに記述されている、「短い利用例」を引用すると、

>>> import csv
>>> spamReader = csv.reader(open('eggs.csv', 'rb'), delimiter=' ', quotechar='|')
>>> for row in spamReader:
...     print ', '.join(row)
Spam, Spam, Spam, Spam, Spam, Baked Beans
Spam, Lovely Spam, Wonderful Spam

おお!やはり「delimiter」なるものが!!!

タブ区切りに♪

早速、parse_csv_data_into_rowsをtsv-tableでオーバーライドする。
delimiterに「\t」を指定して、rstをタブ区切りにして、make html!

 ERROR: "tsv-table" widths do not match the number of columns in table (1).

あちゃー。

もともと「タブ区切りは外部ファイルに定義しなきゃだめよ」という制約があったので、
そんな単純に行く訳ないかと反省し、処理を追いはじめる。

タブがスペースに?誰が?

まずは、parse_csv_data_into_rowsに渡されている、csv_dataの中身を確認してみると、
なんと、タブがない。スペースに置き換わっている??


parse_csv_data_into_rowsを起点にして呼出し元を

さかのぼり、
さかのぼり、、
さかのぼり、、、


行き着いた先は、、、、

/usr/lib/python2.7/site-packages/docutils-0.10-py2.7.egg/docutils/parsers/rst/__init__.py

貴様か、Parser

__init__.pyの中にParserというクラスが定義されており、parse関数の中身を見ると、こんな処理が。

        inputlines = docutils.statemachine.string2lines(
              inputstring, tab_width=document.settings.tab_width,
              convert_whitespace=True)

convert_whitespace。ほーーう。

特定のために前後にデバッグプリントを埋め込む

        print inputstring.split("\n")
        inputlines = docutils.statemachine.string2lines(
              inputstring, tab_width=document.settings.tab_width,
              convert_whitespace=True)
        print inputlines

結果、

[u'.. tsv-table::', u'   :header: "\u958b\u59cb"\t"\u7d42\u4e86"\t"\u6642\u9593"\t"\u5185\u5bb9"', u'   :widths: 10, 10, 10, 200', u'', u'   09:00\t09:10\t00:10\t\u30c6\u30b9\u30c8', u'']
[u'.. tsv-table::', u'   :header: "\u958b\u59cb"        "\u7d42\u4e86"    "\u6642\u9593"    "\u5185\u5bb9"', u'   :widths: 10, 10, 10, 200', u'', u'   09:00        09:10   00:10   \u30c6\u30b9\u30c8']

おお、、、、こいつだ。。。

挑戦は続けます

Parser.parse関数を書き換えてしまうのは影響範囲が計り知れない、そして時間の都合で今回はここで断念。。。

いつか近いうちにリベンジします。