Documentation Guide

This documentation uses Sphinx’s literalinclude directive to import code directly from source files, ensuring the documentation stays in sync with the actual codebase.

Code Inclusion with literalinclude

Basic Usage

Include entire files:

.. literalinclude:: ../app/main.py
   :language: python

Include specific lines:

.. literalinclude:: ../tests/conftest.py
   :language: python
   :lines: 6-12

Include line ranges:

.. literalinclude:: ../app/core/config.py
   :language: python
   :lines: 1-10, 15-20

Advanced Options

Emphasize specific lines:

.. literalinclude:: ../app/main.py
   :language: python
   :lines: 1-20
   :emphasize-lines: 5, 10-12

Add line numbers:

.. literalinclude:: ../tests/test_health.py
   :language: python
   :linenos:

Include with caption:

.. literalinclude:: ../app/main.py
   :language: python
   :caption: FastAPI application setup
   :name: fastapi-main

Include specific functions/classes by markers:

You can also use start-after and end-before to include specific sections:

.. literalinclude:: ../app/main.py
   :language: python
   :start-after: # Health check endpoint
   :end-before: # End health check

Benefits of literalinclude

  • Always up-to-date - Documentation automatically reflects code changes

  • No duplication - Single source of truth for code examples

  • Syntax highlighting - Proper language-specific formatting

  • Reduced maintenance - No need to manually update code blocks

  • Testing integration - Example code is actually tested since it’s from real files

Example: Current Project Files

Here are examples of including code from our actual project files:

Configuration settings:

Configuration imports and dependencies
from pydantic_settings import BaseSettings, SettingsConfigDict
from typing import List, Optional


FastAPI app initialization:

and welcome endpoints.
"""

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from app.api.routes import api_router
from app.core.config import settings
from app.db.database import init_db

Test fixture setup:

"""Test configuration and fixtures."""

import pytest_asyncio
from typing import AsyncGenerator
from fastapi.testclient import TestClient
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine, async_sessionmaker
from sqlmodel import SQLModel

from app.main import app
from app.db.database import get_session


# Use in-memory SQLite for testing
TEST_DATABASE_URL = "sqlite+aiosqlite:///:memory:"


@pytest_asyncio.fixture(scope="function")
async def test_engine():
    """Create a test database engine."""
    engine = create_async_engine(
        TEST_DATABASE_URL,
        echo=False,
        future=True,
    )

    # Create all tables
    async with engine.begin() as conn:
        await conn.run_sync(SQLModel.metadata.create_all)

    yield engine

    # Clean up
    await engine.dispose()


@pytest_asyncio.fixture(scope="function")
async def test_session(test_engine) -> AsyncGenerator[AsyncSession, None]:
    """Create a test database session."""
    TestSessionLocal = async_sessionmaker(
        test_engine, class_=AsyncSession, expire_on_commit=False
    )

    async with TestSessionLocal() as session:
        yield session


@pytest_asyncio.fixture
async def client(test_engine) -> AsyncGenerator[TestClient, None]:
    """Create test client with test database."""

    TestSessionLocal = async_sessionmaker(
        test_engine, class_=AsyncSession, expire_on_commit=False
    )

    async def override_get_session():
        async with TestSessionLocal() as session:
            yield session

    app.dependency_overrides[get_session] = override_get_session

    with TestClient(app) as client:
        yield client

    app.dependency_overrides.clear()

Sample test case:

from fastapi.testclient import TestClient


class TestHealthEndpoint:
    """Test cases for the health endpoint."""

    def test_health_endpoint_returns_200(self, client: TestClient):
        """Test that the health endpoint returns a 200 status code."""
        response = client.get("/health")
        assert response.status_code == 200

API Documentation with autodoc

For Python projects, Sphinx can automatically generate documentation from your code’s docstrings using the autodoc extension.

Setup autodoc

The conf.py file has been configured with these extensions:

  • sphinx.ext.autodoc - Automatically document Python modules

  • sphinx.ext.viewcode - Add links to source code

  • sphinx.ext.napoleon - Support for Google and NumPy style docstrings

Using autodoc

You can automatically document modules, classes, and functions:

Document an entire module:

.. automodule:: myapp.core.config
   :members:

Document a specific class:

.. autoclass:: myapp.models.User
   :members:

Document a specific function:

.. autofunction:: myapp.utils.helper_function

Example: Auto-generated Documentation

To use autodoc, you would add directives like this to your documentation:

.. autoclass:: myapp.models.User
   :members:

This would automatically generate documentation from the class docstrings and type hints.

Note: For autodoc to work properly, all project dependencies must be available in the documentation build environment. You may need to install your project dependencies in the documentation build environment or use mock imports for complex dependencies.

Benefits of autodoc

  • Automatic updates - Documentation reflects current docstrings

  • Cross-references - Automatic linking between related items

  • Type hints - Shows function signatures and return types

  • Inheritance - Shows class inheritance relationships

Combined Approach

You can combine literalinclude for code examples and autodoc for API documentation:

  • Use literalinclude for: tutorials, examples, configuration files

  • Use autodoc for: API reference, class/function documentation

Best Practice: Embed Documentation in Code

The most maintainable approach is to write comprehensive docstrings in your code and use autodoc to extract them automatically:

class UserSettings(BaseSettings):
    """Application settings and configuration.

    This class manages all configuration settings for the application.
    Settings are loaded from environment variables and have sensible defaults.

    Attributes:
        app_name (str): The name of the application.
        version (str): The current version of the app.
    """
    app_name: str = "My Application"
    version: str = "1.0.0"

Then use autodoc to include it in documentation:

.. autoclass:: myapp.config.UserSettings
   :members:

For API Endpoints: Use OpenAPI Documentation

Instead of manually documenting API endpoints in Sphinx, leverage FastAPI’s built-in OpenAPI documentation:

  • Swagger UI: http://localhost:8000/docs - Interactive testing

  • ReDoc: http://localhost:8000/redoc - Clean reference documentation

  • OpenAPI Schema: http://localhost:8000/openapi.json - Machine-readable schema

This approach ensures:

  • Single source of truth - Documentation lives with the code

  • Always up-to-date - Changes to functionality update docs automatically

  • Developer-friendly - Docstrings help during development

  • IDE integration - Modern IDEs show the docstrings as help text

  • Interactive testing - Built-in API testing interface