Skip to content

Docstring styles

Griffe parses your docstrings before this plugin renders anything. Your docstrings must use one of the four conventions it knows: google (the default), numpy, sphinx, or auto. You set the style per package, so one site can document packages written in different styles.

astro.config.mjs
starlightPydocs({
packages: [
{ name: 'mypkg', search: ['../src'], docstringStyle: 'numpy' },
{ name: 'legacy', search: ['../legacy'], docstringStyle: 'sphinx' },
{ name: 'newpkg', search: ['../new'] },
],
});

A package that sets no style gets google. auto is the fourth choice. With auto, Griffe picks a parser for each docstring. Use auto when a package’s docstrings do not all follow the same style.

If you name one of the other three, Griffe uses only that parser. Point the numpy parser at a google docstring, and it reads Args: as ordinary prose. You get no parameter table and no Returns block, but the build still succeeds. Griffe’s own warnings reach your build log with a griffe: prefix, but not every mis-parse produces a warning.

def resample(grid: Grid, factor: float = 2.0) -> Grid:
"""Scale a grid by a factor.
Args:
grid: The grid to scale.
factor: Multiplier applied to both dimensions.
Returns:
A new, scaled grid.
Raises:
ValueError: If `factor` is not positive.
"""

Google style needs a recognised title, a colon, and an indented block. This is the default style. The demopkg fixture behind this site’s example pages uses it. A parameter needs no type in the docstring: name: description is enough, because the annotation supplies the type.

All three arrive as the same structured sections, so all three render the same way. The summary renders as prose, then comes a parameter table, then typed Returns and Raises blocks with the exception type linked.

Griffe’s parsers take their own options. docstringOptions passes these through as griffe’s -D flag:

astro.config.mjs
6 collapsed lines
import starlight from '@astrojs/starlight';
import { defineConfig } from 'astro/config';
import starlightPydocs, { pydocsSidebarGroup } from 'starlight-pydocs';
export default defineConfig({
integrations: [
starlight({
title: 'My project',
plugins: [
starlightPydocs({
packages: [
{
name: 'mypkg',
search: ['../src'],
docstringStyle: 'google',
docstringOptions: {
warn_unknown_params: false,
returns_named_value: false,
},
8 collapsed lines
},
],
}),
],
sidebar: [{ label: 'API reference', items: [pydocsSidebarGroup] }],
}),
],
});

The option names are Griffe’s own, and they differ per parser. See Griffe’s docstring parser options. Options are part of the extraction cache key, so changing one re-extracts the package.

Whatever the style, Griffe produces the same structured sections. Each renders as its own block, in docstring order:

Section Rendered as
Prose Markdown, through the site’s own processor
Parameters, other parameters, type parameters A table of name, type, default and description, with linked types
Attributes The same table without the default column
Returns, yields, receives A list of typed values with their descriptions
Raises, warns A list of exception types, each linked where it resolves
Examples Prose and doctest blocks, in the order they were written
Admonitions (Note:, Warning:, Tip: …) An aside, in one of four flavours matching Starlight’s own
Deprecations A badge on the heading and a caution aside carrying the explanation
Functions, classes, modules, type aliases A list of cross-referenced names, as numpy-style See Also blocks produce

We ignore section kinds we do not model, rather than guess at them. This means a future Griffe release can add a new kind without breaking a page.

Parameter tables list only the parameters the docstring documents. A parameter you leave out of the docstring still appears in the signature above. Types come from the annotation when the docstring gives none. They link exactly like the types in the signature; see Cross-references.

Griffe records an admonition’s annotation (note, warning, danger, seealso, hint, …). Each annotation maps onto one of four asides styled to match Starlight’s: note, tip, caution and danger. An annotation we do not recognise renders as a note, and keeps its own title. Deprecated: blocks are the exception. The google parser routes them through the admonition machinery. This plugin turns them into the deprecation notice instead of an aside, so the badge and the explanation stay together.

An Examples: section arrives as a sequence of prose and transcript pieces. Prose renders as Markdown. A >>> transcript arrives unfenced. This plugin fences it as python before rendering. The site’s own highlighter then highlights it: Expressive Code under Starlight, plain Shiki in a bare Astro project.

This plugin uses python rather than mkdocstrings’ pycon. The Shiki bundles these processors use ship no Python-console grammar, and python highlights a transcript correctly. A block that is already fenced in the docstring is left exactly as written, so you can pick your own language:

def summarise(rows):
"""Summarise a table.
Examples:
The plain transcript form, fenced as `python` for you:
>>> summarise([{"n": 1}])
'n=1'
Or fence it yourself, in any language:
```console
$ python -m mypkg summarise rows.json
n=1
```
"""

The llms.txt rendition of the same content fences transcripts as pycon instead. That output is read by machines, not highlighted by Shiki.

Docstring Markdown goes through the Markdown processor your site has configured, not one this package brings along. Your site’s Markdown settings (the theme, the plugins Starlight registers, a mermaid plugin you added, GFM tables, smart quotes) apply to docstring prose too. This means an API page reads like the rest of the site.

Two consequences:

  • Rendering happens once per build, at astro:config:done, after every integration has finished configuring the pipeline. The HTML lands in a sidecar file beside the cached dump, so no markdown engine runs while pages render.
  • A docstring that cannot be rendered costs that one string. The build logs a warning. The object keeps its signature, parameters and links, and the page still exists.

This plugin supports both Sätteri (the Astro 7 default) and the unified pipeline from @astrojs/markdown-remark, because neither is a dependency here. It calls whatever markdown.processor resolves to. This documentation site runs the default. The examples/vanilla site in the repository pins unified(). CI exercises both.