Sphinx

GitHub概要

sphinx-doc/sphinx

The Sphinx documentation generator

スター7,284
ウォッチ165
フォーク2,257
作成日:2015年1月2日
言語:Python
ライセンス:Other

トピックス

docsdocumentationdocumentation-toolmarkdownpythonrestructuredtextsphinx

スター履歴

sphinx-doc/sphinx Star History
データ取得日時: 2025/8/13 01:43

ドキュメント作成ツール

Sphinx

概要

SphinxはPythonで開発された強力なドキュメント生成ツールです。reStructuredText(rST)をベースとし、APIドキュメント自動生成、学術論文執筆、技術文書作成に特化した豊富な機能を提供します。

詳細

Sphinx(スフィンクス)は2008年にGeorg Brandlによって開発され、Pythonコミュニティの標準的なドキュメントツールとして確立されています。当初はPython公式ドキュメントの作成のために開発され、現在でもPython、Django、Flask等の多くのプロジェクトで使用されています。reStructuredTextマークアップ言語により、構造化された高品質なドキュメントを作成できます。autodoc拡張により、Pythonコードから自動的にAPIドキュメントを生成できます。数学記法、交差参照、索引作成、多言語対応など学術的な文書作成に必要な機能を網羅しています。多様な出力形式(HTML、PDF、ePub、LaTeX等)をサポートし、単一のソースから複数の形式のドキュメントを生成できます。豊富なテーマとエクステンションにより、カスタマイズ性と拡張性を実現しています。Napoleon拡張により、GoogleスタイルやNumPyスタイルのdocstringもサポートします。2025年現在、Read the Docs、Alabaster、Furoなどの人気テーマにより、美しく機能的なドキュメントサイトを構築できます。Sphinx-autodocによるAPI文書自動化、Sphinx-galleryによるサンプル集成、sphinx-needs等の要求管理拡張により、プロフェッショナルなドキュメント作成環境を提供しています。

メリット・デメリット

メリット

  • APIドキュメント自動生成: Pythonコードのdocstringから自動的にAPIリファレンス作成
  • 多様な出力形式: HTML、PDF、ePub、LaTeX、man等の豊富な出力フォーマット
  • 学術文書対応: 数式、引用、索引、交差参照など学術論文作成機能
  • 豊富なエクステンション: todo管理、図表生成、テスト実行など多彩な拡張機能
  • プロフェッショナル品質: 出版レベルの高品質なドキュメント出力
  • テーマシステム: Read the Docs、Alabaster、Furo等の美しいテーマ
  • 国際化対応: 多言語ドキュメントの効率的な管理とローカライゼーション

デメリット

  • 学習コスト: reStructuredText記法とSphinx設定の習得に時間が必要
  • Python依存: Python環境とPythonエコシステムの知識が必要
  • 複雑な設定: 高度な機能利用時の設定ファイル(conf.py)の複雑化
  • マークダウン非対応: デフォルトではMarkdownサポートなし(拡張で対応可能)
  • ビルド時間: 大規模プロジェクトでのドキュメント生成時間の増加
  • デザイン制限: テーマカスタマイズにはCSS/HTMLの専門知識が必要

主要リンク

書き方の例

プロジェクトの初期化

# Sphinxのインストール
pip install sphinx

# プロジェクトの作成
sphinx-quickstart docs

# プロジェクト構造
docs/
├── _build/           # 生成されたドキュメント
├── _static/          # 静的ファイル(CSS、JS、画像)
├── _templates/       # カスタムテンプレート
├── conf.py          # 設定ファイル
├── index.rst        # メインページ
└── make.bat         # Windowsビルドスクリプト

基本的なconf.py設定

# Configuration file for the Sphinx documentation builder.

# -- Project information -----------------------------------------------------
project = 'プロジェクト名'
copyright = '2025, 作成者名'
author = '作成者名'
release = '1.0.0'

# -- General configuration ---------------------------------------------------
extensions = [
    'sphinx.ext.autodoc',        # APIドキュメント自動生成
    'sphinx.ext.autosummary',    # サマリー自動生成
    'sphinx.ext.napoleon',       # Google/NumPyスタイルdocstring
    'sphinx.ext.viewcode',       # ソースコードへのリンク
    'sphinx.ext.intersphinx',    # 他プロジェクトとの相互参照
    'sphinx.ext.mathjax',        # 数学記法サポート
    'sphinx.ext.githubpages',    # GitHub Pages対応
    'sphinx.ext.todo',           # TODOリスト管理
]

# Templates path
templates_path = ['_templates']

# Language settings
language = 'ja'

# Exclude patterns
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']

# -- Options for HTML output ------------------------------------------------
html_theme = 'sphinx_rtd_theme'
html_static_path = ['_static']
html_title = 'プロジェクトドキュメント'
html_short_title = 'プロジェクト'
html_logo = '_static/logo.png'
html_favicon = '_static/favicon.ico'

# テーマオプション
html_theme_options = {
    'analytics_id': 'G-XXXXXXXXXX',
    'logo_only': False,
    'display_version': True,
    'prev_next_buttons_location': 'bottom',
    'style_external_links': False,
    'vcs_pageview_mode': '',
    'style_nav_header_background': '#2980B9',
    'collapse_navigation': True,
    'sticky_navigation': True,
    'navigation_depth': 4,
    'includehidden': True,
    'titles_only': False
}

# -- Options for LaTeX output -----------------------------------------------
latex_elements = {
    'papersize': 'a4paper',
    'pointsize': '10pt',
    'preamble': r'''
\usepackage[utf8]{inputenc}
\usepackage[japanese]{babel}
''',
}

latex_documents = [
    ('index', 'project.tex', 'プロジェクトドキュメント',
     '作成者名', 'manual'),
]

# -- Napoleon settings ------------------------------------------------------
napoleon_google_docstring = True
napoleon_numpy_docstring = True
napoleon_include_init_with_doc = False
napoleon_include_private_with_doc = False
napoleon_include_special_with_doc = True
napoleon_use_admonition_for_examples = False
napoleon_use_admonition_for_notes = False
napoleon_use_admonition_for_references = False
napoleon_use_ivar = False
napoleon_use_param = True
napoleon_use_rtype = True

# -- Autodoc settings -------------------------------------------------------
autodoc_default_options = {
    'members': True,
    'member-order': 'bysource',
    'special-members': '__init__',
    'undoc-members': True,
    'exclude-members': '__weakref__'
}

# -- Todo extension settings ------------------------------------------------
todo_include_todos = True

# -- Intersphinx mapping ----------------------------------------------------
intersphinx_mapping = {
    'python': ('https://docs.python.org/3', None),
    'django': ('https://docs.djangoproject.com/en/stable/', None),
    'numpy': ('https://numpy.org/doc/stable/', None),
}

reStructuredTextの基本記法

====================
プロジェクトタイトル
====================

.. contents:: 目次
   :depth: 2

概要
====

このプロジェクトは、APIドキュメント生成の例を示しています。

API リファレンス
================

モジュール一覧
--------------

.. autosummary::
   :toctree: generated
   :recursive:

   myproject.core
   myproject.utils
   myproject.models

詳細API
-------

.. automodule:: myproject.core
   :members:
   :undoc-members:
   :show-inheritance:

.. autoclass:: myproject.models.User
   :members:
   :special-members: __init__

数式の例
========

インライン数式: :math:`E = mc^2`

ブロック数式:

.. math::

   \int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi}

注釈とアドモニション
==================

.. note::
   これは注意書きです。

.. warning::
   これは警告です。

.. tip::
   これは便利なヒントです。

.. seealso::
   関連情報: :doc:`installation`

コードブロック
==============

Python コード例:

.. code-block:: python
   :linenos:
   :emphasize-lines: 3,5

   def hello_world(name):
       """挨拶関数
       
       Args:
           name (str): 名前
           
       Returns:
           str: 挨拶メッセージ
       """
       return f"Hello, {name}!"

   # 使用例
   message = hello_world("太郎")
   print(message)

テーブル
========

.. csv-table:: 機能比較表
   :header: "機能", "対応状況", "備考"
   :widths: 30, 20, 50

   "自動生成", "✓", "Pythonコードから自動生成"
   "テーマ", "✓", "多数のテーマが利用可能"
   "PDF出力", "✓", "LaTeX経由でPDF生成"
   "多言語", "✓", "国際化機能サポート"

図表
====

.. figure:: _static/architecture.png
   :alt: システム構成図
   :align: center
   :width: 80%

   システム全体のアーキテクチャ

相互参照
========

- セクション参照: :ref:`api-reference`
- ドキュメント参照: :doc:`installation`
- 外部参照: :py:func:`json.dumps`
- 用語集: :term:`API`

.. glossary::

   API
      Application Programming Interface の略

TODOリスト
==========

.. todo::
   ユーザー認証機能の実装

.. todolist::

自動APIドキュメント生成

# sample_module.py - サンプルPythonモジュール
"""
サンプルモジュール

このモジュールは、Sphinxのautodoc機能のデモンストレーションです。
"""

from typing import List, Optional, Dict, Any
import json


class DataProcessor:
    """データ処理クラス
    
    様々なデータ処理操作を提供するクラスです。
    
    Attributes:
        data (List[Any]): 処理対象のデータリスト
        config (Dict[str, Any]): 設定情報
        
    Example:
        >>> processor = DataProcessor([1, 2, 3, 4, 5])
        >>> result = processor.filter_data(lambda x: x > 3)
        >>> print(result)
        [4, 5]
    """
    
    def __init__(self, data: List[Any], config: Optional[Dict[str, Any]] = None):
        """コンストラクタ
        
        Args:
            data: 処理対象のデータリスト
            config: オプション設定。デフォルトは None
            
        Raises:
            ValueError: dataが空の場合
        """
        if not data:
            raise ValueError("データリストは空にできません")
            
        self.data = data
        self.config = config or {}
    
    def filter_data(self, condition) -> List[Any]:
        """条件に基づいてデータをフィルタリング
        
        Args:
            condition (callable): フィルタリング条件を定義する関数
            
        Returns:
            List[Any]: フィルタリング後のデータリスト
            
        Raises:
            TypeError: conditionが呼び出し可能でない場合
            
        Note:
            この関数は元のデータを変更しません。新しいリストを返します。
            
        Warning:
            大量のデータを処理する場合、メモリ使用量に注意してください。
        """
        if not callable(condition):
            raise TypeError("conditionは呼び出し可能である必要があります")
            
        return [item for item in self.data if condition(item)]
    
    def transform_data(self, transformer) -> List[Any]:
        """データを変換
        
        Args:
            transformer (callable): 変換関数
            
        Returns:
            List[Any]: 変換後のデータリスト
        """
        return [transformer(item) for item in self.data]
    
    def save_to_json(self, filename: str) -> None:
        """データをJSONファイルに保存
        
        Args:
            filename: 保存先ファイル名
            
        Raises:
            IOError: ファイル書き込みに失敗した場合
        """
        try:
            with open(filename, 'w', encoding='utf-8') as f:
                json.dump(self.data, f, ensure_ascii=False, indent=2)
        except Exception as e:
            raise IOError(f"ファイル保存に失敗: {e}")


def calculate_statistics(data: List[float]) -> Dict[str, float]:
    """統計情報を計算
    
    数値リストから基本的な統計値を計算します。
    
    Args:
        data: 数値のリスト
        
    Returns:
        統計情報を含む辞書
        
        * mean: 平均値
        * median: 中央値  
        * std: 標準偏差
        * min: 最小値
        * max: 最大値
        
    Raises:
        ValueError: dataが空または数値でない場合
        
    Example:
        >>> stats = calculate_statistics([1, 2, 3, 4, 5])
        >>> print(f"平均: {stats['mean']}")
        平均: 3.0
        
    See Also:
        :py:class:`DataProcessor`: より高度なデータ処理機能
    """
    if not data:
        raise ValueError("データリストが空です")
    
    if not all(isinstance(x, (int, float)) for x in data):
        raise ValueError("すべての要素が数値である必要があります")
    
    n = len(data)
    mean = sum(data) / n
    sorted_data = sorted(data)
    
    # 中央値の計算
    if n % 2 == 0:
        median = (sorted_data[n//2 - 1] + sorted_data[n//2]) / 2
    else:
        median = sorted_data[n//2]
    
    # 標準偏差の計算
    variance = sum((x - mean) ** 2 for x in data) / n
    std = variance ** 0.5
    
    return {
        'mean': mean,
        'median': median,
        'std': std,
        'min': min(data),
        'max': max(data)
    }

Sphinx拡張の作成

# sphinx_extension_example.py - カスタムSphinx拡張
from docutils import nodes
from docutils.parsers.rst import Directive
from sphinx.application import Sphinx
from sphinx.util.docutils import SphinxDirective


class TodoDirective(SphinxDirective):
    """カスタムTODOディレクティブ"""
    
    has_content = True
    required_arguments = 0
    optional_arguments = 1
    final_argument_whitespace = True
    option_spec = {
        'priority': str,
        'assigned': str,
        'due': str,
    }
    
    def run(self):
        """ディレクティブの実行"""
        env = self.state.document.settings.env
        
        # TODOノードの作成
        todo_node = todo('')
        todo_node['priority'] = self.options.get('priority', 'medium')
        todo_node['assigned'] = self.options.get('assigned', '')
        todo_node['due'] = self.options.get('due', '')
        
        # コンテンツの解析
        self.state.nested_parse(self.content, self.content_offset, todo_node)
        
        # 環境にTODOを追加
        if not hasattr(env, 'todo_all_todos'):
            env.todo_all_todos = []
        
        env.todo_all_todos.append({
            'docname': env.docname,
            'lineno': self.lineno,
            'todo': todo_node.deepcopy(),
            'target': nodes.target(),
        })
        
        return [todo_node]


class todo(nodes.Admonition, nodes.Element):
    """TODOノードクラス"""
    pass


def visit_todo_node(self, node):
    """TODOノードの訪問(HTML出力)"""
    priority = node.get('priority', 'medium')
    assigned = node.get('assigned', '')
    due = node.get('due', '')
    
    attrs = {'class': f'todo priority-{priority}'}
    self.body.append(self.starttag(node, 'div', **attrs))
    
    # ヘッダー情報の追加
    self.body.append('<div class="todo-header">')
    self.body.append(f'<span class="todo-priority">優先度: {priority}</span>')
    if assigned:
        self.body.append(f'<span class="todo-assigned">担当: {assigned}</span>')
    if due:
        self.body.append(f'<span class="todo-due">期限: {due}</span>')
    self.body.append('</div>')


def depart_todo_node(self, node):
    """TODOノードの退出(HTML出力)"""
    self.body.append('</div>\n')


def purge_todos(app, env, docname):
    """ドキュメント削除時のTODOクリーンアップ"""
    if not hasattr(env, 'todo_all_todos'):
        return
    
    env.todo_all_todos = [todo for todo in env.todo_all_todos
                          if todo['docname'] != docname]


def merge_todos(app, env, docnames, other):
    """環境マージ時のTODO統合"""
    if not hasattr(env, 'todo_all_todos'):
        env.todo_all_todos = []
    if hasattr(other, 'todo_all_todos'):
        env.todo_all_todos.extend(other.todo_all_todos)


def process_todo_nodes(app, doctree, fromdocname):
    """TODOノードの後処理"""
    if not app.config.todo_include_todos:
        for node in doctree.traverse(todo):
            node.parent.remove(node)


def setup(app: Sphinx):
    """拡張のセットアップ"""
    app.add_config_value('todo_include_todos', False, 'html')
    
    app.add_node(todo,
                 html=(visit_todo_node, depart_todo_node),
                 latex=(visit_todo_node, depart_todo_node),
                 text=(visit_todo_node, depart_todo_node))
    
    app.add_directive("todo", TodoDirective)
    
    app.connect('doctree-resolved', process_todo_nodes)
    app.connect('env-purge-doc', purge_todos)
    app.connect('env-merge-info', merge_todos)
    
    return {
        'version': '0.1',
        'parallel_read_safe': True,
        'parallel_write_safe': True,
    }

テーマカスタマイズ

# カスタムテーマ設定(conf.py内)

# -- HTML output options ----------------------------------------------------
html_theme = 'sphinx_rtd_theme'

# カスタムCSS
html_css_files = [
    'custom.css',
]

# カスタムJavaScript
html_js_files = [
    'custom.js',
]

# テーマオプションの詳細設定
html_theme_options = {
    # サイト設定
    'analytics_id': 'G-XXXXXXXXXX',
    'analytics_anonymize_ip': False,
    
    # ロゴとタイトル
    'logo_only': False,
    'display_version': True,
    
    # ナビゲーション
    'prev_next_buttons_location': 'bottom',
    'style_external_links': False,
    'vcs_pageview_mode': '',
    
    # サイドバー
    'collapse_navigation': True,
    'sticky_navigation': True,
    'navigation_depth': 4,
    'includehidden': True,
    'titles_only': False,
    
    # 外観
    'style_nav_header_background': '#2980B9',
}

# サイドバーの設定
html_sidebars = {
    '**': [
        'about.html',
        'navigation.html',
        'relations.html',
        'searchbox.html',
        'donate.html',
    ]
}

自動デプロイ設定

# .github/workflows/docs.yml - GitHub Actions
name: Build and Deploy Documentation

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  docs:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Python
        uses: actions/setup-python@v4
        with:
          python-version: 3.x

      - name: Install dependencies
        run: |
          pip install -r docs/requirements.txt

      - name: Build documentation
        run: |
          cd docs
          sphinx-build -b html . _build/html

      - name: Deploy to GitHub Pages
        if: github.ref == 'refs/heads/main'
        uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: docs/_build/html

開発ワークフロー

# 開発サーバーの起動(自動再ビルド)
sphinx-autobuild docs docs/_build/html

# 標準的なビルドコマンド
cd docs
make html          # HTML生成
make latexpdf      # PDF生成
make epub          # ePub生成
make man           # manページ生成

# 特定ファイルのみ再ビルド
sphinx-build -b html -a docs docs/_build/html

# クリーンビルド
make clean
make html

# APIドキュメントの自動生成
sphinx-apidoc -o docs/source myproject

# 多言語対応ビルド
make gettext       # 翻訳テンプレート生成
sphinx-intl update -p docs/_build/gettext -l ja  # 日本語対応
make -e SPHINXOPTS="-D language='ja'" html        # 日本語版生成