Formatting Python Code Automatically¶
The Python ecosystem provides two packages that can simplify automated code formatting and are used by some software products. These tools are compliant with the Rubin style guide and can be adopted for any repository. The main caveat is that once this tooling is adopted for a specific repository, use of the tooling must be required for all subsequent pull requests and checked using GitHub Actions. This ensures that the code only goes through a style change for the initial adoption of the tooling.
Ordering imports¶
The isort package can be used to reorder imports in your Python code such that they are in alphabetical order and distinguish core python packages from other packages.
$ isort python
Formatting Python Code¶
We recommend the use of the black command for reformatting Rubin Python code once it has been decided that a repository should be converted.
Black calls itself the “uncompromising code formatter” and its entire purpose is to remove discussions of style from the debate.
You can write the code however you want in your editor but when black
runs on it there is no room for debate.
For this reason configuration options are limited.
The only configuration option that is recommended is to control the line length to meet the Rubin coding style.
black
is not compatible with the E203 error from Flake8.
Consequently any project using black
should disable E203.
Both black
and isort
can be configured by using a file pyproject.toml
in the repository root:
[tool.black]
line-length = 110
target-version = ["py38"]
[tool.isort]
profile = "black"
line_length = 110
The only configuration sets the line length and Python version, with isort
configured to be compatible with black
.
Installation¶
isort
and black
are both available from conda-forge and can be installed directly into a conda environment:
$ mamba install black isort
Of course they can also be installed using pip
.
They are not currently part of the default rubin-env
conda environment.
Once installed it is possible to configure editors to automatically apply these tools on save but care must be taken that this ability is not enabled globally.
GitHub Actions¶
When a repository is migrated to black
and isort
a GitHub Action should be installed.
A suitable Action py-formatting.yaml
is included in the LSST action templates repository.
It may need to be adjusted if there is no bin.src
directory.
Using pre-commit¶
To prevent a situation where code is being pushed to a repository and then being flagged immediately because it has not been formatted, the pre-commit command can be extremely useful.
This framework sets up a git
pre-commit hook and will run checks whenever git commit
is run.
If it finds a problem it will fix the code and let you try the commit again.
It can be installed directly from conda-forge.
To use pre-commit
the repository must be configured by including a file called .pre-commit-config.yaml
in the repository root directory.
The content describes which checks should be applied to every commit.
The one in daf_butler
looks like:
1repos:
2 - repo: https://github.com/pre-commit/pre-commit-hooks
3 rev: v4.4.0
4 hooks:
5 - id: check-yaml
6 args:
7 - "--unsafe"
8 - id: end-of-file-fixer
9 - id: trailing-whitespace
10 - repo: https://github.com/psf/black-pre-commit-mirror
11 rev: 23.9.1
12 hooks:
13 - id: black
14 # It is recommended to specify the latest version of Python
15 # supported by your project here, or alternatively use
16 # pre-commit's default_language_version, see
17 # https://pre-commit.com/#top_level-default_language_version
18 language_version: python3.11
19 - repo: https://github.com/pycqa/isort
20 rev: 5.12.0
21 hooks:
22 - id: isort
23 name: isort (python)
24 - repo: https://github.com/PyCQA/flake8
25 rev: 6.0.0
26 hooks:
27 - id: flake8
This example runs black
and isort
to check the formatting, removes trailing whitespace, lints any YAML files, and also ensures each file ends in a new line.
The checks can be enabled with:
$ pre-commit install
pre-commit installed at .git/hooks/pre-commit
pre-commit
installs everything it needs and ensures that the versions of the tools match the versions in the repository configuration file.
There is no need to install black
or isort
if you are relying on the pre-commit hook (which can be forced to run manually).
Running git commit
looks something like this if there is a problem:
$ git commit
Check Yaml...........................................(no files to check)Skipped
Fix End of Files.........................................................Passed
Trim Trailing Whitespace.................................................Passed
black....................................................................Failed
- hook id: black
- files were modified by this hook
reformatted python/lsst/daf/butler/core/utils.py
All done! ✨ 🍰 ✨
1 file reformatted.
isort (python)...........................................................Passed
In this situation the reformatted file will be present in the repository and git diff
will show the change.