nikkie-ftnextの日記

イベントレポートや読書メモを発信

pycampランディングページの参加人数表は誰でも簡単に更新できるよう、Sphinx拡張を自作して実現しました

はじめに

秘密はね、最後に明かされるんだよ、nikkieです。

Python Boot Camp1(a.k.a pycamp)のライディングページを今年Sphinx作りました!2

この実装の一部「過去の開催回で集まった人数」の表について、実装の秘密を明かしちゃいます!

目次

「過去の開催回で集まった人数」の表

ランディングページの下方に位置する参加人数の表。
構成要素は以下です:

  • 開催地
  • 参加人数
  • 開催地からconnpassのイベントページへのリンク

構成要素の他にもう1つ要件を認識していました。
それは、実装したnikkieでなくても簡単に更新できることです。

pycampは今後も開催され3、この表にも行が追加されていきます。
Sphinxでランディングページを作ることにはモチベーションの高いnikkieですが、作り終わった後の行の追加は心の底からやりたいことと感じませんでした。
そのためnikkieに行の追加を依頼する運用だと、nikkieがボトルネックとなり回らなくなる可能性が高いです。
熱しやすく冷めやすい自分の特性を加味した上で、実装者以外でも容易に行を追加できる状態を達成するのが重要と考えました。

案:csv-table × マークアップしたCSV

csv-tableディレクティブに、リンクのマークアップ4を使ったCSVを渡すと動作しました5

開催地,参加人数
`京都 <https://pyconjp.connpass.com/event/33014/>`__,一般参加5人
`愛媛 <https://pyconjp.connpass.com/event/34564/>`__,一般参加11人、学生1人

正しい方法は分かりました!
ですが、この方法は簡単ではないように思われます。
仕組みを知らない人にとっては正しく使えずに、マークアップを間違いうるでしょう。
ブラックボックスにできていないので簡単ではないのだと考えています。

Sphinx拡張を用意して、CSVではマークアップ不要にする

そこで、Sphinx拡張を自作することにしました。
上記のCSVマークアップロジックを拡張にラップします。
以下のようなCSVに行を追加することで、拡張によってリンクが作られて、表の見た目は同一になります。

開催地,URL,参加人数
京都,https://pyconjp.connpass.com/event/33014/,一般参加5人
愛媛,https://pyconjp.connpass.com/event/34564/,一般参加11人、学生1人

作ったディレクティブevent-history-csv-tableEventHistoryCSVTableクラスとして実装しています6
このクラスはCSVTablecsv-tableディレクティブの実装)を継承します。

parse_csv_data_into_rowsメソッドをオーバーライドし、読み込んだcsv_data(行を表す文字列のリスト)の処理を追加します。

csv_dataのイメージ

[
    "開催地,URL,参加人数",
    "京都,https://pyconjp.connpass.com/event/33014/,一般参加5人",
    "愛媛,https://pyconjp.connpass.com/event/34564/,一般参加11人、学生1人",
]

csv_datacsvモジュール7を使ってパースして、1行を

`開催地 <URL>`__,参加人数

の形式に変換します。

こうしてマークアップSphinx拡張にラップされ、「開催地」「URL」「参加人数」の3列からなるCSVに行を追加しさえすれば人数表が更新されるようになりました!🙌
マークアップしてCSVに行を追加するよりも簡単になってますよね

csv-tableディレクティブの動きを知るのに役立ったリソース

以下のブログ記事を参考に、エディタ(VS Code)でCSVTableの定義(docutilsの実装)を確認しながら実装を進めました

アウトプットしていただき、ありがとうございました!

思わぬ収穫:csv.readerはリストも受け付ける

csv.readercsv.DictReaderにはファイルオブジェクトしか渡してこなかったのですが、今回CSVTableクラスの実装を見て分かったのは「イテラブル(例:リスト)8を渡せる」ということ。
実際にcsv_data(リストを指す変数)を渡しています。

reader = csv.DictReader(csv_data)

ドキュメントを引くとcsv.readerの第1引数csvfileについて9

csvfile は イテレータ プロトコルをサポートし、 __next__() メソッドが呼ばれた際に常に文字列を返すような任意のオブジェクトにすることができます --- ファイルオブジェクト でもリストでも構いません。

とあります。
リ ス ト で も 構 い ま せ ん

終わりに

pycampランディングページにある参加人数の表の実装の秘密を明かしました。
表に含まれるリンクは、マークアップの仕方をSphinx拡張にラップし、ランディングページの実装の詳細を知らなくても、CSVに行を追加するだけでページ下部の表にも行が追加されます!
今回得た知見はcsv-tableディレクティブにCSVの処理を追加したいケースで今後も活用できそうに思います。

また、個人的な課題と思っている「正しい使い方を簡単に、誤った使い方を困難に」を練習した例とも思っています。
これは小さな成功体験!(もっとよくできそうなアイデアが浮かんだ方はぜひ教えてくださいませ)

本記事は、先日のPyLadiesTokyo 8周年パーティーでのLTの補足記事でもありました。
https://ftnext.github.io/2022_slides/pyladies_tokyo_anniversary/landing_page_with_sphinx.html#/11 の項目の補足です。