Code Style Guidelines

Black

We use the black coding style, a flavour of PEP-8 for Python.

We use a pre-commit-hook to apply this style before committing, so you don’t have to bother about formatting. Just code how you feel comfortable and let the tool do the work for you (see Pre-commit Hooks).

If you want to apply the formatting without committing, use our developer tool tools/black.sh:

./tools/black.sh

DjLint

We use djlint to format our Django HTML templates.

We use a pre-commit-hook to apply this style before committing, so you don’t have to bother about formatting. Just code how you feel comfortable and let the tool do the work for you (see Pre-commit Hooks).

If you want to apply the formatting without committing, use our developer tool tools/djlint.sh:

./tools/djlint.sh

Prettier

We use prettier to format our static JS and CSS files.

We use a pre-commit-hook to apply this style before committing, so you don’t have to bother about formatting. Just code how you feel comfortable and let the tool do the work for you (see Pre-commit Hooks).

If you want to apply the formatting without committing, use our developer tool tools/prettier.sh:

./tools/prettier.sh

Linting

In addition to black, we use pylint to check the code for semantic correctness. Run pylint with our developer tool tools/pylint.sh:

./tools/pylint.sh

When you think a warning is a false positive, add a comment (see Messages control):

def some_function(
    something: SomeModel,  # pylint: disable=unused-argument
    *args,
    **kwargs) -> None:
    # pylint: disable=too-many-branches

Note

Please use the string identifiers (unused-argument) instead of the alphanumeric code (W0613) when disabling warnings.

Hint

If you want to run both tools at once, use our developer tool tools/code_style.sh:

./tools/code_style.sh

Docstrings

Please add docstrings in the sphinx format (see Writing docstrings):

"""
[Summary]

:param [ParamName]: [ParamDescription], defaults to [DefaultParamVal]
...

:return: [ReturnDescription]

:raises [ErrorType]: [ErrorDescription]
...
"""

Hint

In the model documentation, the parameters are not required, because they are automatically derived from the model field type.

Whenever you want to document module/class attributes which are not parameters (i.e. because they are not passed to the __init__()-function or contain static values), use inline comments:

#: Description of attribute
attribute = "value of this attribute"

See the configuration files settings and conf or constants for examples.

my[py]

We use my[py] to check type annotations of our python code.

We use a pre-commit-hook to apply this check before committing, so TypeErrors will be prevented. Just code how you feel comfortable and let the tool do the work for you (see Pre-commit Hooks).

If you want to apply the formatting without committing, use our developer tool tools/mypy.sh:

./tools/mypy.sh

Note

If you’re unsure about a type, temporarily add reveal_type(variable) to the code and run ./tools/mypy.sh, the tool will then tell you what type it would guess.

Any imports that are only needed during type checking should be wrapped into a if TYPE_CHECKING: block. For that the variable TYPE_CHECKING should be imported from typing.

The line from __future__ import annotations must be the first line (after the module docstring) of any new python file. (This activates PEP 563 for any python version where it is not already active by default, so we need to keep this until all python versions we support implement it. At the time of writing the first python version where this is not just optional is still mentioned as TBD)

If a third party library is incorrectly typed or missing type hints, and this results in errors you cannot fix, then you can add # type: ignore[<error-class>] (where the <error-class> is the identifier of the error you’re experiencing, e.g. attr-defined) in the end of the line where the error is thrown.

Shellcheck

All developer tools in the tools directory have to comply to the standards of shellcheck (see ShellCheck wiki). Shellcheck is run both in the CI-pipeline of CircleCI (see shellcheck/check) and as pre-commit hook (see Pre-commit Hooks) and can be run locally with:

shellcheck -x tools/*

False positives can be ignored with the syntax:

# shellcheck disable=SC2059