Skip to content

Read the rest of napoleon's sections in Google and Numpydoc - #180

Merged
rr- merged 2 commits into
mainfrom
rework/38-napoleon-sections
Nov 6, 2026
Merged

rr- merged 2 commits into
mainfrom
rework/38-napoleon-sections

Conversation

@rr-

@rr- rr- commented Nov 6, 2026

Copy link
Copy Markdown
Owner

Google and Numpydoc now recognise every section listed in the Sphinx napoleon docs:

  • Keyword Args / Keyword Arguments are keyword params (Kind.KEYWORD), in both styles.
  • Google only: Other Parameters and Receive / Receives are other and received params. Warns / Warn give raises of Kind.WARNS. Raise, Return and Yield are read like their plural forms.
  • These are free-text sections, each giving a text meta with its title set: Note(s), Warning(s), See Also, References, Todo, Methods, Attention, Caution, Danger, Error, Hint, Important and Tip. Numpydoc already had the first four, and its text metas now carry their title as well.
  • Google Deprecated: gives a DocstringDeprecated. If the body starts with a version, that becomes the version: 1.2.0 Use other instead. gives version 1.2.0 and description Use other instead.

Compose writes keyword, other and received params, and warns, into sections of their own. In Google they used to go under Args: / Raises:, and in Numpydoc keyword params went under Parameters, so they read back as the wrong kind. Google text sections are written under their title and no longer under a name derived from the key. For example, see_also used to come out as Seealso:.

Google compose also indents a summary that would otherwise read as a title, such as Note:, when a later line is unindented. One generated docstring now round trips because of this, so (1856, GOOGLE) is removed from GENERATED_EXCLUSIONS. No other exclusions changed.

With roughly 40 titles in the regex, Google parse got 65% slower and Numpydoc 23% slower. The cause was a capture group around every title, which stops the regex engine from skipping an alternative after its first letter. Google now uses one group for the title. Numpydoc uses none for headers that begin with their title, and reads the title from the first line of the match. Compose's nested functions on 3.8 now use annotation aliases defined once at module level.

Thanks to @BrianPugh, whose #108 asked for several of these sections.

Case diffs

  • 147 Numpydoc case files only gain a title: line on their text metas (Notes, See Also, Warnings, ...).
  • convert/numpydoc-other-and-received-params and convert/rest-params: other, received and keyword params are composed to Google under Other Parameters:, Receives: and Keyword Args: instead of Args:. Numpydoc puts keyword params under Keyword Arguments.
  • corpus/pydantic/pydantic.fields.Field: Note: was long description and is now a notes text meta.
  • corpus/numpy/..._NestedSequence: its Warning heading keeps that title, so compose writes Warning instead of Warnings.
  • New: google/napoleon_sections_01 to _03, google/summary_title_01 and numpydoc/napoleon_sections_01.

Parity against origin/main

origin differ compose only parses only in base
case 144 of 1552 139 0
stdlib 26 of 7631 1 3
generated 3985 of 20000 3250 0

tools/parity.py also reports 13 generated inputs that parse only in the tree.

Most of the compose-only differences come from three things: the title that compose now writes (See Also: instead of Seealso:), the new keyword/other/received/warns sections, and the indented title-like summary when composing to Google from another style. The stdlib parse differences are docstrings where a line like Methods:, References:, Notes:, Note: or Example: now starts a section. The three that parse only in base are argparse's Action, FileType and ArgumentParser: their Keyword Arguments: items look like - prog -- text, which have no colon, so a Google parse now raises ParseError where it used to keep the text. Napoleon reads those the same way. Auto-detection still picks another style for them.

Bench

Python 3.8, ratios between 0.76 and 1.06. The worst is Google parse at 1.06, mostly due to case-insensitive matching. Numpydoc parse is 0.84 and Google compose 0.78.

Not done

  • A Numpydoc Deprecated heading with an underline. Numpydoc already reads .. deprecated:: version, the numpydoc form, and a Deprecated heading would clash with it once titles match in any case.
  • Methods is free text. Napoleon reads it as name: description fields, but no Kind exists for methods.

Google read only params, raises, attributes, examples, returns and
yields, and Numpydoc lacked Keyword Arguments, Methods, Todo and the
admonitions. Both now read every section napoleon lists:

- Keyword Args and Keyword Arguments, as keyword params
- Other Parameters and Receive(s), in Google, as their params
- Warns and Warn, in Google, as warnings raised
- Raise, Return and Yield, in Google, as their plural
- Note(s), Warning(s), See Also, References, Todo, Methods,
  Attention, Caution, Danger, Error, Hint, Important and Tip, as text
- Deprecated, in Google, as a deprecation, with the version its body
  starts with, as in "1.2.0 Use other instead."

A text section's meta keeps the section's title, which compose writes
back. Compose gives keyword, other and received params and warnings
sections of their own, so they read back as the kind they are.

Compose indents a Google summary that reads as a title, such as
"Note:", when a later line is unindented, as it was indented to be
read as a summary. That makes one generated docstring round trip.

Matching 40 titles with a group around each made Google parse 65%
slower: a group keeps the regex engine from skipping an alternative
at its first letter. Google now has one group for the title, and
Numpydoc none for the titles that start their header, its title then
being the first line of the match. Compose's nested functions take
named annotations, which Python 3.8 evaluates at each definition.
@rr- rr- self-assigned this Nov 6, 2026
With napoleon's sections the title regex has three times the
alternatives, and matching in any case keeps the regex engine from
skipping them by their first letter, so trying each at every line start
made Google parsing about 10% slower than before on Python 3.14.

Only a line that ends in a colon can hold a title, so find those lines
first and match the title regex at their start alone. Parsers with bare
titles or no title colon still search the whole text. In compose, look
for a colon in the summary before taking its first line apart.
@rr-
rr- merged commit 9c08845 into main Nov 6, 2026
26 checks passed
@rr-
rr- deleted the rework/38-napoleon-sections branch November 6, 2026 23:51
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