A reStructuredText formatter
Project description
🧾 Restitutor
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)
- Literal/code blocks (both
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.rstfiles to process. -
-i, --in-place
Rewrite the given.rstfiles in-place instead of printing tostdout. -
-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:
docutils.core.publish_doctree()parses the input.rstinto anodes.documentAST.- Restitutor registers a set of custom directives and roles so that Sphinx-like constructs are captured as specific node types:
TocTreeNodefor.. toctree::CurrentModuleNodefor.. currentmodule::XRefNodefor cross-reference rolesMarkingListTablewraps thelist-tabledirective and annotates the resulting table with metadata to reconstruct itMarkingTablewraps.. table::and preserves title/width information- Several
Doxy*Nodetypes for Breathe/Doxygen directives CppNodefor C++ domain directives like.. cpp:function::
ast_to_rst()recursively walks the doctree and emits reStructuredText, guided by a formatting context (FmtCtx) that tracks indentation and list prefixes.- 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
RuntimeErrorduring 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 wholedocument) 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:
- Issues: https://github.com/KurtBoehm/restitutor/issues
- Repository: https://github.com/KurtBoehm/restitutor
If you encounter
- crashes on particular
.rstinput, - 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.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file restitutor-0.2.0.tar.gz.
File metadata
- Download URL: restitutor-0.2.0.tar.gz
- Upload date:
- Size: 28.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e7c95b00a3855c604ee3eede2e3659b400ef5174466d5478939414669a3f6a62
|
|
| MD5 |
10685a0d160fea2a2fbc62dc75c3438d
|
|
| BLAKE2b-256 |
7c20beea61dfe3e7c2dea33e65cbecfa2adb7877f88bd80836b82567626f9f16
|
Provenance
The following attestation bundles were made for restitutor-0.2.0.tar.gz:
Publisher:
publish-to-pypi.yml on KurtBoehm/restitutor
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
restitutor-0.2.0.tar.gz -
Subject digest:
e7c95b00a3855c604ee3eede2e3659b400ef5174466d5478939414669a3f6a62 - Sigstore transparency entry: 1226908168
- Sigstore integration time:
-
Permalink:
KurtBoehm/restitutor@fe5b9326315225201bd66c7bc94ef7332b29e0b1 -
Branch / Tag:
refs/tags/0.2.0 - Owner: https://github.com/KurtBoehm
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-to-pypi.yml@fe5b9326315225201bd66c7bc94ef7332b29e0b1 -
Trigger Event:
release
-
Statement type:
File details
Details for the file restitutor-0.2.0-py3-none-any.whl.
File metadata
- Download URL: restitutor-0.2.0-py3-none-any.whl
- Upload date:
- Size: 28.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
25338a2550e277bafc83f40c0511ba9493fed113e0d2d6be7ec890ea68314186
|
|
| MD5 |
ac38c6df04d4da6576863e2084ff8a56
|
|
| BLAKE2b-256 |
1c61486960c4d7e4ac9f3a0a101e9f462a6db764dca6b619bbf959715525e1c4
|
Provenance
The following attestation bundles were made for restitutor-0.2.0-py3-none-any.whl:
Publisher:
publish-to-pypi.yml on KurtBoehm/restitutor
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
restitutor-0.2.0-py3-none-any.whl -
Subject digest:
25338a2550e277bafc83f40c0511ba9493fed113e0d2d6be7ec890ea68314186 - Sigstore transparency entry: 1226908214
- Sigstore integration time:
-
Permalink:
KurtBoehm/restitutor@fe5b9326315225201bd66c7bc94ef7332b29e0b1 -
Branch / Tag:
refs/tags/0.2.0 - Owner: https://github.com/KurtBoehm
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-to-pypi.yml@fe5b9326315225201bd66c7bc94ef7332b29e0b1 -
Trigger Event:
release
-
Statement type: