# 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.

```js title="astro.config.mjs" "docstringStyle"
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.

:::caution[A wrong style degrades silently]
A `docstringStyle` that does not match your docstrings never fails the build. It produces
thin pages instead. Open a rendered page after you change the style.
:::

## The same docstring, three ways

```python "Args:" "Returns:" "Raises:"
    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](/starlight-pydocs/api/demopkg/) uses it. A parameter needs no type in the
    docstring: `name: description` is enough, because the annotation supplies the type.

  ```python /-{3,}/
    def resample(grid: Grid, factor: float = 2.0) -> Grid:
        """Scale a grid by a factor.

        Parameters
        ----------
        grid : Grid
            The grid to scale.
        factor : float, optional
            Multiplier applied to both dimensions.

        Returns
        -------
        Grid
            A new, scaled grid.

        Raises
        ------
        ValueError
            If `factor` is not positive.
        """
    ```

    The underline makes a section. Leave one out, and Griffe reads the title above it as
    prose. Types go on the parameter line itself, after a space-padded colon (`name : type`).
    See it rendered: [`numpkg`](/starlight-pydocs/api/numpkg/).

  ```python ":param" ":type" ":returns:" ":raises"
    def resample(grid: Grid, factor: float = 2.0) -> Grid:
        """Scale a grid by a factor.

        :param grid: The grid to scale.
        :param factor: Multiplier applied to both dimensions.
        :type factor: float
        :returns: A new, scaled grid.
        :raises ValueError: If `factor` is not positive.
        """
    ```

    Sphinx style uses reStructuredText field lists. Types come from a `:type name:` field, or
    from the annotation when there is none. Your site's Markdown processor renders the prose
    inside a field. This package does not understand reStructuredText, so write
    cross-references with the
    [mkdocstrings reference syntax](/starlight-pydocs/guides/cross-references/) instead of an
    rST role such as `:func:`. See it rendered: [`sphpkg`](/starlight-pydocs/api/sphpkg/).

  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.

## Parser options

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

```js title="astro.config.mjs" collapse={1-6, 20-27} {16-19}
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,
              },
            },
          ],
        }),
      ],
      sidebar: [{ label: 'API reference', items: [pydocsSidebarGroup] }],
    }),
  ],
});
```

The option names are Griffe's own, and they differ per parser. See
[Griffe's docstring parser options](https://mkdocstrings.github.io/griffe/reference/docstrings/).
Options are part of the extraction cache key, so changing one re-extracts the package.

## Sections that render

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](/starlight-pydocs/guides/cross-references/).

## Admonition flavours

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.

## Doctests and examples

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:

````python "console"
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.

## Prose rendering

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.

[Cross-references](/starlight-pydocs/guides/cross-references/)
  [Multiple packages](/starlight-pydocs/guides/multiple-packages/)