Skip to main content

LLM-assisted Python docstring reformatter and generator via Ollama

Project description

docdoctor

LLM-assisted Python docstring reformatter and generator.

docdoctor uses a local Ollama model (default: qwen2.5-coder) to:

  • Reformat existing docstrings to a target style while preserving all content.
  • Generate new docstrings from scratch, inferred from function/class signatures, type hints, and bodies.

Patches are output as unified diffs by default — no files are modified until you review and apply them. In-place modification is available as an explicit opt-in.


Features

  • Supports Google, NumPy/NumpyDoc, and Sphinx/reST styles out of the box.

  • Custom style support: pass your own formatting instruction as a string or file.

  • Patch-first workflow: inspect diffs before committing any change.

  • --inplace flag for direct modification (with confirmation prompt).

  • Processes single files, multiple files, or entire directories recursively.

  • --only-missing to skip functions that already have docstrings.

  • Configurable Ollama model, host, temperature.

  • Rich terminal output with progress tracking.

    original_values = df[column_measurement].copy() numeric_values = pd.to_numeric(original_values, errors="coerce") mask_non_numeric = numeric_values.isna() & original_values.notna() non_numeric_unique = original_values[mask_non_numeric].unique()


Requirements

  • Python ≥ 3.10
  • Ollama running locally (ollama serve)
  • The target model pulled: ollama pull qwen2.5-coder

Installation

From source with uv (recommended)

git clone https://github.com/yourorg/docdoctor.git
cd docdoctor
uv sync

This creates a virtual environment in .venv and installs all dependencies.

With pip

pip install .

Development install

uv sync --extra dev
# or
pip install -e ".[dev]"

Quick start

# Check that Ollama is reachable and the model is available
docdoctor check

# Generate patches for a single file (NumPy style, default)
docdoctor run mymodule.py

# Generate patches for a whole package
docdoctor run src/mypackage/

# Use Google style
docdoctor run src/mypackage/ --style google

# Use reST/Sphinx style
docdoctor run src/mypackage/ --style rest

# Write patches to a dedicated directory
docdoctor run src/mypackage/ --patch-dir patches/

# Apply a patch
patch -p1 < src/mypackage/mymodule.py.patch

# Apply all patches at once
find . -name "*.patch" | xargs -I{} patch -p1 < {}

Workflow diagram

Parse file with libcst
        │
        ▼
Extract function/class nodes + existing docstrings
        │
        ▼
  Docstring present?
   ┌────┴─────┐
  Yes         No
   │           │
   ▼           ▼
Reformat    Generate
prompt      prompt
(preserve    (infer from
 content)    signature +
             body)
   │           │
   └─────┬─────┘
         ▼
   Ollama LLM call
         │
         ▼
  Inject via libcst
  (lossless round-trip)
         │
         ▼
  Write .patch file
  (or modify in place)

Usage reference

Usage: docdoctor [OPTIONS] SOURCES...

Arguments:
  SOURCES  Python files or directories to process. [required]

Options:
  -s, --style         [google|rest|numpy|custom]  Target docstring style. [default: numpy]
  -i, --inplace                                   Modify files in place (asks for confirmation).
  -p, --patch-dir     PATH                        Directory to write .patch files.
  -m, --model         TEXT                        Ollama model name. [default: qwen2.5-coder]
      --host          TEXT                        Ollama server URL. [default: http://localhost:11434]
  -t, --temperature   FLOAT                       LLM sampling temperature. [default: 0.1]
  -c, --custom-instruction TEXT                   Custom format instruction (required for --style=custom).
      --only-missing                              Only process functions/classes without a docstring.
  -v, --version                                   Show version and exit.
  --help                                          Show this message and exit.

Subcommands

docdoctor list-styles    # Print all supported styles with examples
docdoctor check          # Verify Ollama is running and model is available

Custom docstring style

Pass a formatting instruction directly:

docdoctor src/ \
  --style custom \
  --custom-instruction "Use Epytext style. Parameters as @param name: description. Returns as @return: description."

Or load from a file:

cat > my_style.txt << 'EOF'
Use a compact one-line summary followed by a Parameters section with YAML-style
entries: `- name (type): description`. End with a Returns: line.
EOF

docdoctor src/ --style custom --custom-instruction my_style.txt

Using a different model

Any model available in your Ollama instance works:

# Use Llama 3.1 8B
docdoctor src/ --model llama3.1:8b

# Use DeepSeek Coder
docdoctor src/ --model deepseek-coder-v2

# Use a remote Ollama server
docdoctor src/ --host http://192.168.1.100:11434 --model qwen2.5-coder

Patch workflow detail

By default, docdoctor writes a .patch file next to each processed source file:

src/
  mymodule.py
  mymodule.py.patch   ← generated by docdoctor

Review the patch:

cat src/mymodule.py.patch

Apply it:

patch -p1 < src/mymodule.py.patch

Reject it (just delete the .patch file):

rm src/mymodule.py.patch

Write all patches to a single directory:

docdoctor src/ --patch-dir ./docdoctores/

In-place mode

If you are confident in the output (e.g. working in a git branch), use --inplace:

# docdoctor will ask for confirmation before modifying anything
docdoctor src/mypackage/ --inplace

# Combine with --only-missing to fill gaps without touching existing docs
docdoctor src/mypackage/ --inplace --only-missing

⚠️ Always commit or back up your code before using --inplace.


Running tests

uv run pytest tests/ -v
# or
hatch run test

Project structure

docdoctor/
├── src/docdoctor/
│   ├── __init__.py
│   ├── __version__.py
│   ├── cli.py              # Typer CLI
│   ├── ollama_client.py    # HTTP client for Ollama /api/generate
│   ├── pipeline.py         # Orchestration: collect → LLM → patch/apply
│   ├── styles.py           # Style specs and prompt templates
│   └── transformer.py      # libcst CST visitor/transformer
├── tests/
│   └── test_core.py
├── pyproject.toml
└── README.md

Design notes

  • libcst for CST transformation — lossless round-tripping ensures that whitespace, comments, and code formatting outside docstrings are never altered, unlike ast + ast.unparse.
  • Patch-first default — the LLM output should always be reviewed. Docstring generation can hallucinate parameter descriptions or miss nuance.
  • Low temperature (0.1) — keeps output deterministic and structured; raise it if you want more creative summaries.
  • One LLM call per function/class — straightforward and inspectable; no batching that obscures which node produced which output.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

docdoctor-0.1.0.tar.gz (40.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

docdoctor-0.1.0-py3-none-any.whl (16.5 kB view details)

Uploaded Python 3

File details

Details for the file docdoctor-0.1.0.tar.gz.

File metadata

  • Download URL: docdoctor-0.1.0.tar.gz
  • Upload date:
  • Size: 40.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.17 {"installer":{"name":"uv","version":"0.9.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"25.04","id":"plucky","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for docdoctor-0.1.0.tar.gz
Algorithm Hash digest
SHA256 3e8074adb3652ca7833f9e5f373da1080258fb8f46192d6c86ea146a5cde00c4
MD5 9ebbce7930f8f95e2478fa1bffa30c74
BLAKE2b-256 a6ca0aa6a677c32f21e1398863b4e2268dd5f825bf3f6309592e51bcdeb076a7

See more details on using hashes here.

File details

Details for the file docdoctor-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: docdoctor-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 16.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.17 {"installer":{"name":"uv","version":"0.9.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"25.04","id":"plucky","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for docdoctor-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e38f90b962c7eada86593d6fe1dc4ea5e7edaa237a7071ceded1a8e173b3a0b1
MD5 086859b800713037f422c96be13f5f8d
BLAKE2b-256 e19d945e3bbd8e09fa7244e881964c9f82e55393122ddd545dfc5b982ff8789a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page