numpy / numpy/numpydoc

Add built-in validation check for bullet lists missing a preceding blank line

Open
#686 1 comment 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
355
Forks
181
Avg merge
1d 9h
Merged PRs (30d)
3

Description

Issue

Sphinx with the Napoleon extension (which numpydoc-validation users almost universally pair with) silently mis-renders bullet lists inside docstring section bodies when the list is not separated from its introductory line by a blank line. The bullet markers get inlined into the introductory paragraph as literal characters rather than being parsed as a list.

Concrete example, taken from a real public-API method:

def analyze_persistence(self, ...) -> dict[str, Any]:
    """...

    Returns
    -------
    dict[str, Any]
        Dictionary containing:
        - "mean_effect_during": Mean effect during intervention period
        - "mean_effect_post": Mean effect during post-intervention period
        - "persistence_ratio": ...
    """

Napoleon collapses the four lines after Dictionary containing: into a single paragraph, so the rendered HTML reads as a wall of prose with literal hyphens rather than as four <li> elements. The fix is mechanically simple — insert a blank line between the introductory line and the first bullet — but the defect is invisible at edit time because the source is also valid (if uninspiring) RST.

This bit a downstream library recently (pymc-labs/CausalPy#892, where ~30 sites were affected across the public API).

Why existing tooling does not catch this

  • numpydoc-validation checks (GL01GL10, SS01SS06, PR01PR10, RT01RT05, SA01SA04, EX01, YD01, ES01) all validate section structure — section names, ordering, parameter sync, summary capitalisation, etc. None inspect the body content of a section.
  • Ruff's pydocstyle (D) rules cover docstring presence, surrounding whitespace, and blank lines around section headers (D406D416), but not within section bodies.
  • Sphinx itself does not warn — Napoleon happily produces the broken paragraph.
  • Markdown linters (pymarkdown, markdownlint) only operate on .md files, so they never see these docstrings.

Feature request

Add a new validation check, e.g.:

  • GL11 (or whatever code is free): "Bullet list inside docstring is not preceded by a blank line and will be rendered as inline prose by Sphinx Napoleon."

The detection rule that worked cleanly in practice (zero false positives across a 13k-line scientific Python codebase) is:

Flag a line that starts (after whitespace) with a bullet marker (-, *, or + followed by whitespace) when the immediately preceding non-blank line ends in : and is not itself a bullet line.

This is intentionally narrower than "all bullet lists must be surrounded by blank lines" — it only targets the unambiguous Napoleon-collapse pattern (intro: followed directly by bullets), which is the form that produces the silent rendering bug. Stricter forms can be added later as separate codes if there is appetite.

Precedent

Issue #507 (Add built-in validation checks for directive syntax) makes a structurally identical case: Sphinx silently fails or mis-renders, and numpydoc-validation is the natural place to lint for it before the docs build. This proposal is a sibling in the same spirit but for bullet-list shape rather than directive shape.

Reference implementation

A working AST-based detector (~30 lines) that we are using locally as a stop-gap:
https://github.com/pymc-labs/CausalPy/blob/main/scripts/validate_docstring_lists.py

It walks ast.walk over each module, calls ast.get_docstring(..., clean=False), and applies the rule above. Plumbing it into numpydoc's existing validation pipeline should be straightforward since the docstring is already extracted there.

Offer

Happy to send a PR if the maintainers think this is in scope — would prefer to confirm appetite before investing in the full submission (tests, docs, error-code allocation).

Thank you for your time.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the referenced scripts/validate_docstring_lists.py detector and trace numpydoc's existing validation pipeline to find where extracted docstrings and error codes are handled. Add the focused check for colon-ended introductions followed by bullets, then cover the positive and non-matching cases in the validation tests and document the allocated code.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
documentation
Issue type
Feature
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
63/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.