Difference between revisions of "Sphinx gotchas"

From Software Heritage Wiki
Jump to navigation Jump to search
(→‎Verbatim code blocks: add gotcha: inline code samples)
(→‎Code cross-references: document explicit anchors)
 
(14 intermediate revisions by the same user not shown)
Line 1: Line 1:
 
Here is a list of common gotchas when formatting Python docstrings for [http://www.sphinx-doc.org/en/stable/ Sphinx] and the [http://www.sphinx-doc.org/en/stable/ext/napoleon.html Napoleon] style.
 
Here is a list of common gotchas when formatting Python docstrings for [http://www.sphinx-doc.org/en/stable/ Sphinx] and the [http://www.sphinx-doc.org/en/stable/ext/napoleon.html Napoleon] style.
  
== Lists ==
+
== Sphinx ==
  
All sorts of [http://www.sphinx-doc.org/en/stable/rest.html#lists-and-quote-like-blocks lists] require an empty line before the first bullet and after the last one, to be properly interpreted as list. No indentation is required for list elements w.r.t. surrounding text, and line continuations should be indented like the first character after the bullet
+
=== Lists ===
  
Good:
+
All sorts of [http://www.sphinx-doc.org/en/stable/rest.html#lists-and-quote-like-blocks '''lists'''] require an empty line before the first bullet and after the last one, to be properly interpreted as list. No indentation is required for list elements w.r.t. surrounding text, and line continuations should be indented like the first character after the bullet
 +
 
 +
<u>Bad:</u>
 +
<pre>
 +
this is a bad example that will not be interpreted as a list
 +
preceding text
 +
- foo
 +
- bar
 +
- baz
 +
following text
 +
</pre>
 +
 
 +
<u>Good:</u>
 
<pre>
 
<pre>
 
this is some text preceding the list
 
this is some text preceding the list
Line 19: Line 31:
 
</pre>
 
</pre>
  
Bad:
+
<u>Bad:</u>
 
<pre>
 
<pre>
this is a bad example that will not be interpreted as a list
 
preceding text
 
 
- foo
 
- foo
- bar
+
- nested lists also requires empty lines, but they are missing here
- baz
+
  - inner list 1
following text
+
  - inner list 2
 +
- outer list continues here
 
</pre>
 
</pre>
  
Good:
+
<u>Good:</u>
 
<pre>
 
<pre>
 
surrounding text
 
surrounding text
Line 44: Line 55:
 
</pre>
 
</pre>
  
Bad:
+
=== Verbatim source code ===
 +
 
 +
Verbatim [http://www.sphinx-doc.org/en/stable/rest.html#source-code '''code blocks'''], e.g., for code examples, requires double colon at the end of a line, then an empty line, and then the code block itself, indented:
 +
 
 +
<u>Bad:</u>
 
<pre>
 
<pre>
- foo
+
This does not work as there is a single column and no empty line before code:
- nested lists also requires empty lines
+
    def foo(bar, baz):
  - inner list 1
+
        qux = bar + baz
  - inner list 2
+
 
- outer list continues here
+
        return qux
 
</pre>
 
</pre>
  
== Verbatim source code ==
+
<u>Good:</u>
 
 
[http://www.sphinx-doc.org/en/stable/rest.html#source-code Verbatim code blocks], e.g., for code examples, requires double colon at the end of a line, then an empty line, and then the code block itself, indented:
 
 
 
 
<pre>
 
<pre>
 
a nice example of python code follows::
 
a nice example of python code follows::
Line 68: Line 80:
 
</pre>
 
</pre>
  
Inline code samples use double backquotes, and not single ones.
+
'''Inline code samples''' use double backquotes, and not single ones.
 +
 
 +
<u>Bad:</u>
 +
<pre>
 +
you have to instantiate the method `def foo(bar): pass` in order to use this abstract class
 +
</pre>
  
Good:
+
<u>Good:</u>
 
<pre>
 
<pre>
 
you have to instantiate the method ``def foo(bar): pass`` in order to use this abstract class
 
you have to instantiate the method ``def foo(bar): pass`` in order to use this abstract class
 
</pre>
 
</pre>
  
Bad:
+
=== **kwargs, **args ===
 +
 
 +
[http://www.sphinx-doc.org/en/stable/rest.html#inline-markup Asterisks needs to be escaped] to avoid capture by emphasis markup. In case of multiple adjacent asterisks, escaping the first one is enough.
 +
 
 +
<u>Bad:</u>
 +
<pre>
 +
additional **kwargs are copied in the returned dictionary
 +
</pre>
 +
 
 +
<u>Good:</u>
 
<pre>
 
<pre>
you have to instantiate the method `def foo(bar): pass` in order to use this abstract class
+
additional \**kwargs are copied in the returned dictionary
 +
</pre>
 +
 
 +
=== Code cross-references ===
 +
 
 +
Backquotes are not enough to cross-reference a Python entity (class, function, module, etc.); you need to use [http://www.sphinx-doc.org/en/stable/domains.html Sphinx domains] for that, and in particular the [http://www.sphinx-doc.org/en/stable/domains.html#the-python-domain Python domain].
 +
 
 +
<u>Bad:</u>
 +
<pre>
 +
see the `do_something` function and the `swh.useless` module for more information
 +
</pre>
 +
 
 +
<u>Good:</u>
 +
<pre>
 +
see the :func:`do_something` function and the :mod:`swh.useless` module for more information
 +
</pre>
 +
 
 +
<u>Good:</u>
 +
<pre>
 +
you can avoid a long, fully-qualified anchor setting an :func:`explicit label <swh.long.namespace.function>` for a link
 +
</pre>
 +
 
 +
See also: the [http://www.sphinx-doc.org/en/stable/domains.html#cross-referencing-python-objects list of Python roles] that you can use to cross-reference Python objects. Note that you can (and should) omit the <code>:py:</code> prefix, as Python is the default domain.
 +
 
 +
Note also that when building Sphinx documentation for individual Software Heritage modules in isolation, cross-references to other modules will ''not'' be resolvable. But they will be resolvable when building the unified documentation from <code>swh-docs</code>.
 +
 
 +
== Napoleon ==
 +
 
 +
=== Docstring sections ===
 +
 
 +
See the [http://www.sphinx-doc.org/en/stable/ext/napoleon.html#docstring-sections list of docstring sections] supported by Napoleon. Everything else will ''not'' be typeset with a dedicated heading, you will have to do so explicitly using reStructuredText markup.
 +
 
 +
=== Args ===
 +
 
 +
Entries in Args section do ''not'' start with bullets, but just with argument names (as any other Napoleon section).
 +
Continuation lines should be indented.
 +
 
 +
<u>Bad:</u>
 +
<pre>
 +
Args:
 +
    - foo (int): first argument
 +
    - bar: second argument
 +
    - baz (bool): third argument
 +
</pre>
 +
 
 +
<u>Good:</u>
 +
<pre>
 +
Args:
 +
    foo (int): first argument
 +
    bar: second argument, which happen to have a fairly
 +
        long description of what it does
 +
    baz (bool): third argument
 +
</pre>
 +
 
 +
=== Returns ===
 +
 
 +
In Returns section you need to use ":" carefully as, if present, it will be interpreted as a separator between return type and description. Also, the description of return value should not start on the same line of "Returns:", but on the subsequent one, indented.
 +
 
 +
<u>Bad:</u>
 +
<pre>
 +
Returns:
 +
    this does not work (colon will be interpreted as type/desc separator), a dict with keys:
 +
 
 +
    - foo
 +
    - bar
 +
<pre>
 +
 
 +
<u>Good:</u>
 +
<pre>
 +
Returns:
 +
    this works (there is no colon) a dict with keys
 +
 
 +
    - foo
 +
    - bar
 +
</pre>
 +
 
 +
<u>Good:</u>
 +
<pre>
 +
Returns:
 +
    dict: this works again (''first'' colon identifies the type) a dict with keys:
 +
 
 +
    - foo
 +
    - bar
 +
</pre>
 +
 
 +
<u>Bad:</u>
 +
<pre>
 +
Returns: this is not good either, you need to start a paragraph
 +
</pre>
 +
 
 +
=== Raises ===
 +
 
 +
You need a ":" separator between exception names and their description.
 +
 
 +
<u>Bad:</u>
 +
<pre>
 +
Raises:
 +
    ValueError if you botched it
 +
    RuntimeError if we botched it
 +
</pre>
 +
 
 +
 
 +
<u>Good:</u>
 +
<pre>
 +
Raises:
 +
    ValueError: if you botched it
 +
    RuntimeError: if we botched it
 
</pre>
 
</pre>
 +
 +
== See also ==
 +
 +
* [[Python style guide]]
  
  

Latest revision as of 15:28, 22 January 2018

Here is a list of common gotchas when formatting Python docstrings for Sphinx and the Napoleon style.

Sphinx

Lists

All sorts of lists require an empty line before the first bullet and after the last one, to be properly interpreted as list. No indentation is required for list elements w.r.t. surrounding text, and line continuations should be indented like the first character after the bullet

Bad:

this is a bad example that will not be interpreted as a list
preceding text
- foo
- bar
- baz
following text

Good:

this is some text preceding the list

- foo
- bar
- baz
- this is a rather long-ish paragraph inserted in the list
  with line continuation
- qux

this is some text following the list

Bad:

- foo
- nested lists also requires empty lines, but they are missing here
  - inner list 1
  - inner list 2
- outer list continues here

Good:

surrounding text

- foo
- nested lists also requires empty lines

  - inner list 1
  - inner list 2

- outer list continues here

surrounding text

Verbatim source code

Verbatim code blocks, e.g., for code examples, requires double colon at the end of a line, then an empty line, and then the code block itself, indented:

Bad:

This does not work as there is a single column and no empty line before code:
    def foo(bar, baz):
        qux = bar + baz

        return qux

Good:

a nice example of python code follows::

    def foo(bar, baz):
        qux = bar + baz

        return qux

here we can restart text flow

Inline code samples use double backquotes, and not single ones.

Bad:

you have to instantiate the method `def foo(bar): pass` in order to use this abstract class

Good:

you have to instantiate the method ``def foo(bar): pass`` in order to use this abstract class

**kwargs, **args

Asterisks needs to be escaped to avoid capture by emphasis markup. In case of multiple adjacent asterisks, escaping the first one is enough.

Bad:

additional **kwargs are copied in the returned dictionary

Good:

additional \**kwargs are copied in the returned dictionary

Code cross-references

Backquotes are not enough to cross-reference a Python entity (class, function, module, etc.); you need to use Sphinx domains for that, and in particular the Python domain.

Bad:

see the `do_something` function and the `swh.useless` module for more information

Good:

see the :func:`do_something` function and the :mod:`swh.useless` module for more information

Good:

you can avoid a long, fully-qualified anchor setting an :func:`explicit label <swh.long.namespace.function>` for a link

See also: the list of Python roles that you can use to cross-reference Python objects. Note that you can (and should) omit the :py: prefix, as Python is the default domain.

Note also that when building Sphinx documentation for individual Software Heritage modules in isolation, cross-references to other modules will not be resolvable. But they will be resolvable when building the unified documentation from swh-docs.

Napoleon

Docstring sections

See the list of docstring sections supported by Napoleon. Everything else will not be typeset with a dedicated heading, you will have to do so explicitly using reStructuredText markup.

Args

Entries in Args section do not start with bullets, but just with argument names (as any other Napoleon section). Continuation lines should be indented.

Bad:

Args:
    - foo (int): first argument
    - bar: second argument
    - baz (bool): third argument

Good:

Args:
    foo (int): first argument
    bar: second argument, which happen to have a fairly
        long description of what it does
    baz (bool): third argument

Returns

In Returns section you need to use ":" carefully as, if present, it will be interpreted as a separator between return type and description. Also, the description of return value should not start on the same line of "Returns:", but on the subsequent one, indented.

Bad:

Returns:
    this does not work (colon will be interpreted as type/desc separator), a dict with keys:

    - foo
    - bar
<pre>

<u>Good:</u>
<pre>
Returns:
    this works (there is no colon) a dict with keys

    - foo
    - bar

Good:

Returns:
    dict: this works again (''first'' colon identifies the type) a dict with keys:

    - foo
    - bar

Bad:

Returns: this is not good either, you need to start a paragraph

Raises

You need a ":" separator between exception names and their description.

Bad:

Raises:
    ValueError if you botched it
    RuntimeError if we botched it


Good:

Raises:
    ValueError: if you botched it
    RuntimeError: if we botched it

See also