My rst README is not formatted on pypi.python.org

EDIT: You can use the following to find errors in your RST that will show up on PyPI:

twine check

You'll need twine version 1.12.0 or higher. If you don't have it you can install or update it using:

pip install --upgrade twine

Source


Deprecated answer:

python setup.py check --restructuredtext

Source


It turns out that the answer from @sigmavirus regarding the links was close. I started a discussion on the distutils mailing list and found out that in-page links (i.e. #minimum-cash) are not allowed by the pypi reStructuredText parser and will invalidate the entire document.

It seems that pypi uses a whitelist to filter link protocols (http vs ftp vs gopher), and sees '#' as an invalid protocol. It seems like this would be pretty easy to fix on their end, but until then, I'll be removing my in-page anchor links.


The first thing that pops out at me (after a quick scan) is that in your Advanced Filters section you use two underscores after a link, e.g.,

`Link text <http://example.com>`__

Where it should be

`Link text <http://example.com>`_

It's odd that the reStructuredText checkers didn't catch that. If you have docutils installed as well, you can run rst2html.py README.rst and it should print out the HTML. If there are errors it will fail and tell you where the errors were.

Also, fair warning, lists should have no leading spaces, i.e., you have

 - foo
 - bar

Instead of

- foo
- bar

(To make it more visually clear)

- foo # correct
 - one too many for a regular list, it will show up as a quoted list

Also, relative linking doesn't work like so Text to link <#link>_. If you want to link to a separate section you have to do the following:

Here's my `link <section_name>`_ to the other section.

.. Other stuff here ...

.. _section_name:

Min/Max Investment Opportunities and Other Foo Biz Baz
------------------------------------------------------

  • You may use collective.checkdocs package to detect invalid constructs:

    pip install collective.checkdocs python setup.py checkdocs

  • You may then use the following python function to filter-out sphinx-only constructs (it might be necessary to add more regexes, to match your content):

#!/usr/bin/python3
"""
Cleans-up Sphinx-only constructs (ie from README.rst),
so that *PyPi* can format it properly.

To check for remaining errors, install ``sphinx`` and run::

        python setup.py --long-description | sed -file 'this_file.sed' | rst2html.py  --halt=warning

"""

import re
import sys, io


def yield_sphinx_only_markup(lines):
    """
    :param file_inp:     a `filename` or ``sys.stdin``?
    :param file_out:     a `filename` or ``sys.stdout`?`

    """
    substs = [
        ## Selected Sphinx-only Roles.
        #
        (r':abbr:`([^`]+)`',        r'\1'),
        (r':ref:`([^`]+)`',         r'`\1`_'),
        (r':term:`([^`]+)`',        r'**\1**'),
        (r':dfn:`([^`]+)`',         r'**\1**'),
        (r':(samp|guilabel|menuselection):`([^`]+)`',        r'``\2``'),


        ## Sphinx-only roles:
        #        :foo:`bar`   --> foo(``bar``)
        #        :a:foo:`bar` XXX afoo(``bar``)
        #
        #(r'(:(\w+))?:(\w+):`([^`]*)`', r'\2\3(``\4``)'),
        (r':(\w+):`([^`]*)`', r'\1(``\2``)'),


        ## Sphinx-only Directives.
        #
        (r'\.\. doctest',           r'code-block'),
        (r'\.\. plot::',            r'.. '),
        (r'\.\. seealso',           r'info'),
        (r'\.\. glossary',          r'rubric'),
        (r'\.\. figure::',          r'.. '),


        ## Other
        #
        (r'\|version\|',              r'x.x.x'),
    ]

    regex_subs = [ (re.compile(regex, re.IGNORECASE), sub) for (regex, sub) in substs ]

    def clean_line(line):
        try:
            for (regex, sub) in regex_subs:
                line = regex.sub(sub, line)
        except Exception as ex:
            print("ERROR: %s, (line(%s)"%(regex, sub))
            raise ex

        return line

    for line in lines:
        yield clean_line(line)

and/or in your setup.py file, use something like this::

def read_text_lines(fname):
    with io.open(os.path.join(mydir, fname)) as fd:
        return fd.readlines()

readme_lines = read_text_lines('README.rst')
long_desc = ''.join(yield_sphinx_only_markup(readme_lines)),

Alternatively you can use the sed unix-utility with this file:

## Sed-file to clean-up README.rst from Sphinx-only constructs,
##   so that *PyPi* can format it properly.
##   To check for remaining errors, install ``sphinx`` and run:
##
##          sed -f "this_file.txt" README.rst | rst2html.py  --halt=warning
##

## Selected Sphinx-only Roles.
#
s/:abbr:`\([^`]*\)`/\1/gi
s/:ref:`\([^`]*\)`/`\1`_/gi
s/:term:`\([^`]*\)`/**\1**/gi
s/:dfn:`\([^`]*\)`/**\1**/gi
s/:\(samp\|guilabel\|menuselection\):`\([^`]*\)`/``\1``/gi


## Sphinx-only roles:
#        :foo:`bar` --> foo(``bar``)
#
s/:\([a-z]*\):`\([^`]*\)`/\1(``\2``)/gi


## Sphinx-only Directives.
#
s/\.\. +doctest/code-block/i
s/\.\. +plot/raw/i
s/\.\. +seealso/info/i
s/\.\. +glossary/rubric/i
s/\.\. +figure::/../i


## Other
#
s/|version|/x.x.x/gi