M2R2
M2R2 converts a markdown file including reStructuredText (rst) markups to a valid rst format.
M2R: the original
M2R2 is a fork of m2r which has been archived. Every m2r config should work out of the box.
Why another converter?
Sphinx documents benefit from being written in markdown, since it's widely used and easy to write code blocks and lists. However, converters using pandoc or recommonmark do not support many rst markups and sphinx extensions. For example, rst's reference link like see `ref`_ (very convenient in long documents where the same link appears multiple times) gets converted to a code block in HTML like see <code>ref</code>_, which is not expected.
Features
- Basic markdown and some extensions (see below)
- inline/block-level raw html
- fenced-code block
- tables
- footnotes (
[^1])
- Inline- and Block-level rst markups
- single- and multi-line directives (
.. directive::) - inline-roles (
:code:`print(1)` ...) - ref-link (
see `ref`_) - footnotes (
[#fn]_) - math extension inspired by recommonmark
- single- and multi-line directives (
- Sphinx extension
- add markdown support for sphinx
mdincludedirective to include markdown from md or rst files- option to parse relative links into ref and doc directives (
m2r_parse_relative_links) - option to render
mermaidblocks as graphs with sphinxcontrib.mermaid (m2r_use_mermaid, default: auto)- auto means that m2r2 will check if
sphinxcontrib.mermaidhas been added to the extensions list
- auto means that m2r2 will check if
- Pure python implementation
- pandoc is not required
Installation
Python 3.9+ is required.
uv add m2r2
Or use uvx to run without installing:
uvx m2r2 your_document.md
For Sphinx integration:
uv add m2r2[sphinx]
Usage
Command Line
m2r2 command converts markdown file to rst format.
m2r2 your_document.md [your_document2.md ...]
Then you will find your_document.rst in the same directory.
Programmatic Use
Import m2r2.convert function and call it with markdown text.
Then it will return converted text.
from m2r2 import convert
rst = convert('# Title\n\nSentence.')
print(rst)
# Title
# =====
#
# Sentence.
Or, use parse_from_file function to load a markdown file and obtain converted text.
from m2r2 import parse_from_file
output = parse_from_file('markdown_file.md')
Upgrading to 1.0
The reusable converter class is named M2R2. Existing imports of M2R still
work through an alias. The convert and parse_from_file functions remain available.
Generated RST may use different spacing while preserving document content and structure. Standalone images keep block image directives. Images within text, headings, and table cells use substitutions so they can appear inline. RST cannot nest inline markup, so emphasis is applied to surrounding text while nested links and code retain their own formatting.
In Sphinx configuration, use m2r_no_underscore_emphasis instead of
no_underscore_emphasis. The old name still works with a deprecation warning.
Sphinx Integration
In your conf.py, add the following lines.
extensions = [
...,
'm2r2',
]
# source_suffix = '.rst'
source_suffix = ['.rst', '.md']
Write index.md and run make html.
When m2r2 extension is enabled on sphinx and .md file is loaded, m2r2 converts to rst and pass to sphinx, not making new .rst file.
mdinclude directive
Like .. include:: file directive, .. mdinclude:: file directive inserts markdown file at the line.
Note: do not use .. include:: file directive to include markdown file even if in the markdown file, please use .. mdinclude:: file instead.
Using mdinclude with another markdown parser
The m2r2 extension parses .md files, so Sphinx refuses to load it next to another extension that does the same, such as myst-parser. To keep the other parser for .md files and still use mdinclude, enable m2r2.mdinclude instead. It adds the mdinclude directive and the m2r_* config values, but no parser.
extensions = [
"myst_parser",
"m2r2.mdinclude",
]
Restrictions
- In the rst's directives, markdown is not available. Please write in rst.
- Column alignment of tables is not supported. (rst does not support this feature)
- Heading with overline-and-underline is not supported.
- Heading with underline is OK
- Rst heading marks are currently hard-coded and unchangeable.
- H1:
=, H2:-, H3:^, H4:~, H5:", H6:#
- H1:
If you find any bug or unexpected behaviour, please report it to Issues.
Example
See example document and its source code.
Contributing
See CONTRIBUTING.md for development setup and guidelines.
Acknowledgement
m2r2 is written as an extension of mistune, which is a highly extensible pure-python markdown parser. Without mistune, this project wouldn't exist. Thank you!
Licence
Release files for m2r2 1.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| m2r2-1.1.0.tar.gz | 146.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| m2r2-1.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size:166.6 kB
Release files / m2r2-1.1.0.tar.gz
| Download URL | m2r2-1.1.0.tar.gz |
|---|---|
| Size | 146.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
998534cc1b6d0542483c976a5387f2d7d2223361fb637ca1d1d733571d5e6db0
|
|
BLAKE2b-256 checksum How to use checksums |
535d130372b82e8cbc2b9fcb8882b7dd7edd36262a46ad3934e997f53a726b0f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Sep 18, 2026.
Transparency logRelease files / m2r2-1.1.0-py3-none-any.whl
| Download URL | m2r2-1.1.0-py3-none-any.whl |
|---|---|
| Size | 20.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1111dcd7a591795f38cb90ec07ed9cc14671299cd6ca535d3f3d8d3999fe65ba
|
|
BLAKE2b-256 checksum How to use checksums |
6ed0e74f47700023fe129446f966d5be532e553120fd2b5ce384f9691682d292
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Sep 18, 2026.
Transparency log