Skip to content

What it leaves out

Every markup language is defined by what it refuses. This page lists each refusal and the evidence for it.

The evidence is a survey of every module, class and function docstring in the Python 3.12 standard library, all 7272 of them, excluding tests, idlelib, lib2to3 and encodings. Where a number appears below, it came from that corpus.

Headings: the exception

Included, against the evidence. Measured usage:

docstrings share
# ATX heading 7 0.1%
reST underline heading 21 0.3%

Twenty-eight docstrings out of 7272. By the standard applied everywhere else on this page they should be cut.

They are in anyway, on familiarity grounds: Markdown without # surprises people, and a format nobody can guess is a format nobody adopts. A plain reading of the numbers is that nobody uses headings because nothing renders them; that argument is unfalsifiable and would justify any feature, so it is offered as a reason and not as evidence.

This is the one place where taste beat measurement. Everything below is measurement.

Definition lists

Not included, and this one was decided twice.

reStructuredText has definition lists (a term on one line, an indented body), and the shape appears 264 times in the corpus. That looks like a strong case until you read what those 264 actually are. Sampling them:

  • Section headers: Args:, Attributes:, Arguments:, Methods: followed by an indented body. Google style, arrived at independently.
  • Hand-aligned prose: quiet: full output with False or 0, / no output with 2: a continuation aligned by eye, at 11 spaces.
  • Lead-ins to examples: For example:, The special characters are:.
  • Actual definition lists: rare.

Adopting the syntax would misparse the first three. Since prose continuation and section headers are both more common than real definition lists, the construct would do more harm than good. reStructuredText still reads that shape as a definition list, so it earns L004 under --compat: migration advice for a codebase moving away from reST.

Parameter documentation is served by bullet lists. Sections are out of scope entirely.

Emphasis that fires on arithmetic

Included, but with reStructuredText's rule rather than CommonMark's.

4.0% of docstrings contain * or ** before a word, and inspecting them shows most are not *args at all; they are arithmetic. From _pydecimal.py:

Given integers xc, xe, yc and ye representing Decimals x = xc*10**xe and
y = yc*10**ye, compute x**y.

Three ** runs in one paragraph. CommonMark pairs them and emits <em> and <strong> across the middle of the formula. The same happens to The __init__ and __del__ methods.

Simplemark emits neither, because its one narrowed rule forbids emphasis inside a word. That rule is a strict narrowing of CommonMark's, tested against the reference parser, simplemark never finds emphasis CommonMark would not. The rule was taken from reStructuredText, which got it right in 2001; that is provenance, not a compatibility claim.

Which spelling to keep was also measured:

docstrings
*emphasis* 251
**strong** 1

Both are kept, but note the inversion: the discussion that prompted this project argued entirely about **bold**, while the corpus uses *italic* 251 times: overwhelmingly to mark parameter names (*encoding*, *opener*, *followlinks*), which is exactly the problem the format exists to solve.

Fenced code blocks

Included, alongside indentation. Indentation is the native convention in Python docstrings: 7.7% of the corpus has an indented verbatim block, split between doctests (4.4%) and plain examples (3.3%), and nobody in the standard library writes fences. But a fence can hold content that starts with something looking like markup, which an indented block cannot express, so the two are not redundant spellings of one thing.

Ordered lists: kept despite the evidence

Numbered lists appear in 9 docstrings out of 7272, 0.1%. By the standard applied to headings they should be cut.

They are kept, because cutting them would not remove 1. from prose; it would only make simplemark disagree with CommonMark about text that already exists. Keeping them costs about fifteen lines and removes a divergence. Omission is only worth it when the construct is both unused and harmless to leave out.

Parameter sections

Out of scope, permanently. No Args:, no Returns:, no Raises:.

Google and NumPy style already occupy that ground, napoleon already translates them, and the typing system is where parameter semantics belong. The original complaint that motivated simplemark asked for two things: reflow with exemptions, and a standard way to highlight parameter names. Code spans answer the second. Parameter sections were never part of it.

An Args: block in an opted-in docstring stays a verbatim block: preformatted, unreflowed, exactly what pydoc does today. No regression, no improvement, no scope creep.

Everything else

Not included, and not planned:

Why
Tables The corpus aligns them by hand inside verbatim blocks, which works
Block quotes No use found in docstrings; reST reads bare indentation as one already
Images Nothing to do with a terminal
Footnotes, citations Documentation-site features, not docstring features
Reference links Non-local: the meaning of [a][b] depends on text elsewhere in the document
Raw HTML A terminal renderer cannot use it, and it is an injection surface
Thematic breaks Decoration
Hard line breaks Incompatible with reflow, which is the point of the format
Setext headings There are no headings
Nested inline markup Removes the delimiter stack, and no docstring needs it
Directives, roles, attributes This is where every documentation format starts growing without limit
Extensibility Extend the renderers, not the syntax

The point of all this

Each cut buys the same thing: a smaller implementation that someone other than its author can maintain. The result is 788 lines of code, no runtime dependencies, and a grammar that fits on one page.

That is the argument the format has to win, and it can only be won by subtraction.