restructuredtext-lint
November 22, 2025 ยท View on GitHub
.. image:: https://github.com/twolfson/restructuredtext-lint/actions/workflows/test.yml/badge.svg :target: https://github.com/twolfson/restructuredtext-lint/actions/workflows/test.yml :alt: Build Status
reStructuredText_ linter_
This was created out of frustration with PyPI; it sucks finding out your reST is invalid after uploading it. It is being developed in junction with a Sublime Text_ linter.
.. _reStructuredText: http://docutils.sourceforge.net/rst.html
.. _linter: http://en.wikipedia.org/wiki/Lint_%28software%29
.. reST: reStructuredText
.. _PyPI: http://pypi.python.org/
.. _Sublime Text: http://sublimetext.com/
Getting Started
Install the module with: pip install restructuredtext_lint
.. code:: python
import restructuredtext_lint
errors = restructuredtext_lint.lint("""
Hello World
=======
""")
# `errors` will be list of system messages
# [<system_message: <paragraph...><literal_block...>>]
errors[0].message # Title underline too short.
CLI Utility
^^^^^^^^^^^
For your convenience, we present a CLI utility rst-lint (also available as restructuredtext-lint).
.. code:: console
$ rst-lint --help
usage: rst-lint [-h] [--version] [--format {text,json}]
[--level {debug,info,warning,error,severe}]
[--rst-prolog RST_PROLOG]
path [path ...]
Lint reStructuredText files. Returns 0 if all files pass linting, 1 for an
internal error, and 2 if linting failed.
positional arguments:
path File/folder to lint
optional arguments:
-h, --help show this help message and exit
--version show program's version number and exit
--format {text,json} Format of the output (default: "text")
--level {debug,info,warning,error,severe}
Minimum error level to report (default: "warning")
--rst-prolog RST_PROLOG
reStructuredText content to prepend to all files
(useful for substitutions)
$ rst-lint README.rst
WARNING README.rst:2 Title underline too short.
Other tools
^^^^^^^^^^^
restructuredtext-lint is also integrated in other tools. A list can be found and updated in our wiki
https://github.com/twolfson/restructuredtext-lint/wiki/Integration-in-other-tools
PyPI issues
^^^^^^^^^^^
While a document may lint cleanly locally, there can be issues when submitted it to PyPI_. Here are some common problems:
-
Usage of non-builtin lexers (e.g.
bibtex) will pass locally but not be recognized/parsable onPyPI_- This is due to
PyPI_ not having a non-builtin lexer installed - Please avoid non-builtin lexers to avoid complications
- For more information, see
#27_
- This is due to
-
Relative hyperlinks will not work (e.g.
./UNLICENSE)-
According to Stack Overflow, hyperlinks must use a scheme (e.g.
http,https) and that scheme must be whitelisted -
Please use absolute hyperlinks (e.g.
https://github.com/twolfson/restructuredtext-lint/blob/master/UNLICENSE)
-
.. _#27: https://github.com/twolfson/restructuredtext-lint/issues/27
Breaking changes in 2.0.0
We removed the --encoding CLI parameter and its correspodning keyword argument.
This was because not using "utf-8" by default was confusing and detracted from the purpose of our tool (#65_).
i.e. rst-lint's purpose is to check reST structural elements, not the content itself.
.. _#65: https://github.com/twolfson/restructuredtext-lint/issues/65
Documentation
restructuredtext-lint exposes a lint and lint_file function
restructuredtext_lint.lint(content, filepath=None, rst_prolog=None)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Lint reStructuredText_ and return errors
- content
String-reStructuredText_ to be linted - filepath
String- Optional path to file, this will be returned as the source - rst_prolog
String- Optional content to prepend to content, line numbers will be offset to ignore this
Returns:
-
errors
List- List of errors-
Each error is a class from
docutils_ with the following attrs-
line
Integer|None- Line where the error occurred- On rare occasions, this will be
None(e.g. anonymous link mismatch)
- On rare occasions, this will be
-
source
String-filepathprovided in parameters -
level
Integer- Level of the warning- Levels represent 'info': 1, 'warning': 2, 'error': 3, 'severe': 4
-
type
String- Noun describing the error level- Levels can be 'INFO', 'WARNING', 'ERROR', or 'SEVERE'
-
message
String- Error message -
full_message
String- Error message and source lines where the error occurred
-
-
It should be noted that
level,type,message, andfull_messageare custom attrs added onto the originalsystem_message
-
.. _docutils: http://docutils.sourceforge.net/
restructuredtext_lint.lint_file(filepath, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Lint a reStructuredText_ file and return errors
- filepath
String- Path to file for linting *args- Additional arguments to be passed tolint**kwargs- Additional keyword arguments to be passed tolint
Returns: Same structure as restructuredtext_lint.lint
Extension
Under the hood, we leverage docutils_ for parsing reStructuredText documents. docutils_ supports adding new directives and roles via register_directive and register_role.
Sphinx
^^^^^^
Unfortunately due to customizations in Sphinx's parser_ we cannot include all of its directives/roles (see #29). However, we can include some of them as one-offs. Here is an example of adding a directive from Sphinx.
.. _Sphinx: http://sphinx-doc.org/
.. Sphinx's parser: Sphinx
.. _#29: https://github.com/twolfson/restructuredtext-lint/issues/29#issuecomment-243456787
https://github.com/sphinx-doc/sphinx/blob/1.3/sphinx/directives/code.py
sphinx.rst
.. code:: rst
Hello
=====
World
.. highlight:: python
Hello World!
sphinx.py
.. code:: python
# Load in our dependencies
from docutils.parsers.rst.directives import register_directive
from sphinx.directives.code import Highlight
import restructuredtext_lint
# Load our new directive
register_directive('highlight', Highlight)
# Lint our README
errors = restructuredtext_lint.lint_file('docs/sphinx/README.rst')
print errors[0].message # Error in "highlight" directive: no content permitted.
Examples
Here is an example of all invalid properties
.. code:: python
rst = """
Some content.
Hello World
=======
Some more content!
"""
errors = restructuredtext_lint.lint(rst, 'myfile.py')
errors[0].line # 5
errors[0].source # myfile.py
errors[0].level # 2
errors[0].type # WARNING
errors[0].message # Title underline too short.
errors[0].full_message # Title underline too short.
#
# Hello World
# =======
Contributing
In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality.
Testing
Testing can be performed locally via:
.. code:: bash
# Configure local `rst-lint` to use run from this package
python setup.py develop
# Install development dependencies
pip install -r requirements-dev.txt
# Run our test suite
./test.sh
Donating
Support this project and others by twolfson_ via donations_.
http://twolfson.com/support-me
.. _others by twolfson: http://twolfson.com/projects
.. _donations: http://twolfson.com/support-me
Unlicense
As of Nov 22 2013, Todd Wolfson has released this repository and its contents to the public domain.
It has been released under the UNLICENSE_.
.. _UNLICENSE: https://github.com/twolfson/restructuredtext-lint/blob/master/UNLICENSE