File: docstrings.md

package info (click to toggle)
python-griffe 1.7.3-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 2,092 kB
  • sloc: python: 14,305; javascript: 84; makefile: 41; sh: 23
file content (335 lines) | stat: -rw-r--r-- 15,067 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
# Docstrings

Here are explanations on what docstrings are, and a few recommendations on how to write them. This guide uses the [Google-style](../../../reference/docstrings.md#google-style), because that is our preferred and recommended style, but you can also use any other supported style. Skip to the [Styles](#styles) section to learn about the existing docstring styles. We invite you to read their own style guides as they are full of examples and good advice.

## Definition

A docstring is a line or block of text describing objects such as modules, classes, functions and attributes. They are written below the object signature or assignment, or appear as first expression in a module:

```python title="module.py"
"""This is the module docstring."""

a = 0
"""This is an attribute docstring."""


def b():
    """This is a function docstring."""


class C:
    """This is a class docstring."""

    def d(self):
        """This is a method docstring."""
```

## Multi-line docstrings

Each docstring can span multiple lines if it is wrapped in triple double-quotes (which is generally the case and the official recommendation even for single-line docstrings):

```python
def function():
    """This is a longer docstring.

    It spans on multiple lines.
    Blank lines are allowed, too.
    """
```

When writing multi-line docstrings, it is recommended to write a short description on the first line, then separate the rest of the docstring with a blank line. The first line is called the **summary**, and the rest of docstring is called the **body**. The summary is useful to documentation generators and other tools to show the short description of an object.

## Markup

Docstrings are just text, so you can use any markup you want. The markup you choose will generally depend on what you decide to do with your docstrings: if you generate API documentation from your docstrings, and the documentation renderer expects Markdown, then you should write your docstrings in Markdown.

Examples of markups are [Markdown](https://daringfireball.net/projects/markdown/) (which has many different implementations and many different "flavors"), [reStructuredText](https://docutils.sourceforge.io/rst.html), [AsciiDoc](https://asciidoc.org/), and [Djot](https://djot.net/).

For example, if you are using [MkDocs](https://www.mkdocs.org) and [mkdocstrings](https://mkdocstrings.github.io/) to generate your API documentation, you should write your docstrings in Markdown. If you are using [Sphinx](https://www.sphinx-doc.org/en/master/), you should probably write your docstrings in reStructuredText, unless you are also using the [MyST](https://myst-parser.readthedocs.io/en/latest/index.html) extension.

Whatever markup you choose, try to stay consistent within your code base.

## Styles

Docstrings can be written for modules, classes, functions, and attributes. But there are other aspects of a Python API that need to be documented, such as function parameters, returned values, and raised exceptions, to name a few. We could document everything in natural language, but that would make it hard for downstream tools such as documentation generators to extract information in a structured way, to allow dedicated rendering such as tables for parameters.

To compensate for the lack of structure in natural languages, docstring "styles" emerged. A docstring style is a micro-format for docstrings, allowing to structure the information by following a specific format. With the most popular Google and Numpydoc styles, information in docstrings is decomposed into **sections** of different kinds, for example "parameter" sections or "return" sections. Some kinds of section then support documenting multiple items, or support a single block of markup. For example, we can document multiple parameters in "parameter" sections, but a "note" section is only composed of a text block.

Structuring the information in sections and items allows documentation-related tools to extract and provide this information in a structured way, by parsing the docstrings according to the style they follow. Griffe has parsers for [Google-style](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings), [Numpydoc-style](https://numpydoc.readthedocs.io/en/latest/format.html), and [Sphinx-style](https://sphinx-rtd-tutorial.readthedocs.io/en/latest/docstrings.html) docstrings. See the complete reference for these parsers and styles in the [Docstrings reference](../../../reference/docstrings.md). We recommend that you read the style guides mentioned here as they are full of examples and good advice too.

<div class="grid cards" markdown>
<div markdown>

```python title="Google-style"
def greet(name: str, end: str = "!") -> None:
    """Greet someone.

    Parameters:
        name: The name to greet.
        end: The punctuation mark at the end.

    Note:
        Greetings are cool!
    """
    print(f"Hey {name}{end}")



```

<!-- The invisible character above is here on purpose, to make both divs the same height. -->

</div>
<div markdown>

```python title="Numpydoc-style"
def greet(name: str, end: str = "!") -> None:
    """Greet someone.

    Parameters
    ----------
    name
        The name to greet.
    end
        The punctuation mark at the end.

    Note
    ----
    Greetings are cool!
    """
    print(f"Hey {name}{end}")
```

</div>
</div>

Our preferred style for docstrings is the **Google-style**, because it is in our opinion the most markup-agnostic style: it is based on any kind of markup or documentation generator. Our second choice would be the Numpydoc-style, for its readability.

For the adventurers, have a look at [PEP 727](https://peps.python.org/pep-0727/) (draft) and [griffe-typingdoc](https://mkdocstrings.github.io/griffe-typingdoc/), a Griffe extension to support PEP 727. PEP 727 proposes an alternative way to provide information in a structured way, that does not rely on a docstring micro-format. It takes advantage of `typing.Annotated` to attach documentation to any type-annotated object, like attributes, parameters and returned values. With PEP 727, docstrings styles and their sections aren't required anymore, and docstrings can be written in plain markup, without following any particular style. This makes it easier for tools like Griffe who then don't have to parse docstrings *at all*. The PEP is a bit controversial (lots of different opinions), so we invite you to make your own opinion by looking at real-world projects using it, such as [FastAPI](https://github.com/tiangolo/fastapi/blob/master/fastapi/applications.py), or by reading the (very-long) [discussion on discuss.python.org](https://discuss.python.org/t/pep-727-documentation-metadata-in-typing/32566/17). The PEP was actually written by FastAPI's author, Sebastián Ramírez.

```python title="PEP 727"
from typing_extensions import Annotated, Doc


def greet(
    name: Annotated[str, Doc("The name to greet."),
    end: Annotated[str, Doc("The punctuation mark at the end.")] = "!",
) -> None:
    """Greet someone.

    > [!NOTE]
    > Greetings are cool!
    """ # (1)!
    print(f"Hey {name}{end}")
```

1. Here we use the [GitHub syntax](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts) for a "note" callout. It assumes our documentation renderer supports this syntax. The point is that we rely purely on Markdown rather than docstrings styles.

## General tips

Your docstrings will typically be used to document your API, either on a deployed (static) website, or locally, on the command line or in a Python interpreter. Therefore, when writing your docstrings, you should address the right audience: the users of your code. Try to stay succinct and give clear examples. Docstrings are not really the place to explain architectural or technical decisions made while developing the project: this information, while extremely valuable, is better written in *code comments*, where the audience is other developers working on the code base.

Your docstrings will typically again be read online (HTML) or other types of documents such as manual pages or PDFs. Make sure to write complete sentences, with correct punctuation. That means for example, to start each parameter description with a capital letter, and to end it with a period.

When documenting objects acting as namespaces (modules, classes, enumerations), prefer documenting each attribute separately than with an Attributes section in the namespace object docstring. For example, add a docstring to each enumeration value rather than describing each value in the docstring of the enumeration class.

## Modules

Module docstrings should briefly explain what the module contains, and for what purposes these objects can be used. If the documentation generator you chose does not support generating member summaries automatically, you might want to add docstrings sections for attributes, functions, classes and submodules.

```python title="package/__init__.py"
"""A generic package to demonstrate docstrings.

This package does not really exist, and is only used as a demonstration purpose for docstrings.
Anyway, this package contains the following API, exposed directly at the top-level,
meaning you can import everything from `package` directly.

Attributes:
    ghost: A ghost wandering in this desolated land.
    dummy: A dummy you can practice on. Not for ghosts.

Classes:
    Ghost: Ah, so this is where our ghost comes from.
        Maybe create some additional ghosts so they can pass the time together?

Functions:
    deploy(): Deploy something on the web (we're not sure what exactly).
"""
```

Do the same thing for every other module of the package, except if you are [hiding your module layout](public-apis.md#module-layout).

## Classes, methods, properties

Class docstrings follow the same logic as module docstrings. Explain what the class is used for, and maybe show a few of its attributes and methods thanks to sections of the same name. A class is already more concrete than a module, so we can maybe start adding usage examples too. Such examples should only show how to create instances of the class. Examples of use for methods can be written in each respective method.

```python
class Ghost:
    """Ghosts that wander the earth.

    Ghosts are meant to... we're actually unsure.
    All we know is that, as a user, you might find it amusing to instantiate
    a few of them and put them together to see what they do.

    Methods:
        wander: Wander the earth.
        spook: Spook living organisms.
        pass_through: Pass through anything.

    Examples:
        Create a new ghost with a cool nickname:

        >>> ghost = Ghost(nickname="Rattlesnake")
    """

    def wander(self) -> None:
        """Wander the earth.
        
        That's it, really.

        Examples:
            >>> ghost.wander()
        """
        ...

    @property
    def weight(self) -> int:
        """The ghost's weight (spoiler: it's close to 0)."""
        ...
```

Note that blocks of lines starting with `>>>` or `...` are automatically parsed as code blocks by Griffe, until a blank line is found. This only works in Examples (plural!) sections. If you rely on [Python-Markdown](https://python-markdown.github.io/) to convert Markdown to HTML (which is the case for MkDocs), you can use the [markdown-pycon](https://pawamoy.github.io/markdown-pycon/) extension to recognize such `pycon` code blocks anywhere, without having to wrap them in fences. You can also choose to use explicit fences everywhere:

````python
    """
    Examples:
        Create a new ghost with a cool nickname:

        ```pycon
        >>> ghost = Ghost(nickname="Rattlesnake")
        ```
    """
````

## Functions

Function and method docstrings will typically describe their parameters and return values. For generators, it's also possible to describe what the generator yields and what it can receive, though the latter is not often used.

```python
import datetime
from typing import Generator, Iterator


class GhostOlympicGames:
    ...


class GOGTicket:
    ...


def organize_gog(date: datetime.date) -> GhostOlympicGames:
    """Organize Olympic Games for Ghosts.

    The ghost world is much simpler than the living world,
    so it's super easy to organize big events like this.

    Parameters:
        date: The date of the games.

    Returns:
        The prepared games.
    """
    ...


def yield_athletes(quantity: int) -> Iterator[Ghost]:
    """Yield a certain quantity of athletes.

    Parameters:
        quantity: How many ghost athletes you want.
    
    Yields:
        Ghost athletes. They're just regular ghosts.
    """
    ...



def gog_tickets_factory() -> Generator[GOGTicket, int, None]:
    """Generate tickets for the GOG.

    We value fairness: tickets are priced randomly.
    Unless we send a specific price to the generator.

    Yields:
        Tickets for the games.

    Receives:
        Price for the next ticket, in ghost money (???).
    """
    ...
```

## Attributes

Attribute docstrings are written below their assignment. As usual, they should have a short summary, and an optional, longer body.

```python
GHOST_MASS_CONSTANT: float = 1e-100
"""The ghost mass constant.

This is a very small number. Use it scientifically
for all ghost-related things.

Note:
    There is actually nothing scientific about any of this.
""" # (1)!
```

1. Our `Note` section here is parsed as an admonition. See [Google-style admonitions](../../../reference/docstrings.md#google-admonitions) for reference.

Class and instance attributes can be documented the same way:

```python
class GhostTown:
    instances: str
    """All the existing towns."""

    def __init__(self, name: str, size: int) -> None:
        self.name = name
        """The town's name."""

        self.size = size
        """The town's size."""
```

## Exceptions, warnings

Callables that raise exceptions or emit warnings can document each of these exceptions and warnings. Documenting them informs your users that they could or should catch the raised exceptions, or that they could filter or configure warnings differently. The description next to each exception or warning should explain how or when they are raised or emitted.

```python
def verify_spirit_chest():
    """Do a verification routine on the spirit chest.

    Raises:
        OverflowError: When the verification failed
            and all the ghosts escaped from the spirit chest.
    """
    ...


def negotiate_return_to_the_spirit_chest():
    """Negotiate with ghost for them to return in the spirit chest.

    Warns:
        ResourceWarning: When the ghosts refuse to go back in the chest
            because the chest is too tight.
    """
    ...
```

## Going further

There are more sections and more features to discover and use. For a complete reference on docstring styles syntax, see our [reference](../../../reference/docstrings.md).