Code quality and static typing
We use pre-commit to ensure common code standards and style, and use mypy to provide
static typing of the pyrealm codebase.
Using pre-commit
As described in the developer overview, pre-commit is installed as
part of the pyrealm developer dependencies and so can be set up to run simply using:
poetry run pre-commit install
poetry run pre-commit run --all-files
This can take a while on the first run, and when the configuration updates, as the tool
needs to install or update all the hooks that are applied to changes within a commit.
Usually the hooks only run on files changed by a particular git commit but using
pre-commit run --all-files scans the entire codebase and is a commonly used check to
make sure all is well.
The pre-commit configuration
The file
.pre-commit-config.yaml
contains the pre-commit hooks used by pyrealm. The configuration file contains links
to each individual hook but in overview:
check for merge conflictsChecks for remaning
gitmerge conflict markers in code files.debug statements (python)Checks for debugger imports and
breakpoint()calls, which should not end up in released code.pyupgradeUpdates Python syntax to the current Python 3.10 syntax.
isortEnforces a consistent sort order and formatting of package imports in modules.
blackEnforces a common code formatting across the codebase. This can be irritating but it keeps code neatly formatted and avoids code changes that are simply alternate formatting.
flake8This runs the [`flake8](https://flake8.pycqa.org/en/latest/) tool to detect a very wide range of common programming issues. We use the default set of plugins to check: PEP 8 style recommendations, code complexity and common programming errors. It is also configured to check docstrings on code objects using [`pydocstyle`](https://www.pydocstyle.org/en/stable/error_codes.html) via the `flake8-docstrings` plugin.
mypyRuns static typing checks to ensure that the types of function arguments and return values are declared and are compatible. See below for more information.
markdownlintChecks all markdown files for common formatting issues.
Output and configuration
When pre-commit runs, you may see some lines about package installation and update,
but the key information is the output below, which shows the status of the checks set up
by each hook:
check for merge conflicts................................................Passed
debug statements (python)................................................Passed
pyupgrade................................................................Passed
isort....................................................................Passed
black....................................................................Passed
flake8...................................................................Passed
mypy.....................................................................Passed
markdownlint.............................................................Passed
Updating pre-commit
The hooks used by pre-commit are constantly being updated to provide new features or
to update code to deal with changes in the implementation. You can update the hooks
manually using pre-commit autoupdate, but the configuration is regularly updated
through our GitHub Actions workflows
Typing with mypy
Unlike many programming languages, Python does not require variables to be declared as being of a particular type. For example, in C++, this code creates a variable that is explicitly an integer and a function that explicitly requires an integer and returns an integer value. This is called typing.
int my_integer = 15;
int fun(int num) {
printf("num = %d \n", num);
return 0;
}
Python does not require explicit typing. That can be very useful but it can also make it
very difficult to be clear what kinds of variables are being used. The pyrealm project
requires static typing of the source code: the syntax for this started with PEP
484 and a set of quality assurance tools have
developed to help support clear and consistent typing. We use
mypy to check static typing. It does take a
bit of getting used to but is a key tool in maintaining clear code and variable
structures.
Supressing checking
The pre-commit tools sometimes complain about things that we do not want to change.
Almost all of the tools can be told to suppress checking, using comments with a set
format to tell the tool what to do.
This should not be done lightly: we are using these QA tools for a reason.
isortallows various# isort: skipaction commentsblackallows lines or section to be left untouched using, for example# fmt: skip.flake8uses the# noqacomment to suppress warnings. Forpyrealmyou should explicitly list the errors to be ignored, so that other errors are not missed:# noqa D210, D415.mypyuses the syntax# type: ignorecomment to suppress warnings. Again,pyrealmrequires that you provide the specificmypyerror code to be ignored to avoid missing other issues:# type: ignore[operator].markdownlintcatches issues in Markdown files and uses a range of HTML comment tags to suppress format warnings. An example is<!-- markdownlint-disable-line MD001 -->and the tool homepage provides a list of the MD rule0 codes that can be used to surpress warnings.