Section author: Mike Fitzpatrick <mike.fitzpatrick@noirlab.edu>
3.7. ReStructuredText Style Guide¶
This page describes how reStructuredText (reST) is written for Data Lab documentation through examples. The last section of this page documents our formatting conventions.
It is adopted from the style guide in the Rubin/LSST DM Developer Guide and licensed under a Creative Commons Attribution 4.0 International License.
For more general guides to writing reStructuredText, see Sphinx’s reStructuredText Primer and the docutils Quick reStructuredText guide.
3.7.1. Sample¶
.. index::
pair: ReStructuredText; sample
.. _sec_ReStructuredTextSample:
#######################
ReStructuredText Sample
#######################
ReStructuredText is an *extensible* markup language used by Astro Data Lab.
.. _DataLab: https://datalab.noirlab.edu
ReStructuredText provides basic *italic*, **bold** and ``monospaced``
typesetting. There is also the concept of **roles** that provide sophisticated
typesetting, such as :math:`\mu = -2.5 \log_{10}(\mathrm{DN} / A) + m_0`, and
:ref:`referencing <rst-internal-links>`.
.. _label-for-subsection-label:
Sectioning
==========
Sections are formed with underlining the headline text. We use :ref:`a
conventional sequence of underline symbols <rst-sectioning>` to indicate
different levels of hierarchy.
Directives
==========
Besides **roles** that are used for inline markup, reStructuredText has the
concept of **directives** to markup *blocks* of content. One example is
the ``code-block`` directive:
.. code-block:: python
print('hello world!')
3.7.2. Inline Text Styling¶
- Italics
*italic text*
→ italic text.- Bold
**bold text**
→ bold text.- Monospace
``monospace text``
→monospace text
. When referring to code objects, it’s better to use markup that links to the object’s API documentation (see the Links to code objects section).- Inline math
:math:`\sqrt{16}`
→ \(\sqrt{16}\) (See also the Math section).
Note
Inline styles can’t be nested
For example, you can’t write *see :ref:`this page <label>`*
.
Inline markup also needs to be surrounded by white space, though trailing punctuation is fine.
You can get around this with an escaped space that is otherwise invisible,
For example one\ *word*
renders as oneword.
3.7.2.1. Other semantic markup¶
In addition to the fundamental inline typesetting styles above, you may use additional reST roles to provide semantic meaning to the text. The documentation’s CSS takes advantage of this semantic meaning to provide visual cues to readers.
- Abbreviations
:abbr:`DL (Data Lab)`
→ DL (a tool tip exposes the definition)- Filenames and paths
:file:`repos.yaml`
→repos.yaml
- Shell commands
:command:`git rebase -i master`
→ git rebase -i master
- User interface labels
:guilabel:`New Pull Request`
→ New Pull Request. This markup can be used for button labels, menus, or even text labels in interactive shell programs.- Keyboard commands
:kbd:`Control-a s`
→ Control-a s. Spell out the keys rather than using Emacs short hand, such asC-x
.
To semantically markup Python code objects, refer to the section on Links to code objects.
3.7.3. Lists¶
Unordered lists can be written as:
- First item
Second paragraph for first item, needs to be consistently indented.
- Second item
- You can put spaces between items, or not.
- Hierarchical lists are also possible
- Put a blank space before the sub-list
- And indent the sub-list consistently
- Last item.
which renders as:
First item
Second paragraph for first item, needs to be consistently indented.
Second item
You can put spaces between items, or not.
Hierarchical lists are also possible
Put a blank space before the sub-list
And indent the sub-list consistently
Last item.
There should be a blank line before and after the list to separate the list from paragraphs. Blanks lines are allowed between list items as well.
Enumerated lists can be written similarly:
1. First thing
2. Second thing
or automatically enumerated,
#. First thing
#. Second thing
which renders as:
First thing
Second thing
or automatically enumerated,
First thing
Second thing
3.7.3.1. Definition lists¶
Definition lists are terms with an indented content section. For example:
DL
Data Lab
produces
- DL
Data Lab
Definition lists are not limited to dictionary-like usage; they can be employed whenever a series of terms with associated micro content is needed.
3.7.4. Sections¶
We create section hierarchies as follows:
.. _sec_PageTitleExample:
##################
Page Title Example
##################
Titles have hash marks above and below.
By convention, titles and section headings are set off from surrounding text by
a single blank line above and below. All levels of section headings may have
named labels, which appear before the heading. We encourage you to add labels
to all sections so that they can be referenced. Names are global, so be
specific. See :ref:`Internal Links to Labels <rst-internal-links>` for
more information. The following section heading has a label named
"``section-headings-example-section``".
.. _section-headings-example-section:
Section Heading
===============
Section headers are set with an underline. The sequence of underline characters
used (``=``, then ``-``, then ``^`` and finally ``"``) indicates the section
hierarchy.
.. _section-headings-example-subsection:
Subsection Heading
------------------
Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit.
Donec et mollis dolor.
.. _section-headings-example-subsubsection:
Sub-subsection Heading
^^^^^^^^^^^^^^^^^^^^^^
Praesent et diam eget libero egestas mattis sit amet vitae augue.
.. _section-headings-example-subsubsubsection:
Sub-sub-subsection Heading
""""""""""""""""""""""""""
Nam tincidunt congue enim, ut porta lorem lacinia consectetur.
Sections in Python docstrings are a special case. We do not put a blank space
between a headline and object lists below, and we do not add explicit section
labels. See the :ref:`docstring style guide <sec_DocumentingPythonAPIswithDocstrings>` for more information.
This specific sequence of section markup styles is not mandated by the reST specification, but we encourage you to use it for consistency across all reST documents.
Sections in Python docstrings are a special case. First, we do not place a blank space between a section header and the object lists below. Second, Python docstrings can only use subsection and subsubsection-level headings.
3.7.5. Linking¶
3.7.5.1. External links¶
Links to external web pages can be made two ways. The first way is:
When writing Python, it's a good idea to use the `PEP8 style guide`_.
.. _PEP8 style guide: https://www.python.org/dev/peps/pep-0008/
The link reference should be provided directly following the paragraph to make it easier for editors to ensure the text in backticks matches the link reference line. Despite this fragility, this style is good since it makes the reST itself more readable.
The second method is to put the URL inline:
When writing Python, it's a good idea to use the
`PEP8 style guide <https://www.python.org/dev/peps/pep-0008/>`_.
You may decide to use either method, taking readability into consideration.
3.7.5.2. Internal links to labels¶
Any content block can be labeled.
For example, to give a section the label making-labels
, we write:
.. _making-labels:
Making Labels
-------------
Labels are an empty directive that appear directly before any block, such
as a section, image, table, or code block.
Labels start with an underscore, and words in labels are separated by
hyphens.
Labels are a **global namespace**, so make them as specific as possible.
With the :ref:
role you can link to a labeled block:
For internal links, :ref:`you'll need to make labels <making-labels>`.
You can also make references with :ref:`label-name`
and the link text
will automatically be populated with the section title or figure caption,
for example.
Remember that labels are global across a Sphinx documentation project. With labels, you can link to sections in other pages.
3.7.5.3. Internal links to other pages¶
To link to another page in the same doc project, use the :doc:
role with
the relative path to the target .rst
document.
See our :doc:`Style guide <sec_ReStructuredTextStyleGuide>` to learn how to write reST docs.
Note how the .rst
extension wasn’t included.
3.7.5.4. Links to equations¶
Equations can be linked to using a :ref:
to their label, as described
above. If the equation with numbered by adding a :label:
field to the
math directive itself then that equation can be reference with the :eq:
role. See Referencing equations for more information.
3.7.5.5. Links to code objects¶
When describing a code object, you can also link to that object’s API
definition using a syntax similar to the :ref:
role used above.
3.7.5.5.1. Links to Python objects¶
Objects can be referenced with these roles:
:py:mod:`package.module`
references a module or package with namespacepackage.module
.:py:func:`pkg.mod.function`
references a Python function at namespacepkg.mod.function
. The role’s text does not need to include trailing parentheses.:py:class:`pkg.mod.Class`
to reference a classClass
inpkg.mod
.:py:meth:`pkg.mod.Class.method`
to reference a methodmethod
in classClass
inpkg.mod
.:py:attr:`pkg.mod.Class.attribute`
to reference an attributeattribute
in classClass
inpkg.mod
.:py:data:`pkg.mod.VARIABLE`
to reference a module-level variableVARIABLE
inpkg.mod
.:py:const:`pkg.mod.CONSTANT`
to reference a module-level constantCONSTANT
inpkg.mod
.
3.7.5.5.1.1. Namespace resolution¶
In these examples, the full namespace of each Python object is specified. In some contexts, Sphinx may be able to identify the reference object without the full namespace. For example in class docstrings, references to methods or attributes in the same class can be made by name alone. See the Sphinx documentation for more details on object resolution.
3.7.5.5.2. Customizing the link text¶
By default the full namespace to the object is shown as the linked text.
To show only the name of the object itself, prefix the namespace with ~
.
For example:
:py:func:`~numpy.sin`
will be rendered as sin().
As with the :ref:
role, it is also possible to provide custom link text.
For example:
:py:func:`Numpy's sine function <numpy.sin>`
3.7.5.5.3. Default domains¶
By default, these code referencing roles require a domain prefix such as
py
or cpp
to specify the language of the object being reference.
This prefix can be omitted when the domain is implicitly set, such as in a
Python docstring.
In a reStructuredText document, the domain can be set via the
default-domain
directive. For example, to set the default domain for a
reST document to Python, use
.. default-domain:: py
When this is set, Python code references can be made more concise, e.g.,
:func:`numpy.sin`
.
See Sphinx’s documentation on Domains for more information about referencing code objects.
3.7.6. Tables¶
We recommend that you use the grid syntax for tables, since they more
flexible than ‘simple’ reST tables. And although not necessary, we suggest
that you provide a caption using the table
directive and a label prefixed
with “table-
.” For example:
.. _table-label:
.. table:: Table caption.
+------------------------+------------+----------+----------+
| Header row, column 1 | Header 2 | Header 3 | Header 4 |
| (header rows optional) | | | |
+========================+============+==========+==========+
| body row 1, column 1 | column 2 | column 3 | column 4 |
| | with many | spans | |
| | rows | both | |
+------------------------+------------+ rows +----------+
| body row 2 | ... | | ... |
+------------------------+------------+----------+----------+
produces:
Header row, column 1 (header rows optional)
Header 2
Header 3
Header 4
body row 1, column 1
column 2 with many rows
column 3 spans both rows
column 4
body row 2
…
…
Note how cells can be joined by omitting the dividing line.
The =
characters divide the header from table content.
Text in the header is set in bold.
You can write tables with multiple header rows, including spans across header cells:
.. _rst-table-multi-header-example:
.. table:: Table with two header rows, including a span.
+----------------+
| Position |
+-------+--------+
| Ra | Dec |
+=======+========+
| 0.0 | 0.21 |
+-------+--------+
| 0.0 | 2.34 |
+-------+--------+
produces:
Position
Ra
Dec
0.0
0.21
0.0
2.34
In the simplest cases, tables are not required to have headers, or even be
inside a table
directive.
+-----------+--------------+
| us-east-1 | ami-e2490b88 |
+-----------+--------------+
| us-west-2 | ami-9a0f1dfb |
+-----------+--------------+
produces:
us-east-1 |
ami-e2490b88 |
us-west-2 |
ami-9a0f1dfb |
Be sure to leave a blank line before and after the table
directive.
3.7.7. Images and Figures¶
3.7.7.1. Plain images¶
Plain images can be included with the image
directive.
For example:
.. image:: /_static/devguide/docs/Data-Lab-Logo.png
:target: ../_images/Data-Lab-Logo.png
:alt: Data Lab Logo
This example shows how an image can by hyperlinked to any URL with the
target
field. Internal links, as in the example, must be relative to
the reST document; Sphinx does not process URLs in an image
‘s
target
field.
The image
directive has
more configurable fields.
If image sizes need to be manipulated from reST, we recommend using scale
since it is responsive. We hope to provide better support for responsive
image sizing.
Be sure to leave a blank line before and after the image
directive.
3.7.7.2. Figure directive¶
Figures include both an image and a caption. For example:
.. figure:: /_static/devguide/docs/Data-Lab-Logo.png
:name: fig-example-figure-label-rst
:target: ../_images/Data-Lab-Logo.png
:alt: Data Lab Logo
Data Lab Logo.
Note that the :name:
field takes the place of a separate
label for hyperlinking.
By convention, these labels should be prefixed with “fig-
.”
Be sure to leave a blank line before and after the figure
directive.
3.7.7.3. Note on paths to image files¶
Images are included in the _static/
directory of the git repository for
this documentation project. Sphinx requires image assets to be located in
this _static/
directory in order to properly copy files into the built
website. By using a prefix “/
” we indicate that a path is relative to
the root of the documentation repository.
Package documentation is hosted in doc/
directories of the git
repositories of individual packages. For such package documentation,
image files should be placed inside a directory in doc/_static/
named
for the package itself. This nested directory structure is needed to merge
package documentation content into the root documentation build.
3.7.8. Math¶
Sphinx allows you to write math expressions with a LaTeX-like plain text syntax that will be typeset by MathJax in the browser. MathJax supports AMSMath-LaTeX syntax. This website by Dr Carol Burns provides a comprehensive listing of available LaTeX syntax in MathJax, along with examples.
In Sphinx, you can either write inline expressions with the math
role,
or block elements with the math
directive.
3.7.8.1. Inline math¶
Write inline math expressions with the math
role.
For example, :math:`\sigma_\mathrm{mean} = \sigma / \sqrt{N}`
produces
\(\sigma_\mathrm{mean} = \sigma / \sqrt{N}\).
3.7.8.2. Block math¶
To display math as a block element, use the math
directive (be sure to
leave a blank line before and after the math
directive). For example:
.. math:: \sigma_\mathrm{mean} = \frac{\sigma}{\sqrt{N}}
:label: math-sample-rst
renders as
3.7.8.2.1. Referencing equations¶
Notice the :label:
field in the previous sample; it both annotates the
equation with a number, and allows the equation to be cross-referenced with
the eq
role; for example “:eq:`math-sample-rst`” produces
(1). Equation references may only be made within the same
reStructuredText page as the original math
directive. See
the Sphinx docs on Math support for more information.
3.7.8.2.2. Multiple Equations¶
Multiple equations can appear in the same math
directive.
Simply include a blank line between each equation (and don’t include an
equation as a argument of the math
directive itself).
For example:
.. math::
\nabla \cdot \mathbf{E} = \frac{\rho}{\epsilon_0}
\nabla \cdot \mathbf{B} = 0
renders as
3.7.8.2.3. Aligned Equations¶
Often when there are multiple statements in a math
directive it’s
desirable to align those statements around the equals sign, for example.
In AMSMath-LaTeX this would be achieved with the align
environment.
In reStructuredText we can accomplish the same in a math
directive:
.. math::
x &= (a + b)^2 \\
&= a^2 + 2ab + b^2
renders as
Notice how the alignment point is marked with an &
and \\
is appended
to each math statement except for the last. Also note how there are no
blank lines between math statements.
3.7.9. Source code¶
For blocks of code, we prefer the code-block
directive.
This directive has the form
.. code-block:: <language>
:name: optional-label
:emphasize-lines: <optional lines to highlight>
<code>
where
<language>
can be any token understood by Pygments, particularlypy
(python),cpp
(C++),java
(Java),js
(JavaScript) andrst
(reStructuredText). Specifynone
to disable highlighting.:name:
is an explicit hyperlink label for the code block.:emphasize-lines:
is an optional sequence of lines to highlight. This can be comma-separated, with hyphens to indicate spans.
For example:
.. code-block:: py
:name: context-timer-example
:emphasize-lines: 4-13,15-17
from contextlib import ContextDecorator
import time
class timercontext(ContextDecorator):
def __enter__(self):
self.start = time.clock()
return self
def __exit__(self, *args):
self.end = time.clock()
self.interval = self.end - self.start
print('Duration: {0:.2e} sec'.format(self.interval))
@timercontext
def run_slowly():
time.delay(1.)
run_slowly()
with timercontext() as t:
time.delay(1)
print('Delayed for {0:.1f}'.format(t.interval))
produces
from contextlib import ContextDecorator
import time
class timercontext(ContextDecorator):
def __enter__(self):
self.start = time.clock()
return self
def __exit__(self, *args):
self.end = time.clock()
self.interval = self.end - self.start
print('Duration: {0:.2e} sec'.format(self.interval))
@timercontext
def run_slowly():
time.delay(1.)
run_slowly()
with timercontext() as t:
time.delay(1)
print('Delayed for {0:.1f}'.format(t.interval))
Be sure to leave a blank line before and after the code-block
directive.
3.7.9.1. Including source code examples from other files with literalinclude¶
The code-block
directive is great for code examples written in the
reStructuredText source file itself. You might also want to show a code
sample contained in a separate file. For this you can use the
literalinclude
directive:
.. literalinclude:: path/to/example.py
:language: py
The source path can either be relative to the reST document or relative to
the documentation root by prefixing the path with /
.
The literalinclude
directive also supports code-block
fields, such
as name
and emphasize-lines
. In addition, you can selective
include ranges of lines with the lines
field. For example, to include
only lines 10 – 20:
.. literalinclude:: path/to/example.py
:language: py
:lines: 10-20
To omit the first two lines from a file:
.. literalinclude:: path/to/example.py
:language: py
:lines: 2-
Sophisticated inclusion patterns can be achieved by listing multiple spans,
such as :lines: 3-10,20-
, which shows the first ten lines and all lines
after the 20th.
When including code example snippets from other files, it may be useful to
remove indentation. Use the dedent
field for that.
For example:
.. literalinclude:: path/to/example.py
:language: py
:lines: 5-10
:dedent: 4
will show lines 5 – 10 and remove 4 space characters (presumably because the snippet is inside a Python class or function).
3.7.9.2. Lightweight syntax for Python code and sessions¶
You can markup Python code blocks using a lightweight syntax:
::
print('hello world!')
Interactive python sections can be marked up as
>>> print('Hello world!')
Hello world!
This lightweight syntax is used in Python docstrings.
3.7.10. Command line prompts¶
For generic command line prompts, we use the sphinx-prompt extension
so that the prompt character (e.g, $
) isn’t selectable. This is great
for giving copy-and-paste-ready command line instructions.
For basic bash prompts,
.. code-block:: shell
mkdir -p hello/world
cd hello/world
produces
mkdir -p hello/world
cd hello/world
3.7.11. Footnotes¶
Footnotes should be used sparingly, if at all, in documentation. Prefer inline hyperlinks to other sections. If you do need footnotes, you can make them as follows:
This is a line.\ [#label]_
.. [#label] This is the footnote content.
Note that we had to provide an escaped space for the footnote mark occurring after a period.
The footnote content should occur not far from the inline footnote mark; generally provide the footnote content at the end of the section.
3.7.12. Citations¶
Citations should be used for scholarly references; use hyperlinks for web native content. Citations can be made as follows:
The LSST Project [Ivezic2008]_ will produce 15 TB of images per night.
.. [Ivezic2008] Ivezic et al 2008. *LSST: from Science Drivers to
Reference Design and Anticipated Data Products.*
`arxiv:0805.2366 <http://arxiv.org/abs/0805.2366>`_
Citations are distinguished from footnotes in that the label does not
begin with a #
.
In the future, scholarly citations will be easier to include and more ‘latex-like’ with our documenteer Sphinx extensions.
3.7.14. RestructuredText Formatting Conventions¶
3.7.14.1. Text wrapping¶
When writing reST documentation in Python docstrings, documentation lines should be wrapped at lengths of 79 characters for consistency with our Python Style Guide.
For reStructuredText documents (e.g., .rst
files), reST doesn’t care
about line formatting. Emacs users, for example, are free to use hard-wrap
formatting lines at 72 characters if that helps you write docs.
Whenever possible, we encourage you to use soft-wrapping for your text.
This allows others format text columns in their editors as they wish.
As well, the GitHub.com code editor does not have hard-wrap auto-formatting.
Those making doc edits on GitHub.com will tend to use soft-wrap by default
(see ‘GitHub Flow in the Browser’).
When using soft-wrap formatting, you might write one sentence per line (i.e., put a line break after each sentence). As a writer, this has the advantage of making it easier to check the rhythm of your writing, including sentence lengths. Shorter sentences are easier to read. One-sentence-per-line is also semantically correct in the sense of Git.
3.7.14.2. Indentation¶
ReStructuredText should be indented consistently with the context, which generally means taking visual alignment cues rather than adhering to a fixed indent width.
In directives, align to the directive’s name:
.. code-block:: python
print('hello world')
In lists, align naturally with the text:
- First item.
Another paragraph for the first item.
- Second item.
Note how that alignment adapts to numbered lists:
1. First item.
Another paragraph for the first item.
2. Second item.
For argument lists in Python docstrings we indent descriptions by four spaces:
Parameters
----------
x_coord : float
Particle's x-coordinate.
y_coord : float
Particle's y-coordinate.
3.7.14.3. Encoding and special characters¶
Data Lab’s reStructuredText source files should be encoded as UTF-8 unicode.
This means that special characters such as en (–) and em (—) dashes can just
be written as such. We do run a variant of smartypants in an attempt to
convert --
and ---
into en and em dashes, respectively, and to
covert dumb quotes ("
) into “typographic” quotes.
3.7.13. Comments in ReStructuredText¶
Provide comments to fellow writers using
..
,Avoid using comments to keep around old or alternate versions of text; prefer using Git version control instead.