openflexure-microscope-server/apidocs/dev/python.md

94 lines
No EOL
3.7 KiB
Markdown

# Python Server Development
## Overview
Python code should be:
* Broken up into small, clear, testable functions.
* Documented with docstrings (For conventions see below).
* Type hinted
* Covered by unit tests (using [pytest](https://docs.pytest.org))
## Python environment, build, and dependencies
As of `v3` we specify dependencies in `pyproject.toml`. These are not currently frozen due to difficulties matching versions on different platforms. On Raspberry Pi, it's best to specify `--only-binary=:all:` when installing packages, to ensure libraries like `numpy` and `scipy` are not compiled from source (which takes many hours, and/or fails). Pinning dependencies with `requirements.txt` and/or `requirements.in` may happen in the future.
## Python: Formatting, linting, and tests
[Ruff](https://docs.astral.sh/ruff/) is used both for linting and formatting the codebase. Our custom linter rules are in our `pyproject.toml`.
> All of the commands below assume that you are running in the OFM virtual environment, i.e. you have run `ofm activate` on an OpenFlexure SD card, or `source .venv/bin/activate` on Linux, or `.venv/Scripts/activate`on Windows Powershell, or `.venv\Scripts\activate.bat` on Windows CMD.
**Before committing** you should lint and auto-format your code:
* To lint, run `ruff check` and manually fix any flagged issues
* To auto-format the Python code run `ruff format`
* To check for spelling errors `codespell .`
**Before pushing** please auto-format your code and also run the quality checks (linting, static analysis, and unit tests)
* All commands above
* `pytest`
* `mypy src`
We use several code analysis and formatting libraries in this project. Our CI will check each of these automatically, so ensuring they pass locally will save you time. Currently `ruff` is used for linting/formatting and `pytest` for unit tests.
To check your code before each commit we recommend putting the following script in your `.git/hooks` directory with the filename `pre-commit`.
```python
#!/bin/bash
set -e
function angrymessage()
{
RED='\033[1;31m'
NC='\033[0m' # No Color
printf "\n${RED}Not committing as ruff or spellcheck failed${NC}\n\n"
}
trap angrymessage ERR
ruff format --check
ruff check
codespell .
```
## Docstrings conventions.
We write docstrings in [reStructuredText](https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html), and process them with [pydoctor](https://pydoctor.readthedocs.io/).
For function arguments, return values, and exceptions we use the following style recognised by reStructuredText:
```python
def a_function(arg1: str, arg2: int) -> tuple[float, int]:
"""A one sentence summary, in imperative mood, ending with punctuation.
More detail after a blank line. This could be a whole paragraph.
When referring to ``code`` in reStructuredText used double backticks
:param arg1: This is the first argument, we can say everything we need to about it.
If the text wraps onto a new line, this line is indented.
:param arg2: This is the second argument.
:returns: Say what it returns without anything within the colons. If returning
multiple values, a bulleted list is a good idea - just make sure:
* It is indented to 1 level in
* There is a blank line before the bullets
* The bullet points are ``*`` not ``-``
"""
```
+The linter rules we use for docstrings are defined by [pydocstyle](https://docs.astral.sh/ruff/rules/#pydocstyle-d). We do not use rules D203, D213, D400 for reasons explained in our `pyproject.toml` file.
The documentation generated by pydoctor from docstrings can be viewed in any merge request (if the CI pipeline has passed) using the "View App" button.