Add built-in validation check for bullet lists missing a preceding blank line
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-validationchecks (GL01–GL10,SS01–SS06,PR01–PR10,RT01–RT05,SA01–SA04,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 (D406–D416), but not within section bodies. - Sphinx itself does not warn — Napoleon happily produces the broken paragraph.
- Markdown linters (
pymarkdown,markdownlint) only operate on.mdfiles, 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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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