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.
-
--inplaceflag for direct modification (with confirmation prompt). -
Processes single files, multiple files, or entire directories recursively.
-
--only-missingto 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
libcstfor CST transformation — lossless round-tripping ensures that whitespace, comments, and code formatting outside docstrings are never altered, unlikeast+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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3e8074adb3652ca7833f9e5f373da1080258fb8f46192d6c86ea146a5cde00c4
|
|
| MD5 |
9ebbce7930f8f95e2478fa1bffa30c74
|
|
| BLAKE2b-256 |
a6ca0aa6a677c32f21e1398863b4e2268dd5f825bf3f6309592e51bcdeb076a7
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e38f90b962c7eada86593d6fe1dc4ea5e7edaa237a7071ceded1a8e173b3a0b1
|
|
| MD5 |
086859b800713037f422c96be13f5f8d
|
|
| BLAKE2b-256 |
e19d945e3bbd8e09fa7244e881964c9f82e55393122ddd545dfc5b982ff8789a
|