Skip to main content

🧾 Restitutor

PyPI - Version Test Workflow Status

An opinionated formatter for reStructuredText (reST) files.

Restitutor parses .rst files with docutils, reconstructs them from the AST, and writes them back in a normalized, consistent style. It aims to be safe, predictable, and friendly to tooling and code review.

✨ Features

  • Normalizes general reStructuredText structure:
    • Headings with consistent adornments
    • Paragraph spacing
    • Bullet and enumerated lists
    • Definition lists and field lists
    • Option lists (CLI style options and descriptions)
  • Preserves and re-emits several Sphinx-style constructs:
    • .. toctree::
    • .. currentmodule::
    • Cross-reference roles like :func:, :class:, :mod:, :ref:, :term:, :envvar:, etc.
    • Generic text roles like :emphasis:, :literal:, :strong:
    • Breathe directives such as .. doxygenclass::, .. doxygenfunction::, etc.
    • C++ domain directives such as .. cpp:function::, .. cpp:class::, etc.
  • Enhanced table handling:
    • Grid tables are reflowed with consistent borders and spacing
    • .. list-table:: tables are preserved as list-table directives
    • Optional preservation of blank-line spacing between list-table rows
    • .. table:: directives are reconstructed around grid tables, with :widths: preserved
  • Handles inline markup:
    • *emphasis*, **strong**, inline literals
    • Hyperlinks and cross-references (including anonymous targets)
    • Substitutions (definitions and uses: .. |name| replace:: and |name|)
    • Inline maths via :math:
  • Renders block-level constructs:
    • Literal/code blocks (both :: and .. code:: lang / .. code-block:: lang)
    • Images (.. image::)
    • Generic admonitions (.. admonition:: Title)
    • Standard admonitions (.. note::, .. warning::, .. tip::, etc.)
    • Line blocks (| line)
    • Footnotes and citations (.. [#]_, .. [label] and corresponding references)

The formatter currently targets a subset of docutils/Sphinx nodes. If it encounters unknown or unsupported nodes, it fails loudly rather than silently corrupting the output.

📦 Installation

Restitutor requires Python 3.12+ and is available on PyPI:

pip install restitutor

🧑‍💻 Usage

The package installs a console script restitute with the following interface:

restitute [-i|--in-place] [-c|--clean] RST [RST ...]
  • RST
    One or more paths to .rst files to process.

  • -i, --in-place
    Rewrite the given .rst files in-place instead of printing to stdout.

  • -c, --clean
    Normalize newlines.

    By default, Restitutor preserves blank-line counts between rows in .. list-table:: tables. With --clean, extra blank lines are removed for a cleaner, but less faithful, representation.

📚 Examples

# Format one or more `.rst` files and print to stdout
restitute docs/index.rst
restitute docs/index.rst docs/usage.rst

# Rewrite files in place
restitute -i docs/index.rst
restitute --in-place docs/*.rst

# Normalize newlines between `list-table` rows
restitute -i --clean docs/*.rst

🧠 How it works

At a high level:

  1. docutils.core.publish_doctree() parses the input .rst into a nodes.document AST.
  2. Restitutor registers a set of custom directives and roles so that Sphinx-like constructs are captured as specific node types:
    • TocTreeNode for .. toctree::
    • CurrentModuleNode for .. currentmodule::
    • XRefNode for cross-reference roles
    • MarkingListTable wraps the list-table directive and annotates the resulting table with metadata to reconstruct it
    • MarkingTable wraps .. table:: and preserves title/width information
    • Several Doxy*Node types for Breathe/Doxygen directives
    • CppNode for C++ domain directives like .. cpp:function::
  3. ast_to_rst() recursively walks the doctree and emits reStructuredText, guided by a formatting context (FmtCtx) that tracks indentation and list prefixes.
  4. The resulting text is either printed or written back to the original file.

Headings

Headings use a fixed adornment sequence:

ADORNMENTS = ["#", "*", "=", "-", "^"]

Level 0 and 1 use overline/underline; deeper levels use underline only:

#############
 Top Heading
#############

************
 Subheading
************

Title
=====

Subtitle
--------

Minor
^^^^^

Lists

Bullet and enumerated lists are normalized to a consistent style:

  • Bullet lists use -
  • Enumerations preserve style where possible (1., a., A., Roman numerals, #. auto-numbered, etc.)
  • Definition lists and field lists are emitted in canonical reST form
  • Option lists keep CLI options and descriptions tightly aligned

Tables

  • Grid tables are rendered with full borders and aligned columns.
  • .. list-table:: tables are preserved as .. list-table::; options like :header-rows: and :widths: are preserved.
  • .. table:: directives are reconstructed around grid tables, including optional :widths:.
  • Without --clean, Restitutor preserves the number of blank lines between top-level list-table rows.

⚠️ Caveats and Limitations

  • Only a subset of docutils/Sphinx nodes is supported. Unsupported nodes raise RuntimeError during formatting.
  • There is no test suite yet.

🧩 API (Internal)

The project is currently focused on the CLI. The main internal entry points are:

  • format_rst(rst_source: str, *, clean: bool = True) -> str
    Parse and re-emit a full reST document from a string.
  • ast_to_rst(buf: Buffer, node: nodes.Node, ctx: FmtCtx, preproc: PreprocessInfo) -> None
    Convert a docutils node (usually a whole document) back into reStructuredText, appending to a buffer.
  • FmtCtx
    A dataclass controlling indentation and list-formatting context.

These APIs are internal and may change without notice.

🤝 Contributing

Issues and pull requests are welcome at:

If you encounter

  • crashes on particular .rst input,
  • incorrect rendering of supported constructs,
  • or want support for additional Sphinx/directive features,

please open an issue with a minimal reproducer (input .rst and observed vs expected output).

📜 Licence

Restitutor is licensed under the Mozilla Public Licence 2.0, provided in License.

Metadata

Release files for restitutor 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for restitutor 0.2.0
File Size Uploaded
restitutor-0.2.0.tar.gz 28.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for restitutor 0.2.0
File Interpreter ABI Platform
restitutor-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 57.6 kB

Release files / restitutor-0.2.0.tar.gz

Download URL restitutor-0.2.0.tar.gz
Size 28.7 kB
Tags Source
SHA-256 checksum
How to use checksums
e7c95b00a3855c604ee3eede2e3659b400ef5174466d5478939414669a3f6a62
BLAKE2b-256 checksum
How to use checksums
7c20beea61dfe3e7c2dea33e65cbecfa2adb7877f88bd80836b82567626f9f16
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 3, 2026.

Transparency log

Release files / restitutor-0.2.0-py3-none-any.whl

Download URL restitutor-0.2.0-py3-none-any.whl
Size 28.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
25338a2550e277bafc83f40c0511ba9493fed113e0d2d6be7ec890ea68314186
BLAKE2b-256 checksum
How to use checksums
1c61486960c4d7e4ac9f3a0a101e9f462a6db764dca6b619bbf959715525e1c4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 3, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page