Skip to content

Split examples as doctest reads them - #167

Merged
rr- merged 3 commits into
mainfrom
rework/31-doctest-examples
Nov 6, 2026
Merged

rr- merged 3 commits into
mainfrom
rework/31-doctest-examples

Conversation

@rr-

@rr- rr- commented Nov 6, 2026

Copy link
Copy Markdown
Owner

Numpydoc and Google now split an examples section the way doctest reads it. Each example holds the text that introduces it as description, and a snippet with the >>> lines, their ... continuations and the expected output, up to a blank line or the next >>> line. Text after the last snippet becomes an example with no snippet.

Examples
--------
To print the numbers:

>>> for i in range(2):
...     print(i)
0
1

Then more text.

Before, Numpydoc gave snippet=">>> for i in range(2):" and put the ... line and the output into the description, together with the text after it. Google kept the whole section as one example with no snippet. Now both styles give two examples:

  • description="To print the numbers:", with the snippet holding the for loop, its print(i) continuation and the output 0 and 1
  • description="Then more text.", snippet=None

This is breaking for users who read example.description: it used to be the text after a snippet in Numpydoc, and is now the text before it.

Compose writes each example's text, a blank line, then its snippet, so the result reads back the same in both styles. A snippet with no text follows the previous one directly. A Google section with nothing in it still gives one empty example, as before, so auto-detection doesn't change for docstrings whose examples aren't indented under the title. Google compose also stops writing trailing spaces on the blank lines inside a section like Examples.

Parity: 794 of 29,123 docstrings differ from main.

  • 254 contain examples: 140 case, 109 generated, 5 stdlib. Two of the generated ones, which mix several styles' syntax, are now auto-detected as Google instead of ReST or Epydoc, because more examples mean more items.
  • 540 differ only by trailing spaces in Google compose output: 21 case, 517 generated, 2 stdlib.

145 case files change for these reasons, plus two Numpydoc tests that pinned the old pairing.

Bench on 3.8: parse is 0.99–1.02x of main, compose 0.98–1.02x.

@rr- rr- self-assigned this Nov 6, 2026
rr- added 2 commits November 6, 2026 18:39
An example is now the text that introduces it and a snippet holding the
>>> lines, their ... continuations and the expected output, up to a
blank line or the next >>> line. Text after the last snippet is an
example of its own, with no snippet. Numpydoc paired a snippet with the
text after it and moved continuation lines out of the snippet, and
Google kept a whole section as one example with no snippet.

Both styles compose examples so that they read back the same: the text,
a blank line, then the snippet. Google no longer writes trailing spaces
on the blank lines of a section such as Examples.
An example with no snippet is the text after its section's last
snippet. Composing every example into one section joined such text
with the next examples, which read back as fewer examples. End a
section after it, and give an empty example a section of its own.
@rr-
rr- force-pushed the rework/31-doctest-examples branch from 3eefc88 to 0fdd784 Compare November 6, 2026 17:40
Python 3.8 evaluates a nested function's annotations each time it is
defined, which made composing Google docstrings 13% slower. Write the
sections with a function at module level.
@rr-
rr- merged commit aa0358f into main Nov 6, 2026
25 checks passed
@rr-
rr- deleted the rework/31-doctest-examples 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