53

I would like to include my project's README.md into my Sphinx documentation like in Can sphinx link to documents that are not located in directories below the root document? - which is that in the resulting Sphinx html documentation I click on a link in the table of contents on the welcome page and get to the README.md.

For that a document readme_link.rst is created which contains the lines

Readme File
-----------

.. include:: ../../README.md

and I add the line

README <readme_link>

into the toctree of index.rst. Going with that, my README.md is not parsed as Markdown, but just printed onto the page as-is-text.

I thought an alternative idea might be to have a markdown file readme_link.md instead, but there is no way to include files with markdown.

How can I have my README.md parsed as markdown?

(Of course I don't want to rewrite it as .rst.)

Why m2r is not working

I tried to follow Render output from markdown file inside .rst file, but this is not working. My README.md has some headings like

# First heading

some text

## Second heading 1

some text

## Second heading 2

some text

and I get the error WARNING: ../README.md:48: (SEVERE/4) Title level inconsistent:. I understand from What does "Title level inconsistent" mean? that I need to use other symbols - but reading into them I realized that the answer refers to rst symbols. That would mean that my markdown readme actually wasn't transformed into rst.

PS: Someone else who tried something like that is https://muffinresearch.co.uk/selectively-including-parts-readme-rst-in-your-docs/

Shon
  • 3,989
  • 1
  • 22
  • 35
Make42
  • 12,236
  • 24
  • 79
  • 155
  • @Waylan: This is not working, see updated question. – Make42 Sep 18 '17 at 15:25
  • IIRC, the check for consistent headings is done when creating the Docutils document object (after parsing has already happened). The document object insists on having consistent header levels and the error message simply assumes the source was `rst`. If you are using Docutils (which Sphinx is built on top of), you absolutely **must** have consistent header levels. It does not matter what markup language you are using. – Waylan Sep 18 '17 at 15:48
  • As a test, I would suggest changing `readme_link.rst` to a markdown file (After all, M2R adds the `minclude` directive to the Markdown parser) and see what happens then. I suspect you may get the same error message. – Waylan Sep 18 '17 at 15:52
  • Finally, as discussed in the comments to the linked question, it is not possible to `include` Markdown file into a `rst` file unless you have some non-standard modification. M2R is the only such modification that I am aware of. Therefore this is still a duplicate and there is no different answer here than exists there. – Waylan Sep 18 '17 at 15:57
  • @Waylan: I am not quite sure what you are suggesting that I should do. I included m2r. My headings are consistent from for a markdown document. As far as I understand it is not possible to `include` another document into a markdown file. – Make42 Sep 18 '17 at 16:09
  • According to the docs, you can use `minclude` from a Markdown file. In the feature list it states: "`mdinclude` directive to include markdown from **md** or rst files" (emphasis added). – Waylan Sep 18 '17 at 17:08
  • The docs also state" When `m2r` extension is enabled on sphinx and `.md` file is loaded, m2r converts to rst and pass to sphinx." So the Markdown headers are first converted to `rst` headers. However, in `rst` there is no given character for any specific level. So if the `h1` header in the converted-from-md `rst` uses a different char than in the parent `rst`, you will get an error. The headers in your parent file need to match the scheme used by M2R. – Waylan Sep 18 '17 at 17:27
  • Just checked the source code for M2R and the headers are defined [here](https://github.com/miyakogi/m2r/blob/master/m2r.py#L177-L184). Level 1 uses `=`. Edit your `readme_link.rst` to use `=` instead of `-` for the header, and you will no longer get that error. – Waylan Sep 18 '17 at 18:27
  • @Waylan: That worked! Can you explain why? I get that the highest level in rest is `=` and not `-`. Was is that `-` was the 2nd level and with `#`, my first header in the readme was above `-` and that gave the conflict? (If you like to write your comments down into an answer, I could except it.) – Make42 Sep 18 '17 at 18:52
  • 1
    Simplest solution as of 2021: https://stackoverflow.com/a/68005314/119775 – Jean-François Corbett Jun 16 '21 at 15:04

7 Answers7

35

You need to edit your readme_link.rst as follows:

Readme File
===========

.. mdinclude:: ../../README.md

Note that the section header is designated with = characters rather than - characters.

There are two factors that contribute to that.

How include works

Standard include (not mdinclude) actually reads the content of the source file and simply copies the raw text in place of the directive. M2R's mdinclude first converts the source Markdown text to rst, and then, like include, copies that test in place of the directive.

Therefore, by the time the rst document is parsed, you have one complete rst document from both the parent and included files. That one complete document needs to be a valid rst document, which takes us to the second point...

Header levels must be consistent.

As a reminder, the reStructuredText Spec explains:

Rather than imposing a fixed number and order of section title adornment styles, the order enforced will be the order as encountered. The first style encountered will be an outermost title (like HTML H1), the second style will be a subtitle, the third will be a subsubtitle, and so on.

...

All section title styles need not be used, nor need any specific section title style be used. However, a document must be consistent in its use of section titles: once a hierarchy of title styles is established, sections must use that hierarchy.

Therefore, the header levels in the included child must be consistent with the header levels in the parent. As M2R generates a rst document, you (as the end user) don't get to specificity which character is used to define each section level. Therefore, to maintain consistency, you need to use the scheme defined by M2R:

  • Rst heading marks are currently hard-coded and unchangeable.
    • H1: =, H2: -, H3: ^, H4: ~, H5: ", H6: #

As you can see, level 1 headers use the = character and level 2 headers use the - character. Therefore, the same scheme needs to be used in the parent readme_link.rst file (you were using the reverse).

An alternate solution

The reStructuredText spec also states:

Underline-only adornment styles are distinct from overline-and-underline styles that use the same character.

Therefore, you could use overline-and-underline styles in your parent document and it wouldn't matter which characters you used for which level as M2R only appears to use underline-only styles. So this would have worked as well:

-----------
Readme File
-----------

.. mdinclude:: ../../README.md

This has the added benefit (or negative -- depending on your point of view) that all headers in the included child document will now be one level lower that they would on their own. Therefore, the child is more semantically "nested" in the parent (more than one h1 in a single HTML document is often considered to not be semantic although it is technically "valid"). Of course, this may or may not be what you want, which is why it is labeled an "alternate solution".

Waylan
  • 37,164
  • 12
  • 83
  • 109
  • 11
    `mdinclude` is no longer supported – pjk Nov 19 '20 at 10:44
  • @pjk do you have a source for that claim? It is still mentioned in the [docs](https://github.com/miyakogi/m2r#mdinclude-directive) for M2R. – Waylan Nov 20 '20 at 14:02
  • based on https://github.com/sphinx-doc/sphinx/issues/7420#issuecomment-609814898 and https://github.com/sparkfun/Qwiic_Template_Py/issues/1 . m2r2 seems to work for me. couldn't get m2r to get my work done. – pjk Nov 23 '20 at 07:23
  • 2
    Ah, I see, it hasn't been updated to work with Sphinx 3. It appears that [m2r2](https://github.com/CrossNox/m2r2) is an updated fork which does work with Sphinx 3. – Waylan Nov 23 '20 at 13:46
  • m2r2 isn't able to import images from `README`. Any hints why it can be so ? – Vineet Aug 03 '21 at 05:04
30

UPDATE: It sounds like https://stackoverflow.com/a/68005314/1187277 is now the recommended solution.


There is an alternative approach, if you only want to include a markdown document in your project as a separate file (and don't need to embed the contents of that file into an .rst file):

1. Ensure you have the necessary prerequisites

(These steps are also requisite for the accepted answer.)

1.1 Ensure you have the markdown renderer installed:

$ pip install -U sphinx>=1.8.3 recommonmark>=0.5.0

1.2 Add recommonmark to the list of extensions in conf.py

See the documentation for canonical instructions on this.

1.3 Make a symlink to your markdown file

$ cd docs             # or docs/source
$ ln -s ../README.md  # or to ../../README.md if using docs/source

2. Include the required markdown file in your docs

Link the file in your toctree:

.. toctree::
   :maxdepth: 2
   :caption: Contents:

   source/README.md
Shon
  • 3,989
  • 1
  • 22
  • 35
  • 5
    I think linking might be problematic for version control. Is there a way to directly use relatively path? I tried ../README.md . But Sphinix couldn't find it. – J_yang Jul 04 '20 at 10:30
  • 1
    For step 1.2, would you please show exactly how to add recommonmark to the list of extensions in conf.py? – chrisinmtown Sep 10 '20 at 19:30
  • @chrisinmtown I added a link to the relevant section of the documentation. I don't want to "hardcode" in the configuration here, lest the answer become stale when they change something. – Shon Sep 11 '20 at 22:51
  • 1
    Anything can change at anytime :) this kind of hint would have really helped: `extensions = [ 'recommonmark' ]` – chrisinmtown Sep 12 '20 at 10:24
  • Do you think that now, with the official documentation just a click away, future readers in your position will be adequately guided? – Shon Sep 14 '20 at 00:58
  • No need for recommandmark anymore, it is outdated. Use [myst-parser](https://stackoverflow.com/a/68005314/119775) instead. – Cunningham Sep 14 '22 at 08:29
  • 1
    Thanks for the info @Cunningham. I don't have occasion to use sphinx these days. If you know the correct changes to update the answer, and edit would be appreciated :) -- or maybe a new answer that supersedes this one? – Shon Sep 17 '22 at 00:49
  • @Shon, yes of course. The solution has been mensionned by Jean-François Corbett in a comment of the first post: Simplest solution as of 2021: [stackoverflow.com/a/68005314/119775](https://stackoverflow.com/questions/46278683/include-my-markdown-readme-into-sphinx/68005314#68005314) – Cunningham Oct 09 '22 at 14:56
25

I've installed myst-parser extension and tried to include a Markdown file into a .rst file

.. include:: README.md

It is not being parsed. Added :parser: markdown option, but docutils complains that "recommonmark" extension is not installed. I've found a way to include parsed md file:

.. include:: README.md
   :parser: myst_parser.sphinx_
menesis
  • 371
  • 3
  • 4
  • 2
    `:parser: myst_parser.sphinx_` was key for me. Parsing was not working until I added it. – jmcker Oct 15 '21 at 22:03
  • I was having an issue with this where it was complaining that `unknown option: "parser".`. Turns out I had a version of `docuitils` prior to 0.17 and upgrading it solved the problem. – Sam Martin Nov 30 '21 at 19:09
  • 1
    This solution is now in the documentation :) https://myst-parser.readthedocs.io/en/latest/sphinx/use.html#include-markdown-files-into-an-rst-file – Chris Sewell Dec 16 '21 at 16:30
  • This is the cleanest solution to include any markdown file in you rst files and combine both syntaxes easily. – CharlesG Apr 01 '22 at 09:58
  • Thank you -- much cleaner solution than adding another dependency (m2r2) – n8henrie Jun 22 '22 at 13:42
  • Great solution, I jsut struggle to use the experimental option to change the link relative. What should you include ? – MCMZL Aug 12 '22 at 15:06
13

The simplest way is to use MyST-Parser, which happens to be the extension now recommended in Sphinx docs for handling Markdown. No need for m2r.

MyST-Parser allows reStructuredText-style directives to be embedded in Markdown files. We'll use that feature to include your Markdown README.md into a placeholder Markdown file that will then get rendered to HTML.

In conf.py:

extensions = [
    # ...
    "myst_parser"
]

Your readme_link file should then be in Markdown format instead of reStructuredText i.e. create a readme_link.md file containing an include directive:

```{include} ../../README.md
```

This directive simply dumps the contents of README.md into readme_link.md which is itself in Markdown, so there's no need to do any conversion to reStructuredText at this point. readme_link.md will get rendered into HTML along with all other source files thanks to the myst_parser extension.

Jean-François Corbett
  • 37,420
  • 30
  • 139
  • 188
9

If you also come across the error TypeError: add_source_parser(), here is the solution:

Using m2r2 instead of m2r. That is,

in the file readme_link.rst, we write

.. mdinclude:: ../README.md

and in the file conf.py we add

extensions = [
    # ...
    'm2r2'
]
# ...

# source_suffix = '.rst'
source_suffix = ['.rst', '.md']
bowen
  • 91
  • 1
  • 1
2
  1. Link your README.md form project root to the directory that your conf.py exists .
    ln -s {path to your README.md} {path to the dir that conf.py is in}

  2. install the myst-parser package:
    pip install myst-parser

  3. include the myst-parser in your conf.py file.

extensions = [
    "myst_parser",  # be carefull to use `_` and not `-`
]
  1. create a .rst file (lets call it include_readme.rst for now) and paste the following block in it:
.. include:: CHANGELOG.md
   :parser: myst_parser.sphinx_
  1. add the include_readme.rst to your index.rst file. your index.rst might look like this:

Welcome to documentation!
======================================

.. toctree::
   :maxdepth: 2
   :caption: Contents:

   ...
   include_readme.  # this is a `.rst` file but u can exclude the `.rst` suffix here
   ...
Amir nazary
  • 384
  • 1
  • 7
1

A rather simplictic solution like

.. literalinclude:: ../README.md

might do the trick for you.

This will not parse the .md file but instead display it as a literal code block.

Depending on your situation that might be an acceptable solution. Good thing is that this does not require (potentially unmaintained) extensions, works on Windows which does not support symlinks, allows you to put the content of the README into an existing .rst file, and does not conflict with the .rst headers. The obvious downside is that no parsing is happening.

apitsch
  • 1,532
  • 14
  • 31