diff --git a/.gitignore b/.gitignore index 46e3d0d82..49fb9bc99 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ tmp/ .nox __pycache__ *notes-from-review.md +*.idea* diff --git a/documentation/write-user-documentation/document-your-code-api-docstrings.md b/documentation/write-user-documentation/document-your-code-api-docstrings.md index 6b964357a..10bb75f86 100644 --- a/documentation/write-user-documentation/document-your-code-api-docstrings.md +++ b/documentation/write-user-documentation/document-your-code-api-docstrings.md @@ -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. @@ -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. @@ -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) + 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 @@ -96,7 +99,9 @@ def extent_to_json(ext_obj): ``` + (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 @@ -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 + + 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 @@ -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. @@ -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. +```