Skip to content

Instantly share code, notes, and snippets.

@goerz
Created August 5, 2019 19:26
Show Gist options
  • Save goerz/9be64b2a8d9a569d8586def1259685f0 to your computer and use it in GitHub Desktop.
Save goerz/9be64b2a8d9a569d8586def1259685f0 to your computer and use it in GitHub Desktop.
Sphinx plugin for inserting a warning on the "latest" version
"""Add a warning to the top of any documentation page for the "latest" version
on ReadTheDocs (RTD). Somewhat confusingly, "latest" is the latest development
version, not the latest release (which is stable).
Note that RTD has a builtin feature to show a similar warning on the
documentation of old releases. This can be enable in the Admin section on RTD,
under "Advanced Settings", "Show version warning"
"""
# This program is public domain
# Author: Michael Goerz
import os
import re
MSG = r'''
.. warning::
You are reading the documentation for an unreleased development version.
Consider the most recent `stable </en/stable/>`_ version.
'''
def split_metadata(rst):
"""Split Sphinx metadata from the rest of the rst body.
See https://www.sphinx-doc.org/en/1.5/markup/misc.html#file-wide-metadata.
"""
metadatalines = []
bodylines = []
region = 0 # 0: start of file, 1: in metadata, 2: in body
rx_field = re.compile(r'^:[\w\s]+:.*$')
for line in rst.splitlines():
if region == 0:
if line == '':
region = 1
metadatalines.append(line)
elif rx_field.match(line):
region = 1
metadatalines.append(line)
else:
region = 2
bodylines.append(line)
elif region == 1:
if line == '':
metadatalines.append(line)
elif rx_field.match(line): # another tag
metadatalines.append(line)
elif line.startswith(" "): # indented continuation
metadatalines.append(line)
else:
region = 2
bodylines.append(line)
elif region == 2:
bodylines.append(line)
else:
raise ValueError("Invalid region %s" % region)
bodylines.append('') # final newline
return "\n".join(metadatalines), "\n".join(bodylines)
def add_warning(rst):
"""Add a the warning MSG to the top of the given rst content."""
metadata, body = split_metadata(rst)
return metadata + MSG + body
def rewrite_rst(app, docname, source):
"""Rewrite Sphinx RST data to contain warning MSG."""
if app.env.doc2path(docname).endswith('rst'):
source[0] = add_warning(source[0])
def setup(app):
"""Initialize plugin."""
if os.environ.get('READTHEDOCS_VERSION', '') == 'latest':
app.connect('source-read', rewrite_rst)
###############################################################################
# TESTING
_TEST_RST = r'''
:autogenerated:
krotov.optimize module
======================
.. currentmodule:: krotov.optimize
.. automodule:: krotov.optimize
:members: optimize_pulses
:undoc-members:
:show-inheritance:
:member-order: bysource
Summary
-------
Functions:
.. autosummary::
:nosignatures:
optimize_pulses
``__all__``: :func:`optimize_pulses <krotov.optimize.optimize_pulses>`
Reference
---------
'''
_TEST_RST_EXPECTED = r'''
:autogenerated:
.. warning::
You are reading the documentation for an unreleased development version.
krotov.optimize module
======================
.. currentmodule:: krotov.optimize
.. automodule:: krotov.optimize
:members: optimize_pulses
:undoc-members:
:show-inheritance:
:member-order: bysource
Summary
-------
Functions:
.. autosummary::
:nosignatures:
optimize_pulses
``__all__``: :func:`optimize_pulses <krotov.optimize.optimize_pulses>`
Reference
---------
'''
def test_split_metadata():
"""Test split_metadata function."""
metadata, body = split_metadata(_TEST_RST)
assert metadata == '\n:autogenerated:\n'
assert body.startswith('krotov.optimize module\n======================')
assert body.endswith('Reference\n ---------\n')
def test_add_warning():
"""Test add_warning function."""
rst_with_warning = add_warning(_TEST_RST)
assert rst_with_warning == _TEST_RST_EXPECTED
if __name__ == "__main__":
test_split_metadata()
test_add_warning()
print("OK")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment