Testing Documentation Code Examples#
Serapeum uses pytest-markdown-docs to run Python code fences in markdown files as pytest tests. This ensures all documentation examples stay correct and up to date.
Setup#
The plugin is included in the dev dependencies. Install it with:
Running Doc Tests#
The docs/ directory is excluded from the default pytest paths, so you must pass the file explicitly:
# Run all code blocks in a single file
uv run pytest --markdown-docs docs/reference/providers/ollama/examples.md
# Run all code blocks across the entire docs directory
uv run pytest --markdown-docs docs/
# Verbose output
uv run pytest -v --markdown-docs docs/reference/providers/ollama/examples.md
Listing Code Blocks in a File#
To see all testable code blocks and their identifiers:
This outputs each block with its fence number and line:
<MarkdownInlinePythonItem [CodeFence#1][line:52]>
<MarkdownInlinePythonItem [CodeFence#2][line:70]>
...
Running a Specific Code Block#
Use the node ID shown by --collect-only:
uv run pytest -v --markdown-docs "docs/reference/providers/ollama/examples.md::[CodeFence#1][line:52]"
The line number corresponds to the opening ``` of the code fence in the file, making it easy to cross-reference with your editor.
Controlling Which Blocks Are Tested#
Use info string modifiers on the opening code fence:
| Modifier | Effect |
|---|---|
notest |
Skip this block entirely |
continuation |
Share state with the previous block (imports, variables carry over) |
fixture:<name> |
Inject a pytest fixture into the block's scope |
retry:N |
Retry the block up to N times on failure |
Example — skip a block:
```python notest
# This illustrative snippet will not be executed
llm = Ollama(model="...", api_key="sk-...")
```
Example — continuation across blocks:
```python
from serapeum.ollama import Ollama
llm = Ollama(model="qwen3.5:397b", api_key=os.environ.get("OLLAMA_API_KEY"))
```
```python continuation
# `llm` is still in scope from the block above
response = llm.complete("Hello")
```
Filtering Code Blocks by Custom Markers#
You can tag individual Python code blocks with custom markers such as function_calling or ci,
then use the --md-marker flag to run only the blocks that carry a specific tag.
Tagging a Code Block#
Append one or more marker names after the language identifier on the opening fence:
```python function_calling
# Runs only when --md-marker function_calling is passed
result = expensive_function_calling_call()
```
```python ci
# Runs only when --md-marker ci is passed
result = ci_only_call()
```
```python
# Untagged — runs normally, but is skipped when --md-marker is active
result = always_runs()
```
Tags compose freely with the built-in modifiers:
```python function_calling continuation fixture:my_fixture
# tagged 'function_calling', shares state with the previous block, and injects my_fixture
```
Running Tagged Blocks#
# Run only blocks tagged 'function_calling'
python -m pytest --markdown-docs --md-marker function_calling docs/
# Run blocks tagged 'function_calling' OR 'ci'
python -m pytest --markdown-docs --md-marker function_calling --md-marker ci docs/
# Run all blocks (default — unchanged behaviour)
python -m pytest --markdown-docs docs/
Because each tag is added as a real pytest marker, you can also use standard -m expressions:
# Same as --md-marker function_calling
python -m pytest --markdown-docs -m function_calling docs/
# Boolean expressions work too
python -m pytest --markdown-docs -m "function_calling and not ci" docs/
Listing Which Blocks Have Markers#
Combine --collect-only with --md-marker to preview what would run:
Registering New Markers#
The function_calling and ci markers are registered in pyproject.toml under [tool.pytest.ini_options].markers.
If you introduce a new tag (e.g., gpu), add it there to suppress unknown-marker warnings:
Environment Variables#
Code blocks that call the Ollama cloud API require OLLAMA_API_KEY to be set. Load it from a .env file before running:
# The dotenv package is included in dev dependencies
uv run pytest --markdown-docs docs/reference/providers/ollama/examples.md
In your .env file at the repo root:
Tests that require a live API call should be marked as e2e (see Contributing) or use notest if they are purely illustrative.