Documentation Convention
This document states the convention that we follow for writing Documentation and especially docstrings for
classes and functions for sosw
package. This convention is based on
[https://www.python.org/dev/peps/pep-0008/](PEP8), with minor styling changes listed below.
Basics
We use
sphinx
package to compile documentation.We use
sphinx.autodoc
extention to automatically parse the Python code and extract docstrings..rst
wins against.md
Make docstrings readable both in the code and in HTML. Use new lines and tabs to beautify the source of docstrings even if they are not really required.
Richard wins against Winnie.
Building the docs
You can locally build the docs and use the built in python web server to view the html version directly from localhost in your preferred browser.
sphinx-build -ab html ./docs ./sosw-rtd; (cd sosw-rtd && python -m http.server)
Common Sense Boosters
Document for humans. You will have to read this one day later.
Read other good docs to notice some good practices.
Do not be afraid to use some new markup features not yet used in our documentation.
Create labels where required, if you feel that you will need it one day from other doc.
Do not make pull requests if your docstrings do not compile in Sphinx without warnings.
Structure
index.rst
of each Lambda should reside in ./docs/
. It should have the basic Readme information and links
to the documentation of external components used in the Lambda. At the end of the file, you should include the
autodoc directives for each module of your function (the minimum of app.py
)
If you add schemas or images (good practice) include them in ./docs/images/
and use appropriately.
Example of Docstring
def hello(name, age, tags=None):
"""
User friendly welcome function.
Uses `name` and `age` to salute user.
This is still same line of documentation.
While this is a new paragraph.
Note that `rst` is sensitive to empty lines and spaces.
Some code Example:
.. code-block:: python
def hello():
return "world"
This is paragraph 3.
* And some bullet list
* With couple rows
Now go parameters. PyCharm adds them automatically.
:param str name: User name of type string.
:param tags: Types are not required, but this is a good
practice to show what you expect.
:param age: You can also specify multiple types, with a
little different syntax.
Note that empty lines do not matter here for
`sphinx`, but good for code readability.
:type age: int | float
:rtype: dict
:return: You can specify type of return value in
`rtype` (if it is uncertain).
"""
return f"Hello {'bro' if age > 10 else 'kid'}"
I hope this example above was useful. Note the indention and spacing again. Now we are out of code-block. Do not get frustrated with the 80 chars width that I used in the example. This is just to show this code-block nicely when displayed as code in rendered HTML. Our convention is 120 characters max width.
Here is the compiled version of the example docstring from above:
- docs.hello.hello(name, age, tags=None)[source]
User friendly welcome function. Uses name and age to salute user. This is still same line of documentation.
While this is a new paragraph. Note that rst is sensitive to empty lines and spaces.
Some code Example:
def hello(): return "world"
This is paragraph 3.
And some bullet list
With couple rows
Even 3 rows
Now go parameters. PyCharm adds them automatically.
- Parameters:
name (str) – User name of type string.
tags – Types are not required, but this is a good practice to show what you expect.
age (int | float) – You can also specify multiple types, with a little different syntax. Note that empty lines do not matter here for sphinx, but good for code readability.
- Return type:
dict
- Returns:
You can specify type of return value in rtype (if it is uncertain).
End of the compiled example.
Configuration
There are some bugs with compiling documentation for components. Sphinx recognises the module components correctly, but then in notices the same module during import from autodoc of lambdas. And fails to import manually.
One workaround - create a symlink inside the lambdas (as init-lambda would normally do) and then include :automodule: for components directly in Lambdas index.
Another option is to rename the components to smth else like components-tmp and compile the documentation for it. But you will have to take care about the links directly in the documentation of lambdas in the second case.