You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 3 Next »

We use Sphinx to embed code documentations in source files, as Python docstrings. Sphinx uses the reStructuredText markup language. Sphinx and its Python support, as well as reST markup, have various quirks that demand discipline.

Python Formatting

Our goals are readability and clarity.

  1. Python docstrings should always appear on the line underneath the symbol they are attached to.
  2. Docstrings will be indented once off the symbol they are attached to.
  3. We will normally use multi-line docstrings with triple-double-quote delimiters.
  4. The delimiters will each appear on their own line. (Note that in some Python guides, the first delimiter does not appear on its own line. The archaic reason for this is that it adds an extra newline at the beginning of the docstring, but this is irrelevant when one uses markup languages like reST.)
  5. Line lengths throughout the entire block should be limited to same number of columns as code (100 columns). Wrap whole words to the next line; prefer never to hyphenate.
  6. We will normally add an extra empty line after the docstring, neatly separate it from code.

If the docstring is very short, it's permissible to put delimiters and content all in one line and avoid the extra empty line. Only do this if the content fits in a single line within the allowed column limit (100).

English Descriptions

The point is to succinctly describe what the symbol is for, what it does, how it behaves, and how to use it.

  1. If its usage is specific, it would also be good to specify where it is used (which modules, classes, mechanisms, etc.).
  2. Use several paragraphs as necessary. Each paragraph should start at column 0 and have an empty line separating it from the next section.
  3. The first paragraph should be as short as possible: it is a quick description that should be enough for a programmer familiar with the code. It can even be a fragment rather than a complete grammatical sentence. Subsequent paragraphs will delve into more detail.

Avoid using the name or type of the symbol itself, as it is redundant. This is bad:

Parameter is a class that wraps value and gives them a strict type.

This is better:

Wraps values and provides a strict type.

Markup

Emphasis

  • *asterisk for italics*
  • **double-asterisk for bold**

Escape Special Characters

Sphinx is aggressive about interpreting special characters, and not very good at automatically detecting when you don't want it to interpret them. Make sure to escape them with a backslash.

So, if you want to use an asterisk as is, make sure to escape it:

Uses value \* unit size / 2.0 to calculate the final frequency.

Another common annoyance is the underscore. This would render incorrectly:

Do not delete the value of user_password.

Instead, do this:

Do not delete the value of user\_password.

(Actually, it's probably better to use double-back-quotes to render symbols, in which case you do not have to escape underscores. See below.)

Symbols

The safest way to mention an arbitrary symbol is to embed it in double-back-quotes. Example:

The ``user_password`` field in the result will contain the generated password.

The single-back-quote delimiter is used only for linked Python symbols. Sphinx can sometimes find the symbol automatically, but is often wrong, especially if there is ambiguity. It is thus best to prefix the single-back-quoted symbol with the type of the symbol, and also provide full Python paths if it's not immediately within the code block. The following prefixes are supported:

  • :class: Class name. Always provide the full Python path, even if it's within the same module.
  • :func: Global function name. Always provide the full Python path, even if it's a global method within the same module.
  • :meth: Method name. You do not have to provide the full Python path if it's a method within the same class as the docstring.

Examples:

The :meth:`release` method in this class should be used to release all resources when done. Do
not use the instance after it has been released. To release all instances, you may use the
:func:`aria.tools.release_all` global function.

Use back-quotes with the URL in triangle-quotes followed by double-underscore. Example:

This is a `link to a website <http://mysite.org/page>`__.

While the double-underscore is not strictly required, it tells Sphinx to avoid an annoying optimization by which it groups identical links together and turns them into footnotes, making the documentation harder to read. The double-underscore tells Sphinx to always render the link as is, and so is always safe for all links.

URLs can be wrapped across multiple lines. Prefer to break the hyperlink before URL separators ("/", "#", "?", etc.). Example:

See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca
/TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html
#DEFN_ENTITY_NODE_TEMPLATE>`__

Code Blocks

This is surprisingly easy in reST. Simply end the previous paragraph in double-colon and indent the code block. Sphinx will render a single colon and put your paragraph as is. Example:

Usage example::

  x = Resource()
  try:
    if x.valid:
      x.display()
  finally:
    x.destroy()

Make sure to properly destroy the resource as shown above.

Note that if you don't have a paragraph prior to your code, use a paragraph that is just "::" in which case Sphinx will not render a colon.

Attributes, Parameters, Arguments, Return Values

All of these are marked up twice: once is the English description, next is the type. The exact prefixes will be detailed later when used.

Note that if the description must be split into multiple lines, Sphinx requires that subsequent lines be indented. Example:

:param output: specifies that the phase has a *single* output; note that actual path of the
               output will be based on this parameter but not identical to it

Description

  1. The English description is a non-capitalized fragment. It should not end in a period.
  2. Do not add "the" at the beginning of the description, unless absolutely necessary to provide clarity.
  3. Do not add "of the class" or "of the instance" unless absolutely necessary to provide clarity.
  4. If more details must be added, add extra fragments using a semicolon.

Type

  1. The type should be the lowest common denominator of the supported type. For example, if the type can be either a str or a unicode, then basestring should be specified.
  2. If the type is a class, use :class:`Name`.
  3. If multiple types are supported, separate them with a pipe (no spaces before or after the pipe).
  4. List types should have the element type embedded in brackets.
  5. Dict types should have the key and value types separate by a "," (space after the comma) and embedded in curly brackets.
  6. If None is a possible value, do not specify the type as None or NoneType. None values are not truly typed, but instead are treated specially everywhere in Python. In such cases, explain in the English description how None values are treated, if at all.
  7. Because Python is very dynamic, sometimes type does not matter much. In such cases do not use type object; instead omit the type information altogether.

Functions

In the class docstring add a section to document all arguments and return value. Arguments are documented with :param: and :type:. The return value is documented with :returns: and :rtype:. Complete example:

def release_resources(factory, time='now'):
  """
  Release all instances of :class:`Resource`.

  :param factory: factory holding the resources
  :type factory: :class:`Factory`
  :param time: when to release the resources, either 'now' or 'later'
  :type time: basestring
  :returns: ``True`` if released at least one resource
  :rtype: bool
  """

Classes

Fields

In the class docstring make sure to add a section where you document all its fields in a separate block using :ivar: and :vartype: (ivar here stands for "instance variable"). Example:

Represents a typed value. The value can contain nested intrinsic functions.

This model can be used as the ``container_holder`` argument for :func:`functions.evaluate`.

:ivar name: Name
:vartype name: basestring
:ivar type_name: Type name
:vartype type_name: basestring
:ivar value: Value
:ivar description: Description
:vartype description: basestring

Methods

Methods are documented identically to functions.

The only difference is that you should ignore the self argument in documentation. Example:

def release(self, time='now'):
  """
  Release this resource. Do not use the resource after it has been released.

  :param time: when to release the resources, either 'now' or 'later'
  :type time: basestring
  :returns: ``True`` if released
  :rtype: bool  
  """

Properties

Properties are documented similarly to methods.

Because they have no arguments, and always have a return value, only :rtype: should be specified. Example:

@property
def factory(self):
  """
  The factory from which this resource was created.

  :rtype: :class:`Factory`
  """

Constructors

You can document Python's __init__ constructor just like any other method, however be aware that Sphinx will add the content after the class docstring. (This reflects the fact that the symbol itself is used as a constructor function in Python.)

This feature can lead to confusing results. For this reason, we recommend not adding anything to the __init__ docstring other than the argument description block. Put all relevant English descriptions in the class docstring instead.

  • No labels