sphinx-rustdoc-postprocess
Post-process sphinxcontrib-rust RST output, converting leftover markdown fragments (code fences, tables, links, headings, inline code) to proper RST via pandoc.
The problem
sphinxcontrib-rust generates RST files from Rust crates, but rustdoc
doc-comments are written in markdown. The generated RST ends up with markdown
fragments embedded verbatim inside directive bodies, which Sphinx cannot render
correctly.
For a real-world example, see rgpot (source), which uses this extension to document its Rust core library alongside C++ API docs.
Before (raw sphinxcontrib-rust output)
Given Rust doc-comments like these in lib.rs:
//! ## Module Overview
//!
//! | Module | Purpose |
//! |--------|---------|
//! | [`types`] | `#[repr(C)]` data structures for force/energy I/O |
//! | [`tensor`] | DLPack tensor helpers |
sphinxcontrib-rust produces RST with the markdown still intact inside directives:
.. py:module:: rgpot_core
## Module Overview
| Module | Purpose |
|--------|---------|
| [`types`] | `#[repr(C)]` data structures for force/energy I/O |
| [`tensor`] | DLPack tensor helpers |
This renders incorrectly in Sphinx: headings inside directives break the document structure, markdown tables appear as literal pipe characters, and single-backtick code is not valid RST.
After (postprocessed output)
After this extension runs, the same file becomes:
.. py:module:: rgpot_core
**Module Overview**
+------------+----------------------------------------------------+
| Module | Purpose |
+============+====================================================+
| ``types`` | ``#[repr(C)]`` data structures for force/energy IO |
+------------+----------------------------------------------------+
| ``tensor`` | DLPack tensor helpers |
+------------+----------------------------------------------------+
Similarly, markdown code fences:
```c
rgpot_status_t s = rgpot_potential_calculate(pot, &input, &output);
if (s != RGPOT_SUCCESS) {
fprintf(stderr, "rgpot error: %s\n", rgpot_last_error());
}
```
become proper RST code-block directives:
.. code-block:: c
rgpot_status_t s = rgpot_potential_calculate(pot, &input, &output);
if (s != RGPOT_SUCCESS) {
fprintf(stderr, "rgpot error: %s\n", rgpot_last_error());
}
And markdown links like [metatensor](https://docs.metatensor.org/) become
`metatensor <https://docs.metatensor.org/>`_, while rustdoc intra-doc links
like [`types`] become types .
Installation
pip install sphinx-rustdoc-postprocess
Pandoc must be available on your PATH. See pandoc.org for installation
instructions.
Usage
Add to your Sphinx conf.py:
extensions = [
"sphinxcontrib_rust",
"sphinx_rustdoc_postprocess",
]
The extension hooks into builder-inited at priority 600 (after
sphinxcontrib-rust's default 500), so it automatically runs on the generated
RST files before Sphinx reads them.
Configuration
| Config value | Default | Description |
|---|---|---|
rustdoc_postprocess_rst_dir |
"crates" |
Subdirectory of srcdir to scan for RST files |
rustdoc_postprocess_toctree_target |
"" |
RST file to inject a toctree snippet into (empty = skip) |
rustdoc_postprocess_toctree_rst |
"" |
RST snippet to append to the target file (empty = skip) |
Full configuration example
# conf.py
import os
extensions = [
"sphinxcontrib_rust",
"sphinx_rustdoc_postprocess",
]
# sphinxcontrib-rust settings
rust_crates = {
"my_crate": os.path.abspath("../../my-crate/"),
}
rust_doc_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "crates")
rust_rustdoc_fmt = "rst"
# Inject a toctree entry for the Rust docs into an existing index page
rustdoc_postprocess_toctree_target = "api/index.rst"
rustdoc_postprocess_toctree_rst = """
Rust API
--------
.. toctree::
:maxdepth: 2
../crates/my_crate/lib
"""
What gets converted
| Markdown construct | RST output |
|---|---|
```lang code fences |
.. code-block:: lang directives |
\vert table \vert pipe tables |
RST grid tables (via pandoc) |
[text](url) links |
`text <url>`_ |
[`Name`] intra-doc links |
``Name`` |
`code` inline code |
``code`` |
## Heading ATX headings |
**Heading** (bold, since RST headings can't nest in directives) |
Development
pixi install
pixi run test
A pre-commit job is setup on CI to enforce consistent styles, so it is best
to set it up locally as well (using uvx for isolation):
# Run before committing
uvx pre-commit run --all-files
License
MIT
Metadata
Release files for sphinx-rustdoc-postprocess 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| sphinx_rustdoc_postprocess-0.1.1.tar.gz | 88.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sphinx_rustdoc_postprocess-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 97.1 kB
Release files / sphinx_rustdoc_postprocess-0.1.1.tar.gz
| Download URL | sphinx_rustdoc_postprocess-0.1.1.tar.gz |
|---|---|
| Size | 88.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
091cf42f660049e17c8632390a16267006800747b86635063fda02dbc5df6a94
|
|
BLAKE2b-256 checksum How to use checksums |
29b5fbf07cd42648bad3f6c8026a724d4099230373b1bc2633e5b27137aef101
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 Jul 9, 2026.
Transparency logRelease files / sphinx_rustdoc_postprocess-0.1.1-py3-none-any.whl
| Download URL | sphinx_rustdoc_postprocess-0.1.1-py3-none-any.whl |
|---|---|
| Size | 8.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f650713d35c89e87d78022bc4d598f9786ac8e5a6c699e1f3ab47ab54f23abbe
|
|
BLAKE2b-256 checksum How to use checksums |
269bd12031e1dc3aadb5123629a83688bf088539d69f2a6850729aca2464c204
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 Jul 9, 2026.
Transparency log