epythet.validation.parse

Level 0.5: parse each docstring’s docutils doctree and run the ledger’s detectors.

This is the load-bearing level of epythet validate: the research measured that a strict sphinx-build -W -n is silent on 12 of 21 artifact classes, while the doctree of the docstring, parsed in isolation, exposes 20 of them at about a thousand docstrings per second and without a build.

Two things make a naive implementation fail and are handled here:

  • plain docutils knows nothing of :func:, .. versionadded:: and the rest of Sphinx’s vocabulary, so stub roles and directives are registered first (otherwise nearly every correct Sphinx docstring is flagged);

  • with sphinx.ext.napoleon enabled fleet-wide, Google sections are rewritten before docutils sees them, so the same transform is applied here (napoleon=True) and rules can opt out via applies_to.napoleon.

file_insertion_enabled and raw_enabled are off so that a docstring can never make the validator read a file or inject raw HTML.

Module Attributes

ONE_ARGUMENT_DIRECTIVES

Directives whose real implementation takes at most one argument.

Functions

evaluate_rule(rule, parsed)

Run one parse-level rule over one parsed docstring; returns the evidence list.

findings_for(parsed, rules, *[, level])

One finding per (docstring, rule) that fired, carrying the first hit and the count.

install_stubs()

Register stub Sphinx roles and directives with docutils (idempotent).

napoleon_transform(text)

Rewrite Google/NumPy sections into RST fields the way sphinx.ext.napoleon does.

parse_docstring(docstring, *[, napoleon])

Parse one docstring (after the optional napoleon transform).

parse_rst(text)

Parse RST text into a doctree, returning it with the docutils messages.

run_parse_level(docstrings, ledger, *[, ...])

Level 0.5 over a stream of docstrings.

sphinx_available()

Whether sphinx.ext.napoleon can be imported.

Classes

ParsedDocstring(docstring, text, tree, messages)

One docstring, its (possibly napoleon-transformed) text, doctree and messages.

epythet.validation.parse.ONE_ARGUMENT_DIRECTIVES = frozenset({'code', 'code-block', 'literalinclude', 'math', 'sourcecode'})

Directives whose real implementation takes at most one argument.

class epythet.validation.parse.ParsedDocstring(docstring, text, tree, messages, _paragraphs=None, _literals=None)[source]

Bases: object

One docstring, its (possibly napoleon-transformed) text, doctree and messages.

property literals: list[str]

Text of every inline literal.

property paragraphs: list[str]

Prose of every paragraph not inside a system message.

Text inside inline literal nodes is left out, so a field marker quoted as code (double backticks around :param x:) never trips a prose regex.

texts_for(node)[source]

The text corpus a regex detector scans: paragraph, literal or any.

Return type:

list[str]

epythet.validation.parse.evaluate_rule(rule, parsed)[source]

Run one parse-level rule over one parsed docstring; returns the evidence list.

Return type:

list[str]

epythet.validation.parse.findings_for(parsed, rules, *, level=0.5)[source]

One finding per (docstring, rule) that fired, carrying the first hit and the count.

A rule whose detector declares only_if_no_other_hits: true (the catch-all DR032) is evaluated last and reported only when nothing more specific fired on the same docstring, so a docutils message never appears twice under two rule ids.

Return type:

Iterator[Finding]

epythet.validation.parse.install_stubs()[source]

Register stub Sphinx roles and directives with docutils (idempotent).

Return type:

None

epythet.validation.parse.napoleon_transform(text)[source]

Rewrite Google/NumPy sections into RST fields the way sphinx.ext.napoleon does.

Returns text unchanged when Sphinx is not importable; the caller records a note in that case.

Return type:

str

epythet.validation.parse.parse_docstring(docstring, *, napoleon=True)[source]

Parse one docstring (after the optional napoleon transform).

Return type:

ParsedDocstring

epythet.validation.parse.parse_rst(text)[source]

Parse RST text into a doctree, returning it with the docutils messages.

Return type:

tuple[document, list[str]]

epythet.validation.parse.run_parse_level(docstrings, ledger, *, napoleon=True)[source]

Level 0.5 over a stream of docstrings.

Return type:

list[Finding]

epythet.validation.parse.sphinx_available()[source]

Whether sphinx.ext.napoleon can be imported.

Return type:

bool