Skip to content

Enable the D417 Ruff rule and stop repeating type annotations in docstrings - #104

Merged
mmacferrin merged 2 commits into
mainfrom
ruff-d417
Sep 3, 2026
Merged

Enable the D417 Ruff rule and stop repeating type annotations in docstrings#104
mmacferrin merged 2 commits into
mainfrom
ruff-d417

Conversation

@mmacferrin

@mmacferrin mmacferrin commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Progress on #40. Two commits, each independently green.

1. Enable D417 and set the Google docstring convention

D417 (undocumented-param) was suppressed because it reported nine functions with undocumented parameters. Eight of those were false positives. No pydocstyle convention was configured, so Ruff parsed the Parameters + dashed-underline headers as NumPy sections, found no NumPy-formatted entries inside, and reported every argument as undocumented.

The docstring bodies are Google-style throughout, and docs/source/conf.py already sets napoleon_google_docstring = True, so the convention is pinned to google. That takes D417 from 9 findings to 1; numpy would have left 8. The only rules the convention retires are D400, whose check is subsumed by the still-active D415, and the cosmetic D413.

The 49 dashed section headers become Args:/Returns:/Raises:, and the parameters that were genuinely undocumented — visible only once the sections parsed — are filled in: omit_bboxes, gdf, auto_clean_csv, tolerance, three in process_parallel, and dem_ndv / min_confidence_level / min_bathy_confidence in validate_dem, worded from the CLI help for the matching options.

D417 also caught a real documentation bug: process_parallel documented a kwargs_lists parameter that the signature spells kwargs_list.

Ignore list: 57 → 56.

2. Let annotations be the only source of parameter types

Google's style guide asks for a type in an Args: entry only when the signature does not annotate the parameter, and conf.py loads sphinx_autodoc_typehints with always_document_param_types = True — so an annotated parameter already renders its type and default from the signature. A hand-written type is a duplicate that can contradict it, and did:

count
params documented with a type 86
annotated and agreeing 45
annotated and divergent 28
unannotated (docstring is the only source) 13

The drift was almost entirely a | None added to a signature and never to the prose — validate_dem's output_dir claimed str against an annotation of str | None. The type is dropped from all 73 annotated parameters and kept, in Google name (type): form, for the 13 without annotations.

Three problems in the same docstrings were stopping Sphinx from rendering these sections at all, and are fixed here too:

  • 30 entries were NumPy-shaped (name : type, prose on the next line). Napoleon splits on the first colon, so the type rendered as the opening words of the description.
  • 22 section bodies sat flush with their header instead of indented under it. D417 accepts that; napoleon reads the section as empty and emits no parameters.
  • 3 Raises: blocks put the exception name on its own line.

Verification

Running every docstring through napoleon with this repo's own conf.py settings, counting parameters emitted as real :param: fields in the files touched here:

:param fields
main 50
this branch 124

No documented parameter fails to render, and no rendered description still opens with a bare type.

ruff check, ruff format and the full prek suite pass at both commits. No code changed anywhere — every edited file was verified to produce an identical AST once docstring constants are blanked, with docstring counts unchanged.


🔍 Docs preview: https://ivert--104.org.readthedocs.build/en/104/

D417 was suppressed because it reported 9 functions with undocumented
parameters. Eight of those were false positives: no pydocstyle convention
was configured, so Ruff parsed the `Parameters` + dashed-underline headers
as NumPy sections, found no NumPy-formatted entries inside them, and
reported every argument as undocumented.

The docstring bodies are Google-style throughout, and docs/source/conf.py
already sets napoleon_google_docstring = True, so pin the convention to
google. That drops D417 from 9 findings to 1, where numpy would leave 8.
The only rules the convention retires are D400, whose check is subsumed by
the still-active D415, and the cosmetic D413.

Convert the 49 dashed section headers to Args:/Returns:/Raises: and fill in
the parameters that were genuinely undocumented once the sections parsed:
omit_bboxes, gdf, auto_clean_csv, tolerance, three in process_parallel, and
dem_ndv/min_confidence_level/min_bathy_confidence in validate_dem, whose
wording follows the CLI help for the matching options. process_parallel
also documented a "kwargs_lists" parameter that the signature spells
kwargs_list.

Only docstrings change here; every edited file was checked to have an
identical AST once docstring constants are blanked.
Google's style guide asks for a type in an Args: entry only when the
signature does not annotate the parameter, and docs/source/conf.py loads
sphinx_autodoc_typehints with always_document_param_types = True, so an
annotated parameter already renders its type and default from the
signature. A hand-written type is therefore a duplicate that can, and did,
contradict the signature: 28 of the 73 annotated parameters carrying a type
disagreed with their annotation, nearly all of them missing a "| None"
added to the signature later.

Drop the type from all 73 annotated parameters and keep it, in Google
"name (type):" form, for the 13 that have no annotation.

Three problems in the same docstrings kept Sphinx from rendering these
sections at all, and are fixed here too:

  - 30 entries were NumPy-shaped ("name : type" with the prose on the
    following line). Napoleon splits on the first colon, so the type was
    rendered as the opening words of the description.
  - 22 section bodies sat flush with their Args:/Returns:/Raises: header
    rather than indented under it. D417 accepts that; napoleon reads the
    section as empty and emits no parameters.
  - 3 Raises: blocks put the exception name on its own line.

Across the files touched here, the number of parameters napoleon renders as
real :param: fields goes from 50 to 124, with no documented parameter left
unrendered and no description still opening with a bare type.

Docstrings only; each edited file has an identical AST once docstring
constants are blanked.
@mmacferrin
mmacferrin merged commit 5b73caa into main Sep 3, 2026
5 checks passed
@mmacferrin
mmacferrin deleted the ruff-d417 branch September 3, 2026 22:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant