Skip to content

Read optional params and defaults by one rule - #168

Merged
rr- merged 1 commit into
mainfrom
rework/32-defaults
Nov 6, 2026
Merged

rr- merged 1 commit into
mainfrom
rework/32-defaults

Conversation

@rr-

@rr- rr- commented Nov 6, 2026

Copy link
Copy Markdown
Owner

Each style had its own way of finding that a param is optional and what its default is, and each missed things the others caught. A Google description starting with Defaults to 3. gave no default, because Google only looked for . Defaults to X. in the middle of a sentence. ReST and Epydoc took everything after "defaults to", so py_compile.compile got "the PEP 3147/PEP 488 location" as a default. Numpydoc read default=the out of "By default the …".

Now all four styles use one rule.

In the type, the text is split at commas outside brackets and quotes:

  • optional (in any case, or *optional*), (optional) and a trailing ? mark the param optional.
  • default 1, default=1, default: 1, default is 1, defaults to 1 and defaults 1 give the default, without surrounding backticks.
  • The rest is the type, so {'a', 'b'}, default 'a' keeps its braces and Dict[str, int] keeps its comma.

In the description, when the type has no default: defaults to X, default is X, default value is X, default: X or default=X, case-insensitively. X has to be one value (a literal, a name, a call, or a quoted or bracketed expression), maybe followed by a remark in parentheses or by if, when or unless:

Description default
Defaults to 3. 3
Value (default: 3). 3
Defaults to None, meaning all. None
Defaults to os.getcwd(). os.getcwd()
Defaults to 0 (no padding). 0
The default is to use all of them. none
Unlike the default :meth:run. none

A param with a default is optional. Breaking: is_optional of a parsed param is now always a bool, False instead of None for a param with no type.

Numpydoc compose wrote an optional param with no type as x, optional, which reads back as a param named x, optional. It now writes x : optional. That case got more common with this change, so it's fixed here.

Compose output changes only where a param became optional through its description. For example, Google start (int): Defaults to 0. now composes as start (int?): Defaults to 0..

The numpydoc PARAM_*_REGEX constants and google.GOOGLE_ARG_DESC_REGEX stay importable, but parsing no longer uses them.

Parity against main: 3,289 of 29,123 docstrings differ.

Change case stdlib generated
Only is_optional from None to False 263 94 2,464
Defaults found, dropped or cleaned, and params that became optional with them, plus their compose output 62 2 404

The two stdlib docstrings are getpass.getpass, which gains the defaults 'Password: ' and sys.stderr, and py_compile.compile, which loses two prose "defaults". In the case files, the found defaults include 'greedy' instead of the, np.mean instead of `np.mean`, and pandas' default 'raise' taken out of a type it was stuck in. The dropped ones are prose like "English locale", "displaying nothing" and "an internal Console instance writing to stdout".

Bench on Python 3.8: parse is 0.99–1.02× of main and compose 0.98–1.03×.

@rr- rr- self-assigned this Nov 6, 2026
Every style now splits a param's type the same way, in
_text.type_spec: at commas outside brackets and quotes, taking out
optional (in any case, or as *optional*), (optional), a trailing ?, and
a default written as default 1, default=1, default: 1, default is 1 or
defaults to 1.

With no default in the type, _text.param_spec looks for one the
description states: defaults to X, default is X, default value is X,
default: X or default=X, where X is one value, maybe followed by a
remark in parentheses or a condition. Prose such as "the default is to
use all of them" gives none. Google only knew ". Defaults to X." in the
middle of a description, ReST and Epydoc took everything after
"defaults to".

A param with a default is optional, and is_optional is always a bool:
False instead of None for a param with no type.

Numpydoc composes an optional param with no type as "x : optional", as
"x, optional" read back as a param of that name.
@rr-
rr- force-pushed the rework/32-defaults branch from 5f4a71e to 48acc9a Compare November 6, 2026 17:36
@rr-
rr- merged commit ffd2d1c into main Nov 6, 2026
25 checks passed
@rr-
rr- deleted the rework/32-defaults 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