Documentation Guide
Introduction
Documentation that is up-to-date and understandable is vital to the health of a software project. 📚 This page describes the documentation requirements and guidelines to be followed during the development of PlasmaPy and affiliated packages.
Tip
Updating documentation is one of the best ways to make a first contribution to an open source software project. 🔰
Note
If you discover areas within PlasmaPy’s documentation that are confusing or incomplete, please raise an issue! This really helps PlasmaPy not only by helping us improve the documentation for all, but also by creating opportunities for new contributors to make their first contribution to the project.
PlasmaPy’s documentation is hosted by Read the Docs and is available at these locations:
The documentation corresponding to the most recent release to PyPI is labeled
stable
and is found at https://docs.plasmapy.org or https://docs.plasmapy.org/en/stable.The documentation corresponding to the ongoing development on the
main
branch in PlasmaPy’s GitHub repository, which is often ahead of the most recent release, is labeledlatest
and can be found at https://docs.plasmapy.org/en/latest. 🏗️
Tip
A preview of the documentation is generated every time a pull request is created or updated. You can access this preview by scrolling down to the checks at the bottom of a pull request, and clicking on Details next to docs/readthedocs.org:plasmapy.
Markup Languages
ReStructuredText
PlasmaPy’s documentation is written using the reStructuredText markup
language. reStructuredText is human readable when viewed within a
source code file or when printed out using help
. reStructuredText
also contains markup that allows the text to be transformed into
PlasmaPy’s documentation. reStructuredText files use the file
extension .rst
. Documentation contained within .py
files
are in the form of docstrings, which are
written in reStructuredText.
ReStructuredText Examples
Here we show some examples of commonly used reStructuredText syntax in PlasmaPy. Please refer to the documentation for Sphinx and reStructuredText for a list of available roles and directives.
This is an example of including headings for the document title, sections, subsections, and so on. The lines surrounding each heading are the same length as that heading.
==============
Document title
==============
Heading 1
=========
Heading 2
---------
Heading 3
~~~~~~~~~
We can link to code objects by enclosing them in single backticks. This
linking will work for Python objects as well as certain packages like
NumPy, SciPy, Astropy, and pandas. This linking is described in the
section on Cross-referencing external packages. In-line code samples are
typically enclosed in double backticks. To get inline code highlighting,
use the :py:
role for Python code.
Here `plasmapy.particles` provides a linked reference to the
module's documentation.
Adding a tilde at the beginning `~plasmapy.particles` still
provides a linked reference to the associated documentation
but shortens the display so only "particles" is displayed.
Double backticks are used to show inline code that is not
cross-referenced: ``plasmapy.particles``.
The ``:py:`` role can be used for inline code highlighting:
:py:`import astropy.units as u`.
This reStructuredText block renders as:
Here
plasmapy.particles
provides a linked reference to the module’s documentation.Adding a tilde at the beginning
particles
still provides a linked reference to the associated documentation but shortens the display so only “particles” is displayed.Double backticks are used to show inline code that is not cross-referenced:
plasmapy.particles
.The
:py:
role can be used for inline code highlighting:import astropy.units as u
.
Sphinx can format code blocks for Python and the Python console
using the code-block
directive.
.. code-block:: python def sample_function(): return 42 .. code-block:: pycon >>> print(6 * 9) 54
This reStructuredText block renders as:
def sample_function(): return 42>>> print(6 * 9) 54
Here are some examples for linking to websites.
`PlasmaPy Enhancement Proposals <https://github.com/PlasmaPy/PlasmaPy-PLEPs>`_
are used to propose major changes to PlasmaPy.
`Write the Docs`_ has a guide_ on writing software documentation.
.. _`Write the Docs`: https://www.writethedocs.org
.. _guide: https://www.writethedocs.org/
This reStructuredText block renders as:
PlasmaPy Enhancement Proposals are used to propose major changes to PlasmaPy.
Write the Docs has a guide on writing software documentation.
Displayed math may be created using the math
directive using LaTeX syntax.
.. math::
\alpha = \beta + \gamma
This reStructuredText block renders as:
\[\alpha = \beta + \gamma\]
Math can be in-line using the math
role.
An example of in-line math is :math:`x`. Using Unicode characters
like :math:`α + β + γ` makes math easier to read in the source code.
This reStructuredText block renders as:
An example of in-line math is \(x\). Using Unicode characters like \(α + β + γ\) makes math easier to read in the source code.
Markdown
A few of PlasmaPy’s files are written using Markdown, such as README
files and licenses from other packages. Markdown is simpler but more
limited than reStructuredText. Markdown files use the file extension
.md
. Posts on GitHub are written in GitHub Flavored
Markdown. The following code block contains a few common examples of
Markdown formatting.
# Header 1
## Header 2
Here is a link to [PlasmaPy's documentation](https://docs.plasmapy.org).
We can make text **bold** or *italic*.
We can write in-line code like `x = 1` or create a Python code block:
```Python
y = 2
z = 3
```
Writing Documentation
Docstrings
A docstring is a comment at the beginning of a function or
another object that provides information on how to use that function
(see PEP 257). Docstrings are designated by surrounding the content
with triple quotes """This is my docstring."""
.
In order to improve readability and maintain consistency, PlasmaPy uses the numpydoc standard for docstrings. Docstring conventions for Python are more generally described in PEP 257.
Tip
If a docstring contains math that utilizes LaTeX syntax, begin the
docstring with r"""
instead of """
.
In a normal string, backslashes are used to begin escape sequences,
and a single backslash needs to be represented with \\
. This
complication is avoided by beginning the docstring with r"""
,
which denotes the docstring as a raw string. For example, the raw
string r""":math:`\alpha`"""
will render the same as the
normal string """:math:`\\alpha`"""
.
Example docstring
Here is an example docstring in the numpydoc format:
import warnings
import numpy as np
def subtract(a, b, *, switch_order=False):
r"""
Compute the difference between two integers.
Add ∼1–3 sentences here for an extended summary of what the function
does. This extended summary is a good place to briefly define the
quantity that is being returned.
.. math::
f(a, b) = a - b
Parameters
----------
a : `float`
The number from which ``b`` will be subtracted.
b : `float`
The number being subtracted from ``a``.
switch_order : `bool`, |keyword-only|, default: `True`
If `True`, return :math:`a - b`. If `False`, then return
:math:`b - a`.
Returns
-------
float
The difference between ``a`` and ``b``.
Raises
------
`ValueError`
If ``a`` or ``b`` is `~numpy.inf`.
Warns
-----
`UserWarning`
If ``a`` or ``b`` is `~numpy.nan`.
See Also
--------
add : Add two numbers.
Notes
-----
The "Notes" section provides extra information that cannot fit in the
extended summary near the beginning of the docstring. This section
should include a discussion of the physics behind a particular concept
that should be understandable to someone who is taking their first
plasma physics class. This section can include a derivation of the
quantity being calculated or a description of a particular algorithm.
Examples
--------
Include a few example usages of the function here. Start with simple
examples and then increase complexity when necessary.
>>> from package.subpackage.module import subtract
>>> subtract(9, 6)
3
Here is an example of a multi-line function call.
>>> subtract(
... 9, 6, switch_order=True,
... )
-3
PlasmaPy's test suite will check that these commands provide the output
that follows each function call.
"""
if np.isinf(a) or np.isinf(b):
raise ValueError("Cannot perform subtraction operations involving infinity.")
warnings.warn("The `subtract` function encountered a nan value.", UserWarning)
return b - a if switch_order else a - b
Template docstring
This template docstring may be copied into new functions. Usually only some of the sections will be necessary for a particular function, and unnecessary sections should be deleted. Any sections that are included should be in the order provided.
def sample_function():
r"""
Compute ...
Parameters
----------
Returns
-------
Raises
------
Warns
-----
See Also
--------
Notes
-----
References
----------
Examples
--------
"""
Doctests
PlasmaPy’s test suite runs code examples in docstrings to verify that the expected output in the docstring matches the actual output from running the code. These doctests verify that docstring examples faithfully represent the behavior of the code.
def double(x):
"""
>>> double(4) # this line is tested that it matches the output below
8
"""
return 2 * x
An ellipsis (...
) denotes that the actual and expected outputs
should only be compared to the available precision. This capability is
needed for functions in plasmapy.formulary
that depend on fundamental
constants that are occasionally revised.
def f():
"""
>>> import numpy as np
>>> np.pi
3.14159...
>>> np.pi ** 100
5.187...e+49
"""
To skip the execution of a line of code in a docstring during tests, end
the line with # doctest: +SKIP
. This is appropriate for lines
where the output varies or an exception is raised.
def g():
"""
>>> import random
>>> random.random() # doctest: +SKIP
0.8905444
>>> raise ValueError # doctest: +SKIP
"""
Roles
The following are roles that are customized for PlasmaPy or come from various Sphinx extensions.
- :commit:
Links to a GitHub commit.
- :issue:
Links to a GitHub issue.
- :orcid:
Links to an ORCID account.
- :pr:
Links to a GitHub pull request.
- :py:
Used for in-line Python code formatting. Defined using
rst_prolog
indocs/conf.py
.
- :sub:
For subscripts.
- :sup:
For superscripts.
- :user:
Links to a GitHub username.
- :wikipedia:
Links to a Wikipedia article.
Example notebooks
PlasmaPy’s documentation includes an example gallery of Jupyter
notebooks. The notebooks are located in docs/notebooks
. The example
gallery is built using nbsphinx.
To add a notebook to the example gallery, include the .ipynb
file in the appropriate subdirectory of docs/notebooks
. The notebook
must be included in an nbgallery
directive in docs/examples.rst
(though this contains wildcards for most existing directories, so no
additional step may be required).
Before adding the Jupyter notebook, open it and run
nbsphinx that it should
execute the notebook during the documentation build. However, if the
notebook is computationally intensive, instead pre-execute it with
before
doing git commit
. Doing this will reduce documentation build times.
If a notebook makes use of a Python package that is not included in
PlasmaPy’s requirements, included in the docs
dependencies set as
defined in pyproject.toml
.
There are two methods for using markup in non-code cells in a Jupyter notebook in the gallery:
In “raw” cells, we can make use of reStructuredText formatting and thus enable linking to code objects.
In Markdown cells, we can make use of Markdown formatting. However, to link to a code object, we must include a link to the actual documentation page. Be sure to link to the
stable
version of the documentation (as opposed tolatest
), even if the link does not exist onstable
yet. For example, a link toplasmapy.formulary
can be accomplished with[`plasmapy.formulary`](https://docs.plasmapy.org/en/stable/formulary/index.html)
If a code cell in a notebook intentionally raises an exception, add a metadata tag entitled “raises-exception” to that cell.
Glossary definitions
Define important terms in PlasmaPy’s Glossary, which is located
at docs/glossary.rst
. Here is an example of a term defined within the
glossary
directive.
.. glossary::
kwargs
An abbreviation for keyword arguments.
Using the term
role allows us to link to the definitions
of terms. Using :term:`kwargs`
will link to kwargs in
the Glossary. We can also refer to terms defined in the projects
connected via intersphinx if they have not already been defined in
PlasmaPy’s Glossary. Using :term:`role`
will link to
role and :term:`directive`
will link to directive in
Sphinx’s glossary.
Documentation guidelines
This section contains guidelines and best practices for writing documentation for PlasmaPy and affiliated packages.
Write documentation to be understandable to students taking their first course or beginning their first research project in plasma science. Include highly technical information only when necessary.
Use technical jargon sparingly. Define technical jargon when necessary.
Use the active voice in the present tense.
Keep the documentation style consistent within a file or module, and preferably across all of PlasmaPy’s documentation.
Update code and corresponding documentation at the same time.
Write sentences that are simple, concise, and direct rather than complicated, vague, or ambiguous. Prefer sentences with ≲ 20 words.
Avoid idioms, metaphors, and references that are specific to a particular culture.
Many words and software packages have more than one common spelling or acronym. Use the spelling that is used in the file you are modifying, which is preferably the spelling used throughout PlasmaPy’s documentation.
More generally, it is preferable to use the spelling that is used in Python’s documentation or the spelling that is used most commonly.
Represent names and acronyms for a software package or language as they are represented in the documentation for each project. Common examples include “Python”, “Astropy”, and “NumPy”, and “reStructuredTest”.
When referencing PlasmaPy functionality, write the full namespace path to where the functionality is defined, not where it is conveniently accessed. For example, write
`~plasmapy.formulary.speeds.Alfven_speed`
rather than`~plasmapy.formulary.Alfven_speed`
.This does not necessarily need to be done when referencing external packages, since each package may have their own standard. For example, Astropy’s
Quantity
class is defined in`astropy.units.quantity.Quantity`
but is also indexed at`~astropy.units.Quantity`
so either option will link to the same documentation.For readability, limit documentation line lengths to ≲ 72 characters. Longer line lengths may be used when necessary (e.g., for hyperlinks).
Note
Studies typically show that line lengths of 50–75 characters are optimal for readability. 📄
Use indentations of 3 spaces for reStructuredText blocks.
Store images within the
docs/_static
directory, except for images that are generated during the Sphinx build. 🖼️ Thedocs/_static
directory contains files that are used for the online documentation but are not generated during the Sphinx build.Avoid linking to websites that might disappear due to link rot such as documents hosted on personal websites.
When including references, use a link that includes a persistent identifier such as a digital object identifier (DOI) when one is available (e.g., https://doi.org/10.5281/zenodo.4602818). 🔗
Wikipedia articles may be linked to when they contain a well-developed and accurate description of a concept.
Include both the original references for a topic as well as accessible pedagogical references. Prefer references that are open access over references that require purchase of a subscription or are behind a paywall.
Note
Emphasize important points with admonitions like this one.
Start the names of all physical units with a lower case letter, except at the beginning of a sentence and for “degree Celsius”. 🌡️
Physical unit symbols should not be formatted as math. If units are needed inside a math block, use LaTeX’s
\text
command as in the example below. The backslash followed by a space is needed to have a space between the number and the units.The speed of light is approximately :math:`3 × 10^8` m/s or .. math:: 3 × 10^{10}\ \text{cm/s}
This reStructuredText block renders as:
The speed of light is approximately \(3 × 10^8\) m/s or
\[3 × 10^{10}\ \text{cm/s}\]The names of chemical elements are lower case, except at the beginning of a sentence.
Particle and chemical symbols should be formatted as regular text. Use
sub
for subscripts andsup
for superscripts.Because interpreted text must normally be surrounded by whitespace or punctuation, use a backslash followed by a space for the interpreted text to show up immediately next to the regular text. This is not necessary before a period or comma.
The symbol for helium is He. The symbol for an electron is e\ :sup:`-`. An alpha particle may be represented as :sup:`4`\ He\ :sup:`1+`.
This reStructuredText block renders as:
The symbol for helium is He.
The symbol for an electron is e-.
An alpha particle may be represented as 4He1+.
Begin each
.py
file with a docstring that provides a high-level overview of what is contained in that module.Place the
__all__
dunder immediately after the docstring that begins a module and before the import statements (but after anyfrom __future__
imports that must be at the beginning of a file). This dunder should be alist
that contains the names of all objects in that module intended for use by users. Private objects (i.e., objects with names that begin with an underscore) should not be included in__all__
.__all__
is a leftover from the now dissuaded practice of star imports (e.g.,from package import *
), but is still used by Sphinx for selecting objects to document. Only objects contained within__all__
will show up in the online documentation.
Docstring guidelines
All functions, classes, and objects that are part of the public API must have a docstring that follows the numpydoc standard. Refer to the numpydoc standard for how to write docstrings for classes, class attributes, and constants.
The short summary statement at the beginning of a docstring should be one line long, but may be longer if necessary.
The extended summary that immediately follows the short summary should be ≲ 4 sentences long. Any additional information should included in the “Notes” section.
Put any necessary highly technical information in the “Notes” section of a docstring.
The short summary should start on the line immediately following the triple quotes. There should not be any blank lines immediately before the closing triple quotes.
The first line of the docstring for a function or method should begin with a word like “Calculate” or “Compute” and end with a period.
The first line of an object that is not callable (for example, an attribute of a class decorated with
property
) should not begin with a verb and should end with a period.Keep the docstring indented at the same level as the
r"""
or"""
that begins the docstring, except for reStructuredText constructs like lists, math, and code blocks. Use an indentation of four spaces more than the declaration of the object.def f(): """This is indented four spaces relative to the `def` statement."""
The first sentence of a docstring of a function should include a concise definition of the quantity being calculated, as in the following example.
def beta(T, n, B): """Compute the ratio of thermal pressure to magnetic pressure."""
When the definition of the quantity being calculated is unable to fit on ∼1–2 lines, include the definition in the extended summary instead.
def beta(T, n, B): """ Compute plasma beta. Plasma beta is the ratio of thermal pressure to magnetic pressure. """
When a function calculates a formula, put the formula in the extended summary section when it can be included concisely. Put complicated formulae, derivations, and extensive discussions of physics or math in the “Notes” section.
Private code objects (e.g., code objects that begin with a single underscore, like
_private_object
) should have docstrings. A docstring for a private code object may be a single line, and otherwise should be in numpydoc format.Docstrings for private code objects do not get rendered in the online documentation, and should be intended for contributors.
Parameters
Describe each parameter in the “Parameters” section of the docstring using the following format:
parameter_name : type specification
Parameter description.
Some examples are:
x : `float`
Description of ``x``.
y : `int`
Description of ``y``.
settings : `dict` of `str` to `int`
Description of ``settings``.
Type specifications
The type specification may include:
Size and/or shape information
Type information
Valid choices for the parameter
Whether the parameter is keyword-only, optional, and/or positional-only
Default values
The type specification should not include information about the meaning of the parameter. Here are some example type specifications:
|particle-like|
`list` of `str`
|array_like| of `int`, default: [-1, 1]
|Quantity| [length], default: 10 m
|Quantity| [temperature, energy], |keyword-only|, default: 0 K
Use the substitution
|array_like|
to indicate that an argument must be array_like (i.e., convertible into anndarray
).Use
|particle-like|
to indicate that a particle-like argument should be convertible into aParticle
,CustomParticle
, orParticleList
.Use
|particle-list-like|
to indicate that a particle-list-like argument should be convertible into aParticleList
.Use
|atom-like|
to indicate that an argument must be atom-like (i.e., an element, isotope, and/or ion). ⚛️When the array must be \(n\)-dimensional, precede the type by
nD
wheren
is replaced by the number of dimensions.1D |array_like| 3D |array_like|
If the shapes and sizes of the parameters are interrelated, then include that information in parentheses immediately before the type information. Include a trailing comma inside the parentheses when the parameter is 1D. Use
:
for a single dimension of arbitrary size and...
for an arbitrary number of dimensions of arbitrary size.(M,) |array_like| (N,) |array_like| (M, N) |array_like| (N, :) |array_like| (M, N, ...) |array_like|
If the parameter can only be specific values, enclose them in curly brackets. The options may be listed with the default value first, sorted alphanumerically, or ordered so as to maximize readability.
{"classical postmodernist", "retro-futuristic"} {"p+", "e-"}, default: "p+" {1, 2, 3, 4}, default: 3
Tip
Use
typing.Literal
in type hint annotations when a parameter should only be provided with specific values (e.g.,x: Literal{1, 2, 3, 4}
).If a default is given, it is not necessary to state that the parameter is optional. When the default is
None
, useoptional
instead ofdefault: `None`
.
Tip
If a particular type specification is not covered above, look for conventions from the numpydoc style guide, the matplotlib documentation guide, or the LSST docstring guide.
Parameter descriptions
The parameter description should concisely describe the meaning of
the parameter, as well as any requirements or restrictions on allowed
values of the parameter (including those specified by
validate_quantities()
or particle_input()
. The parameter description
should not repeat information already in the type specification, but may
include type information when:
The type specification does not fit with in the docstring line character limit;
Different types have different meanings, requirements, or restrictions; or
The docstring will be more understandable by doing so.
For functions that accept an arbitrary number of positional and/or
keyword arguments, include them in the “Parameters” section with the
preceding asterisk(s). Order *args
and **kwargs
as they
appear in the signature.
*args : tuple, optional
Description of positional arguments.
**kwargs : dict, optional
Description of keyword arguments.
Exceptions and warnings
Docstrings may include a “Raises” section that describes which exceptions get raised and under what conditions, and a “Warns” section that describes which warnings will be issued and for what reasons.
The “Raises” and “Warns” sections should only include exceptions and warnings that are not obvious or have a high probability of occurring. For example, the “Raises” section should usually not include a
TypeError
for when an argument is not of the type that is listed in the “Parameters” section of the docstring.The “Raises” section should include all exceptions that could reasonably be expected to require exception handling.
The “Raises” section should be more complete for functionality that is frequently used (e.g.,
Particle
).The “Raises” and “Warns” sections should typically only include exceptions and warnings that are raised or issued by the function itself. Exceptions and warnings from commonly used decorators like
validate_quantities()
andparticle_input()
should usually not be included in these sections, but may be included if there is strong justification to do so.
Attributes
Dunder methods (e.g., code objects like
__add__
that begin and end with two underscores) only need docstrings if it is necessary to describe non-standard or potentially unexpected behavior. Custom behavior associated with dunder methods should be described in the class-level documentation.Docstrings for most dunder methods are not rendered in the online documentation and should therefore be intended for contributors.
Docstrings for
__init__
,__new__
, and__call__
are rendered in the documentation, and should be written for users. The docstrings for__init__
and__new__
are included in the class-level docstring, while the docstring for__call__
is included in the methods summary of a class.
When an attribute in a class has both a getter (which is the method decorated with
property
) and asetter
decoration, then the getter andsetter
functionality should be documented in the docstring of the attribute decorated with@property
.class Person: @property def age(self): """Document both getter and setter here.""" return self._age @age.setter def age(self, n): self._age = n
Narrative documentation guidelines
Each top-level subpackage must have corresponding narrative documentation.
Use narrative documentation to describe how different functionality works together.
Narrative documentation should be used when the full scope of some functionality cannot be adequately described within only the docstrings of that functionality.
Use title case for page titles (e.g., “This is Title Case”) and sentence case for all other headings (e.g., “This is sentence case”).
Sphinx
Sphinx is the software used to generate PlasmaPy’s documentation from reStructuredText files and Python docstrings. It was originally created to write Python’s documentation and has become the de facto software for documenting Python packages. Most Python packages utilize Sphinx to generate their documentation.
Configuration
The docs/conf.py
file contains the configuration information needed
to customize Sphinx behavior. The documentation for Sphinx lists the
configuration options that can be set.
The docs/_static/css
directory contains CSS files with style
overrides for the Read the Docs Sphinx Theme to customize the look
and feel of the online documentation.
Sphinx extensions
PlasmaPy’s documentation is built with the following Sphinx extensions:
sphinx.ext.autodoc
for including documentation from docstrings.sphinx.ext.extlinks
for shortening links to external sites (e.g.,orcid
andwikipedia
).sphinx.ext.graphviz
to allow Graphviz graphs to be included.sphinx.ext.intersphinx
for linking to other projects’ documentation.sphinx.ext.mathjax
for math rendering with MathJax.sphinx.ext.napoleon
for allowing NumPy style docstrings.sphinx.ext.todo
to supporttodo
directives.sphinx.ext.viewcode
to generate links to pages showing source code.sphinxcontrib-bibtex
to enable usage of a BibTeX file to create the Bibliography.sphinx_copybutton
to add a “copy” button for code blocks.sphinx_gallery.load_style
for using sphinx-gallery styles.sphinx_changelog
for rendering towncrier changelogs.sphinx-tabs
for creating tabbed content.sphinx-hoverxref
for showing floating windows on cross references of the documentation.sphinx-notfound-page
to add a 404 page for the documentation.sphinx-issues
to add roles for linking to GitHub (commit
,issue
,pr
, anduser
).sphinx-reredirects
to enable hyperlink redirects.sphinx-toolbox
for handy tools for Sphinx documentationsphinxemoji
for emoji substitutionsplasmapy_sphinx
for customizations created for use in PlasmaPy and affiliated packages. Note thatplasmapy_sphinx
is expected to be broken out into its own package in the future.
These extensions are specified in extensions
configuration
value in docs/conf.py
.
Cross-referencing external packages
Intersphinx allows the automatic generation of links to the
documentation of objects in other projects. 🔗 This cross-package
linking is made possible with the sphinx.ext.intersphinx
extension and
proper package indexing by the external package using
sphinx.ext.autodoc
.
When we include `astropy.units.Quantity`
in the documentation, it
will show up as astropy.units.Quantity
with a link to the appropriate
page in Astropy documentation. Similarly, `~astropy.units.Quantity`
will show up as Quantity
.
The external packages that we can cross-reference via the magic of
intersphinx
are defined in intersphinx_mapping
in docs/conf.py
. Intersphinx has already been set up in PlasmaPy to
include the central Python documentation, as well as frequently used
packages such as Astropy, lmfit, matplotlib, NumPy, pandas,
SciPy, and Sphinx.
Tip
When adding new packages to intersphinx_mapping
, please
double check that the configuration has been set up correctly.
If a cross-link is not working as expected this is usually due to one of the following reasons:
A typo;
The package not being defined in
intersphinx_mapping
, orThe referenced source package not properly or fully indexing their own code, which is common in Python packages.
For some packages, the name of the package itself does not link correctly.
Substitutions
Some functions and classes are referred to repeatedly throughout the documentation. reStructuredText allows us to define substitutions
.. |Particle| replace:: `~plasmapy.particles.particle_class.Particle`
Here whenever |Particle|
is used Sphinx will replace it with
`~plasmapy.particles.particle_class.Particle`
during build time.
PlasmaPy contains pre-defined global substitutions that can be used
elsewhere in the documentation. For example, we can write |Quantity|
instead of `~astropy.units.Quantity`
, and |Particle|
instead of
`~plasmapy.particles.particle_class.Particle`
. These global
substitutions are defined in docs/_global_subtitutions.py
, and are
summarized in the following table.
Substitution |
Replaces |
Example |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
This feature is under development. Breaking changes may occur in the future. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
IDE |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3.12 |
|
|
3.10 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Note
Since substitutions are executed by Sphinx when the documentation
is built, any substitution used in docstrings will not show up when
using help
. For example, when |Particle|
is used in a
docstring, help
will show it as |Particle|
rather than
`~plasmapy.particles.particle_class.Particle`
. Consequently,
substitutions should not be used in docstrings when it is important
that users have quick access to the full path of the object
(such
as in the See Also
section).
Emoji
Emojis in software documentation help enhance readability, convey
emotions, and make the content friendlier and less intimidating. Emojis
improve comprehension by providing visual cues, such as ⚛️ for
plasmapy.particles
, 🌊 for plasmapy.dispersion
,
🩺 for plasmapy.diagnostics
, and 🧮 for
plasmapy.formulary
.
Not all text editors, terminals, or IDEs have the ability to display emojis properly. PlasmaPy’s
documentation makes use of the sphinxemoji
extension which adds
substitutions for emojis. For example, we can denote good first issues
with |:beginner:|
for 🔰. Click here for the full list
of emoji codes supported by sphinxemoji
.
Tip
Add emojis to research articles to strike up conversations with referees and editors! 😅
Bibliography
PlasmaPy uses sphinxcontrib-bibtex
to manage references for its
documentation. This Sphinx extension allows us to store references in
a BibTeX file which is then used to generate the
Bibliography. References in the Bibliography are
then citeable from anywhere in the documentation.
To add a new reference to the Bibliography, open
docs/bibliography.bib
and add the reference in BibTeX format. The
citekey should generally be the surname of the first author (all lower
case) followed by a colon and the year. A letter should be added after
the year when needed to disambiguate multiple references. Include the
DOI if the reference has one. If the reference does not have a DOI,
then include the URL. The ISBN or ISSN number should be included for
books. The misc
field type should be used when citing data sets and
software. Please follow the existing style in docs/bibliography.bib
and alphabetize references by the surname of the first author. To
preserve capitalization, enclose words or phrases within curly brackets
(e.g., {NumPy}
).
Use :cite:p:`citekey`
to create a parenthetical citation and
:cite:t:`citekey`
to create a textual citation, where
citekey
is replaced with the BibTeX citekey. Multiple citekeys can
also be used when separated by commas, like
:cite:p:`citekey1, citekey2`
. For example,
:cite:p:`wilson:2014`
will show up as
[Wilson et al., 2014], :cite:t:`wilson:2014`
will show up as
Wilson et al. [2014], and :cite:p:`wilson:2014, wilson:2017`
will show up as [Wilson et al., 2014, Wilson et al., 2017].
Creating a documentation stub file for a new module
When the narrative documentation does not index a subpackage (a
directory) or module (a .py
file) with automodule
,
automodapi
, or the like, then a stub file must be created for that
particular subpackage or module in docs/api_static
. For example, the
stub file for plasmapy.particles.atomic
is placed at
docs/api_static/plasmapy.particles.atomic.rst
and its contents
look like:
:orphan: `plasmapy.particles.atomic` =========================== .. currentmodule:: plasmapy.particles.atomic .. automodapi:: plasmapy.particles.atomic
A missing stub file may lead to either a reference target not found
error or the absence of the module in the documentation build.
Note
If a pull request adds a new subpackage and a new module, then a stub file must be created for both of them.
For example, suppose a pull request creates the plasmapy.io
subpackage in the src/plasmapy/io/
directory and the
plasmapy.io.readers
module via src/plasmapy/io/readers.py
. It
will then be necessary to create stub files at both
docs/api_static/plasmapy.io.rst
and
docs/api_static/plasmapy.io.readers.rst
.
Templating
Sphinx uses the Jinja templating engine to generate HTML code. Jinja may be used within the documentation when templating is necessary. For more details, please refer to Sphinx’s templating page.
Danger
There are certain tasks that one would expect to be straightforward with reStructuredText and Sphinx but are only possible by doing a horrible workaround that can take hours to figure out. This has given rise to the saying:
Sphinx rabbit holes often have dragons in them. 🐇 🕳️ 🐉
Remember: your happiness and well-being are more important than nested inline markup!
Building documentation
Tip
Because a documentation preview is generated automatically by Read the Docs for every pull request, it is not necessary to build the documentation locally on your own computer. New contributors can safely skip this section.
There are two methods for building the documentation: make and Nox.
Using make will build the documentation based off of what is in the current directory structure. make is quicker for local builds than Nox but requires you to install and set up all dependencies.
Using Nox does not require setting up all dependencies ahead of time, but is more computationally intensive since it creates a virtual environment and builds the package before building the documentation. Consequently, PlasmaPy uses Nox for building the documentation on continuous integration testing platforms.
Prerequisites
Prior to building the documentation, please follow the instructions on getting ready to contribute. Alternatively, the dependencies for building docs can be installed by entering the top-level directory of the repository and running:
pip install -e .[docs,tests]
It may also be necessary to install the following software:
Building documentation
PlasmaPy’s documentation can be built using Nox, make, or sphinx-build. We recommend starting with Nox.
We can use Nox to build the documentation locally by running:
nox -s docs
To pass any options to sphinx-build, put them after --
. For
example, use nox -s docs -- -v
to increase output
verbosity.
Building with Nox is well-suited for reproducible documentation builds in an isolated Python environment, which is why it is used in continuous integration tests.
Building documentation with make is useful for interactively building and rebuilding the documentation.
If make is installed, we can build the documentation by entering
the docs
directory and running:
make html
The documentation build can then be removed with
make clean
Using sphinx-build allows us to choose different options to sphinx-build than the defaults used by Nox and make.
PlasmaPy’s documentation can be build by going to the top-level directory of the repository and running:
sphinx-build docs docs/_build/_html -b html
The documentation landing page can be opened with a web browser at
docs/_build/html/index.html
.
To check hyperlinks locally, run:
nox -s linkcheck
make linkcheck
sphinx-build docs docs/_build/_html -b linkcheck
Tip
When writing documentation, please fix any new warnings that arise.
To enforce this, the docs
Nox environment fails if there are
any warnings.
Troubleshooting
This section describes how to fix common documentation errors and warnings. 🛠️
Reference target not found
Warnings like py:obj reference target not found
occur when Sphinx
attempts to interpret text as a Python object, but is unable to do so.
For example, if a docstring includes `y`
, Sphinx will attempt to
link to an object named y
. If there is no object named y
, then
Sphinx will issue this warning, which gets treated like an error.
If the text is meant to be an inline code example, surround it with double backticks instead of single backticks.
When the text is meant to represent a code object, this warning usually
indicates a typo or a namespace error. For example, the warning
resulting from `plasmapy.paritcles`
could be resolved by fixing the
typo and changing it to `plasmapy.particles`
.
Important
For PlasmaPy objects, use the full namespace of the object (i.e., use
`plasmapy.particles.particle_class.Particle`
instead of
`plasmapy.particles.Particle`
) or a reStructuredText
substitution like |Particle|
as defined in
docs/_global_subtitutions.py
.
This warning may occur when a new module or subpackage is created without creating a stub file for it.
This warning sometimes occurs in the type specification of a parameter
in a docstring. Sphinx attempts to link words in type specifications to
code objects. Type lines are intended to provide concise information
about allowed types, sizes, shapes, physical types, and default values
of a parameter. To resolve this warning, first move information about
the meaning of a parameter from the type specification into the
parameter description that begins on the following line. To expand the
list of allowed words or patterns in type specifications, add a regular
expression to nitpick_ignore_regex
in docs/conf.py
.
This warning may also occur when there is an extra space between a
Sphinx role and the argument it is intended to act on. For example,
this warning would be fixed by changing :math: `y`
to :math:`y`
.
Missing documentation pages for new modules
When a new module or subpackage is created, it is usually necessary to
create a stub file for it in docs/api_static
. A
missing stub file can lead to either a reference target not found
error or missing documentation pages.
Missing attribute errors
An AttributeError
may occur when an import
statement is missing
in a __init__.py
file. For example, the error
AttributeError: module 'plasmapy.subpackage' has no attribute 'module'
will occur when src/plasmapy/subpackage/__init__.py
is missing
from plasmapy.subpackage import module
. Make sure that
__all__
contains "module"
as well.
List ends without a blank line
Warnings like the following:
WARNING: :40: (WARNING/2) Bullet list ends without a blank line; unexpected unindent.
WARNING: :47: (WARNING/2) Definition list ends without a blank line; unexpected unindent.
may show up when Sphinx attempts to interpret text as a list, but is unable to do so. This warning might not show the file that it occurs in.
If this documentation contains a list, make sure that it is followed by a blank line and follows the formatting described in Sphinx’s documentation on lists.
This warning may occur in other places due to an indentation or other formatting problem. Try checking out the formatting in the Example docstring above.
This warning can occur when a changelog entry contains lines that start with a backtick. Try editing each changelog entry so that it is on a single really long line, rewording the changelog entry, or using Substitutions.
Could not match a code example to HTML
This warning occurs when sphinx-codeautolink cannot match a code
object to its corresponding documentation. Double check that the code is
correct, and consider adding any missing import
statements. The
documentation for this extension contains examples
on how to skip blocks with .. autolink-skip::
and how to do
invisible imports with .. autolink-preface::
.
If this warning occurs in the “Examples” section of a docstring, put
.. autolink-skip: section
at the beginning of that section (see
#2554). These warnings sometimes only show up when rebuilding
the documentation.
A related warning is Could not match transformation of _ on source
lines
.
Document isn’t included in any toctree
In general, each source file in the documentation must be included in a table of contents (toctree). Otherwise, Sphinx will issue a warning like:
WARNING: document isn't included in any toctree
This warning may occur when adding a new .rst
file or example
Jupyter notebook without adding it to a toctree.
This warning can be resolved by:
Adding the file to the appropriate toctree, or
Adding the
orphan
metadata field at the top of the file (not recommended in most situations).
In the docs
directory, the tables of contents are generally located
in index.rst
in the same directory as the source files. For
example Jupyter notebooks, the tables of contents are in
docs/examples.rst
.