Write Effective Docstrings
The quality of your API reference depends directly on the docstrings in your source code. Great Docs renders them as-is, so what you write is what your users see. This recipe covers practical tips for writing docstrings that look good in the rendered documentation.
Choose a Style and Be Consistent
Great Docs supports three docstring styles. Pick one for your entire package and stick with it. Mixing styles within a project leads to inconsistent rendering.
NumPy style uses section headers with underlines. It reads well in both the source code and the rendered docs:
def connect(host: str, port: int = 5432) -> Connection:
"""Open a connection to the database server.
Establishes a TCP connection and performs the initial handshake.
The connection must be closed explicitly or used as a context manager.
Parameters
----------
host
The server hostname or IP address.
port
The port number. Defaults to 5432 for PostgreSQL.
Returns
-------
Connection
An open connection ready for queries.
Raises
------
ConnectionError
If the server is unreachable or the handshake fails.
"""
...Google style uses indented sections with colons. It is more compact:
def connect(host: str, port: int = 5432) -> Connection:
"""Open a connection to the database server.
Establishes a TCP connection and performs the initial handshake.
The connection must be closed explicitly or used as a context manager.
Args:
host: The server hostname or IP address.
port: The port number. Defaults to 5432 for PostgreSQL.
Returns:
An open connection ready for queries.
Raises:
ConnectionError: If the server is unreachable or the handshake fails.
"""
...Great Docs auto-detects your style during great-docs init. You can also set it manually in great-docs.yml:
great-docs.yml
parser: numpy # or: google, sphinxWrite a Good Summary Line
The first line of every docstring is the summary. It appears in the API reference sidebar tooltips and in search results. Keep it short (one line) and action-oriented:
# Good: starts with a verb, one line
def save(data: dict, path: str) -> None:
"""Write data to a JSON file."""
# Less useful: vague or overly long
def save(data: dict, path: str) -> None:
"""This function is used for saving data objects to disk in JSON format with pretty-printing."""Add an Extended Description
After the summary, add a blank line and then one or more paragraphs of explanation. This is where you describe behavior, edge cases, and usage context:
def retry(func, max_attempts: int = 3, delay: float = 1.0):
"""Retry a function call on failure.
Calls the function up to `max_attempts` times. If the function raises
an exception, it waits `delay` seconds before retrying. The delay
doubles after each failed attempt (exponential backoff).
If all attempts fail, the last exception is re-raised.
Parameters
----------
func
The callable to retry.
max_attempts
Maximum number of attempts before giving up.
delay
Initial delay in seconds between retries.
"""
...Document Parameters Meaningfully
Avoid restating the parameter name or type as the description. Instead, explain what the parameter controls and mention default behavior or constraints:
# Useful: explains what the parameter does
"""
Parameters
----------
timeout
Maximum seconds to wait for a response. Set to 0 to disable
the timeout entirely. Defaults to 30.
"""
# Less useful: just repeats the name
"""
Parameters
----------
timeout
The timeout value.
"""Use Cross-References
If your docstring mentions other symbols from your package, use the linking syntax so readers can navigate directly to the related page. The simplest form is inline code, which is auto-linked when it matches a documented symbol:
class Store:
"""Persistent key-value store.
Use `Connection` to open a store, or call `Store.close` to
release resources when done.
"""
...For qualified names, use ~~ to shorten the display: `~~mypackage.Connection` renders as Connection with a link.
See the Cross-Referencing page for the full linking syntax.
Docstrings That Do Not Render Well
A few patterns cause problems in the rendered output. Avoid very long summary lines that wrap awkwardly in the sidebar. Avoid using reStructuredText constructs (like :param: or .. note::) unless your parser is set to sphinx. And avoid leaving parameters undocumented when other parameters in the same function are documented, as this creates an inconsistent appearance.