uvとsphinxでパッケージのdocsを自動生成

# 概要
uvで管理しているpythonパッケージのドキュメントをsphinxで自動生成する手順をまとめました。
sphinx公式のドキュメントやqiitaなどを参照しつつ進めましたが、完全に同じ状況の参考記事がなかったため、試行錯誤した部分が多く、またsphinxも触るのが初めてなため、いろいろ変なことをやっているかもしれません。ご容赦ください。

# 目標
`uv init --lib`で初期化したパッケージのAPIリファレンスをsphinxで自動生成したいです。
チュートリアルなどはあとまわしです。
とりあえず、パッケージと同じような階層で、ソースコード中のdocstringに基づいてドキュメントが生成できればよしとします。

# リポジトリ構成

`uv init --lib`で初期化した場合の以下のような構成を前提とします。

```
my_pkg/
├── src/
│   └── my_pkg/
├── docs/
├── pyproject.toml
```

主なポイント
- ソースコードは`src/my_pkg/`に配置
- ドキュメントは`docs/`ディレクトリに作成
- 依存関係は`pyproject.toml`で管理

# Sphinx導入手順

## 1. 必要なパッケージのインストール

```sh
uv add sphinx sphinx-rtd-theme autodoc-pydantic --dev
```
## 2. Sphinxの初期設定

1. プロジェクトのルートディレクトリで以下のコマンドを実行してSphinxを初期化します：

```bash
uv run sphinx-quickstart docs
```

2. 対話形式で以下のような質問が表示されます：
   - Separate source and build directories (y/n) [n]: y
   - Project name: MyPkg
   - Author name(s): name
   - Project release []: 0.1.0
   - Project language [en]: ja

## 3. 設定ファイル

### conf.py
`docs/source/conf.py`を以下のようにする

```python
import os
import subprocess
import sys

sys.path.insert(0, os.path.abspath("../../src"))


def get_version():
    try:
        # 最新のgit tagを取得
        tag = subprocess.check_output(
            ["git", "describe", "--tags", "--abbrev=0"], universal_newlines=True
        ).strip()
        return tag
    except subprocess.CalledProcessError:
        # git tagが存在しない場合はデフォルトのバージョンを返す
        return "0.1.0"


# Configuration file for the Sphinx documentation builder.
#
# For the full list of built-in configuration values, see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html

# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information

project = "MyPkg"
copyright = "2025, name"
author = "name"
version = get_version()
release = version
language = "ja"

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration

extensions = [
    "sphinx.ext.autodoc",  # ソースコード読み込み用
    "sphinx.ext.napoleon",  # docstring パース用
    "sphinxcontrib.autodoc_pydantic",  # pydanticのドキュメント生成用
]


templates_path = ["_templates"]
exclude_patterns = []


# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output

html_theme = "sphinx_rtd_theme"
# -- Options for sphinx-multiversion -----------------------------------------
```

ポイントは以下。

- versionはget_version関数でgitのtagから自動で取得
- extensionsは`autodoc`、`napoleon`、`autodoc-pydantic`の３つ。
- html_themeに`sphinx_rtd_theme`を使用

### index.rst

`docs/source/index.rst`を以下のようにする。

```rst
.. my_pkg documentation master file, created by
   sphinx-quickstart on Wed Mar 19 17:33:32 2025.
   You can adapt this file completely to your liking, but it should at least
   contain the root `toctree` directive.

MyPkg ドキュメント
===================================

バージョン: |version|

（プロジェクトの概要）

主な機能
--------

- 機能1
- 機能2

Contents
--------

.. toctree::
   :maxdepth: 2
   :caption: Contents:

   modules
```

主なポイントは以下

- toctreeに`modules`を追加。これは後にautodocで自動生成されるrstの名前。

### タスク（pyproject.toml）

taskipyを使用してタスクコマンドを実行します。

```sh
uv add taskipy --dev
```

pyproject.tomlにタスクコマンドを追加します。
docs-generateはソースコードに基づきhtmlを生成するコマンドです。
docs-openはhtmlをブラウザで開いて確認するコマンドです。mac以外の場合openコマンドは使えないかもしれません。

```toml:pyproject.toml
[tool.taskipy.tasks]
docs-generate = "sphinx-apidoc -f -o docs/source src/my_pkg && sphinx-build -M clean docs/source docs/build && sphinx-build -M html docs/source docs/build"
docs-open = "open docs/build/html/index.html"
```


## 4. APIドキュメントの自動生成

pyproject.tomlで設定したタスクコマンドを使います。

```sh
uv run task docs-generate
```

docs/sourceにモジュールごとのrstファイルとmodule.rstが生成されます。
docs/build/html/index.htmlが生成されます。
なおbuild時に警告がでますが、そこまで問題なさそうなので無視します。

## 5. 確認

```bash
uv run docs-open
```

ブラウザでそれっぽいドキュメントページが見られればOKです。

# おわりに
sphinxの設定時に意識したことをまとめておきます。
- extensionはミニマムには以下でよさそう
  - autodoc: ソースコードのdocstringに基づいてAPIリファレンスを作るために必要
  - napoleon: Google形式などのdocstringをパースするために必要
  - autodoc-pydantic: pydanticを使っている場合、フィールドの情報などをパースするために必要。上２つに比べると必須ではないが便利。
- ドキュメントに表示するバージョンはgitのタグから自動で取得
- rstファイルやhtmlの自動生成コマンドはソースコードの変更のたびに使うため、taskに追加して効率化

以上です。似たような構造のリポジトリで開発している方の参考になれば幸いです。