🎁

'Toybox(おもちゃ箱)'という命名思想

2024/12/15に公開

※若干「アイデア」感のある記事ですが、一応「技術記事」のつもりで書いています。

atsphinx-toybox

自分は、内外の需給を拾った結果としてatsphinxというSphinx拡張のコレクションを作っています。
基本的には「1機能1プロジェクト」で公開しているのですが、最近になって特に無関係な複数機能をまとめたatsphinx-toyboxというプロジェクトを公開するようになりました。

https://pypi.org/project/atsphinx-toybox/

一応、ある程度の思考を経てこの形式での公開をするようにしたのですが、この記事ではそのあたりの考えをまとめてみます。

個別のプロジェクトを作ることで起きること

普段はatsphinx-FOOBARのようなプロジェクトとして公開していますが、この運用のほうが楽な理由もあります。

改修等における【余波】を可能な限り減らせる

それぞれのプロジェクトが完全な独立をしているということは、「特定のプロジェクトだけ依存ライブラリのバージョンを変える」ことが容易になります。
特にものによっては依存ライブラリが複数あって、「このバージョン以上でないと動かないor楽」というケースは起こりえます。

今はあまり考慮する必要がないですが、機能がやや複雑になったケースで「新しめの文法を使って書いたほうが良い」ときなどにも有効となるでしょう。

インストールを容易にすることで、自分以外の「思わぬ賛同者」を拾える

PyPIからpipなどで「普通にインストールできる」ということは、利用者にとって利用障壁を低くすることが出来ます。

例えば、Gist上に野良プロジェクトとして公開することなども出来ますが、利用者視点だとインストールや不具合への対処はどうしても煩雑になってしまいます。
一方で、PyPI上に適宜バージョン管理をしてプロジェクトを公開しておくことで、自分にとってもコントロールがしやすい形態を維持できるようになります。

共通的な領域を見出すことにより、プロジェクトの【型】を作り出せる

【Pythonプロジェクト】の体裁を取るには、機能のコードだけでなく多くの要素が必要になります。

  • メタデータを管理するファイル。
  • 動作を担保するテストコード。
  • 利用方法を説明するドキュメント。
  • これらの管理を適切に運用するためのワークフロー。

上に挙げた内容の大半は、Pythonプロジェクトとしてほとんど同じものを使うことになります。

結果的に、ボイラープレートと呼ばれる【型】を作ることになるのですが、安定した品質の開発に大きく寄与します。
また「【型】そのものをメンテナンスする」プロセスが産まれて、より安定した構成を組み上げるための情報を集める動機づけにもなります。

少なからず、「プロジェクトに対するメンテナンス責務」が産まれる

とはいえ、グローバルな環境に「任意のユーザーが利用可能である」状態で公開するということは、どうしても製造者責任といえるものがより強くなってしまいます。
自分の場合は利用者自体が少ないのと利用ケースでこういうことが起きにくいですが、致命的な脆弱性があるのであれば利用者のためにフォローアップは必要になってきます。

また、賛同だけでなく批判の対象にならざるを得ない点についても気をつけないといけないでしょう。

Toybox = おもちゃ箱

上記の点を「積極的に回避する」とまでは言わないのですが、これらを踏まえた上でToyboxという名前でのPythonプロジェクトを作って公開することにしました。
考え方としては、主に以下のようなことを考慮して命名、公開をしています。

「実用を考慮していない」ことを明示したかった

すでに何度か出ている通り、Toyboxは文字通り「おもちゃ箱」という意味を持たせています。
これは、「遊び場的プロジェクトである」ことを起点に「実用度外視のものも置く」「そのまま放ったらかしにする可能性もある」という思想を意図しています。

もちろん、結果として「需要がありそうだから普通のPythonプロジェクトにする」可能性はゼロではないですが。

メンテナンス性を考慮しない「無茶な実装」を雑にしてみたかった

「【型】を起点に開発する」という考え方は、どうしても「【型】から外れたことをしにくくなる」ことを意味します。

atsphinx-toybox自体は、一番最初こそ【型】から作ってはいますが、テストを積極的に書くかをあまり考えないようにしています。
というのも、時折実装として思い切ったことをするケースが出てくるため、正直に言えば「テストが面倒になりそう」となりそうだからです。

雑な動作確認自体はするし、デモは書くのですが、「無茶な実装」を前提に本当に最低限のことだけするようにしています。

別のバージョニングポリシーをつけたかった

他のatsphinx-FOOBAR系列は、セマンティックバージョニングを目安にバージョン更新しています。
そのため、CHANGELOGも真面目に書いていますし、破壊的な変更についても多少なりとも気を使っています。

一方で、atsphinx-toyboxではCalver(いわゆる日付ベースのバージョニング)を採用しています。
これには「カジュアルに更新するし実用は度外視である」ことなどをバージョニング側にも含ませる意図が有ります。

流石に作りすぎた

今年の秋にPyCon JPのDeveloper Sprintでatsphinx-pytutorを作ってみたのですが、あまりにも勢い任せで作ってしまったという反省があります。
この反省を踏まえて「何かしらの明確な需要が(自分を含めて)存在する」のでなければ、以降はこっちに置こうと考えています。

おまけ: この時点で内包する機能

そんな思想で作っているToyboxですが、この記事を書いている時点でどんなことが出来るのかを軽く紹介しようと思います。

いくつかの動作については、下記のドキュメント内で確認できます。

https://atsphinx.github.io/toybox/en/

atsphinx.toybox.sass

Sphinxのビルド時に、まとめてSASS/SCSSをビルドするための拡張機能です。
もしかしたらsphinxcontrib-sassを見たことがある人もいるかもしれません。

あちらと比較した際の最大の違いは「ビルド処理にdart-sassを使う」点です。
更に「初回のビルド時にdart-sassの実行バイナリをGitHubから取ってくる」という無茶をしています。

結果的に、dart-sassのリリースに非対応な環境は全切りとなる代わりに、次の恩恵を得ました。

  • libsass-pythonが不要になったためインストール自体が極めて楽になった。
  • dart-sassのビルド済みでない環境では一切動かなっくなった。
  • SASSのコンパイルが多分早くなった。

atsphinx.toybox.stlite

Python製のWeb UIフレームワークにStreamlitというものがあり、これをWebAssembly上で動作するようにしたものとしてStliteが有ります。
この拡張では、Stliteディレクティブを用意することで、Sphinxドキュメント内にStliteの動作を表示させられるようになります。

demo.rst
.. stlite::
   :id: stlite-demo
   :requirements: matplotlib

   import streamlit as st
   import matplotlib.pyplot as plt
   import numpy as np

   size = st.slider("Sample size", 100, 1000)

   arr = np.random.normal(1, 1, size=size)
   fig, ax = plt.subplots()
   ax.hist(arr, bins=20)

   st.pyplot(fig)

実装の関係で、「Stliteを動作させる単体のHTMLを生成してiframeに埋め込む」というちょっとトリッキーなことをしています。

Sphinxにおける日本語ドキュメントの検索には、全文検索向けのトークン分割をしています。
このパッケージでは、Rust製の形態素解析エンジンであるLinderaをトークン分割に使えるような実装を用意しています。

なお、依存ライブラリとしてlindera-pyを要求するのですが、Wheelだと40MBもあります。
とはいえ、動作自体はだいぶ軽量なので、ドキュメント全体の検索性能向上が図れるのであれば良い投資と言えるのではないでしょうか。

実際に組み込んでみた記事がこちらです。記事内では言及していないですが、検索時のスコアリングが若干変わっています。

https://zenn.dev/attakei/articles/tokenize-japanese-on-sphinx

Discussion