Skip to content

Add: typing section to docstring page in guide #76

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Apr 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ tmp/
.nox
__pycache__
*notes-from-review.md
*.idea*
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Document the code in your package's API using docstrings

## What is an API?

API stands for **A**pplied **P**rogramming **I**nterface. When
discussed in the context of a (Python) package, the API refers to
the functions, methods and classes that a package maintainer creates for users.
Expand All @@ -14,13 +15,14 @@ using the package's API.
Package APIs consist of functions and/or classes, methods and attributes that create a user interface (known as the API).

## What is a docstring and how does it relate to documentation?

In Python a docstring refers to text in a function, method or class
that describes what the function does and its inputs and outputs. Python programmers usually refer to the inputs to functions as ["parameters"](https://docs.python.org/3/glossary.html#term-parameter) or ["arguments"](https://docs.python.org/3/faq/programming.html#faq-argument-vs-parameter), and the outputs are often called "return values"

The docstring is thus important for:

* When you call `help()` in Python, for example, `help(add_numbers)`, the text of the function's docstring is printed. The docstring thus helps a user better understand how to applying the function more effectively to their workflow.
* When you build your package's documentation, the docstrings can be also used to automagically create full API documentation that provides a clean view of all its functions, methods, attributes, and classes.
- When you call `help()` in Python, for example, `help(add_numbers)`, the text of the function's docstring is printed. The docstring thus helps a user better understand how to applying the function more effectively to their workflow.
- When you build your package's documentation, the docstrings can be also used to automagically create full API documentation that provides a clean view of all its functions, methods, attributes, and classes.

```{tip}
Example API Documentation for all functions, methods, attributes and classes in a package.
Expand All @@ -31,31 +33,32 @@ Example API Documentation for all functions, methods, attributes and classes in
## Python package API documentation

If you have a descriptive docstring for every user-facing
class, method, attribute and/or function in your package (*within reason*), then your package's API is considered well-documented.
class, method, attribute and/or function in your package (_within reason_), then your package's API is considered well-documented.

In Python, this means that you need to add a docstring for
every user-facing
class, method, attribute and/or function in your package (*within reason*) that:
class, method, attribute and/or function in your package (_within reason_) that:

* Explains what the function, method, attribute or class does
* Defines the `type` inputs and outputs (ie. `string`, `int`, `np.array`)
* Explains the expected output `return` of the object, method or function.
- Explains what the function, method, attribute or class does
- Defines the `type` inputs and outputs (ie. `string`, `int`, `np.array`)
- Explains the expected output `return` of the object, method or function.

### Three Python docstring formats and why we like NumPy style

There are several Python docstring formats that you can chose to use when documenting
your package including:

* [NumPy-style](https://numpydoc.readthedocs.io/en/latest/format.html#docstring-standard)
* [google style](https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html)
* [reST style](https://sphinx-rtd-tutorial.readthedocs.io/en/latest/docstrings.html)
- [NumPy-style](https://numpydoc.readthedocs.io/en/latest/format.html#docstring-standard)
- [google style](https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html)
- [reST style](https://sphinx-rtd-tutorial.readthedocs.io/en/latest/docstrings.html)

<!-- https://peps.python.org/pep-0287/ - 2002 pep 287-->

We suggest using [NumPy-style docstrings](https://numpydoc.readthedocs.io/en/latest/format.html#docstring-standard) for your
Python documentation because:

* NumPy style docstrings are core to the scientific Python ecosystem and defined in the [NumPy style guide](https://numpydoc.readthedocs.io/en/latest/format.html). Thus you will find them widely used there.
* The Numpy style docstring is simplified and thus easier-to-read both in the code and when calling `help()` in Python. In contrast, some feel that reST style docstrings is harder to quickly scan, and can take up more lines of code in modules.
- NumPy style docstrings are core to the scientific Python ecosystem and defined in the [NumPy style guide](https://numpydoc.readthedocs.io/en/latest/format.html). Thus you will find them widely used there.
- The Numpy style docstring is simplified and thus easier-to-read both in the code and when calling `help()` in Python. In contrast, some feel that reST style docstrings is harder to quickly scan, and can take up more lines of code in modules.

```{tip}
If you are using NumPy style docstrings, be sure to include the [sphinx napoleon
Expand Down Expand Up @@ -96,7 +99,9 @@ def extent_to_json(ext_obj):
```

<!-- I can't seem to get doc targets across pages to work-->

(docstring_best_practice)=

### Best: a docstring with example use of the function

This example contains an example of using the function that is also tested in
Expand Down Expand Up @@ -156,10 +161,11 @@ output of the `es.extent_to_json(rmnp)` command can even be tested using
doctest adding another quality check to your package.
```


## Using doctest to run docstring examples in your package's methods and functions

<!-- This link isn't working no matter how i create the target. not sure
why -->

Above, we provided some examples of good, better, best docstring formats. If you are using Sphinx to create your docs, you can add the [doctest](https://www.sphinx-doc.org/en/master/usage/extensions/doctest.html) extension to your Sphinx build. Doctest provides an additional; check for docstrings with example code in them.
Doctest runs the example code in your docstring `Examples` checking
that the expected output is correct. Similar to running
Expand All @@ -179,7 +185,6 @@ Below is an example of a docstring with an example.
doctest will run the example below and test that if you provide
`add_me` with the values 1 and 3 it will return 4.


```python
def add_me(aNum, aNum2):
"""A function that prints a number that it is provided.
Expand Down Expand Up @@ -207,3 +212,74 @@ def add_me(aNum, aNum2):


```

## Adding type hints to your docstrings

In the example above, you saw the use of numpy-style docstrings to describe data types
that are passed into functions as parameters or
into classes as attributes. In a numpy-style docstring you add those
types in the Parameters section of the docstring. Below you can see that
the parameter `aNum` should be a Python `int` (integer) value.

```python
Parameters
----------
aNum : int
An integer value to be printed
```

Describing the expected data type that a function or method requires
helps users better understand how to call a function or method.

Type-hints add another layer of type documentation to your code. Type-hints
make make it easier for new developers, your future self or contributors
to get to know your code base quickly.

Type hints are added to the definition of your function. In the example below, the parameters aNum and aNum2 are defined as being type = int (integer).

```python
def add_me(aNum: int, aNum2: int):
"""A function that prints a number that it is provided.
```

You can further describe the expected function output using `->`. Below
the output of the function is also an int.

```python
def add_me(aNum: int, aNum2: int) -> int:
"""A function that prints a number that it is provided.
```

### Why use type hints

Type hints:

- Make development and debugging faster,
- Make it easier for a user to see the data format inputs and outputs of methods and functions,
- Support using static type checking tools such as [`mypy`](https://mypy-lang.org/) which will check your code to ensure types are correct.

You should consider adding type hinting to your code if:

- Your package performs data processing,
- You use functions that require complex inputs
- You want to lower the entrance barrier for new contributors to help you with your code.

```{admonition} Beware of too much type hinting
:class: caution

As you add type hints to your code consider that in some cases:

- If you have a complex code base, type hints may make code more difficult to read. This is especially true when a parameter’s input takes multiple data types and you list each one.
- Writing type hints for simple scripts and functions that perform obvious operations don't make sense.
```

### Gradually adding type hints

Adding type hints can take a lot of time. However, you can add
type hints incrementally as you work on your code.

```{tip}
Adding type hints is also a great task for new contributors. It will
help them get to know your package's code and structure better before
digging into more complex contributions.
```