Code formatting with black

First of all, let's talk about formatting. It may sound like a minor issueand it generally is—but formatting won't affect your code performance. In a team, however, formatting matters. It improves readability and allows quicker reading through the code; good formatting highlights both typical and non-trivial areas of the code, helping to skim through trivial parts and focus on what's important. At the same time, formatting, if not automated, takes time and can cause arguments within a team, given that PEP8 does not have strict rules on any single aspect, and there are always matters of taste.

Now, there are quite a few tools that help with formattingand statically finding potential issues in codeincluding wrong syntax, non-used variables, and so on. These tools are called linters. Arguably the most popular linter for Python is flake8. Under the hood, it combines three linters:

  • PyFlake 8
  • pycodestyle (formerly PEP8)
  • McCabe

Another popular one is pylama, which combines seven linters, including the preceding ones, under the hood (it helps with linting docstrings, too!). Among others, there is Bandit, Radon, and MyPy, which specifically check code versus the given type hints. The good news is that many IDEs and code editors support running linters in the background, highlighting potential errors while you code. In order to use one in VS Code, just go to the command palette and type select linterVS Code will offer you a list of supported ones and will install and start running the chosen one all by itself.

You should definitely use linters! However, they were designed to inform you, and can be configurable (for example, to ignore specific errors). To automate the process furtherand make everyone on the team follow the same set of formatting ruleswe will introduce black.

black is designed to be a deterministic, automated formatter. It is easy to set up as a pre-commit hook (in other words, it will run automatically before every Git commit). Therefore, you don't need to change your personal formatting habits (or lack thereof)once the code is ready to be committed, black will take over and process everything. The best part is that black is not configurable, so there is no room for debates in the team regarding which formatting style is the best.

Let's check whether we can improve the readability of our wikiwwii package. black has a diff option and will show which files will be changed without changing them. Let's run this first:

  1. In the repository root folder, type the following in the Terminal:
black ./wikiwwii --diff

Quite a few lines were affectedblack replaces all the single quotation marks with doubles, makes sure that the comment symbol is separated from the code by two whitespaces, and so on and so forth. Where possible, it keeps elements on the same lineif not, it will keep every argument on the same indentation level.

  1. Let's run that without --diff to reformat our code. Feel free to revise all the changes via VS Code:

The preceding is a diff visualization (available via the GIT tab) of the file before and after black formatting (on the left, red lines and characters with a minus sign near the line number were removed/modified, while green ones with the plus sign on the right were added or changed).

I think you'll agree that those changes make sensesome of them are more important than others, but still, it definitely looks better than it did before.

  1. Now, how could we set that to run automatically? The easiest way is to leverage another package that deals with GitHub hooks, called pre-commit. In order to use it, we'll create a new file in the repository's root and name it .pre-commit-config.yamlInside, type the following settings:
repos:
-   repo: https://github.com/python/black
    rev: stable
    hooks:
    - id: black
      language_version: python3.7

With that setting in place, we can run pre-commit install, which will "deploy" the preceding settings into a hook.

  1. Finally, we can set a few settings that black accepts. As per the developers' recommendation, it is better to set that up via the pyproject.toml file:
[tool.black]
line-length = 88
target-version = ['py37', 'py38']
exclude = '''
/(
.eggs
| .git
| .hg
| .mypy_cache
| .tox
| .venv
| .dvc
| _build
| buck-out
| build
| dist
)/
'''

Now, everything should be in place. Let's try committing the changes.

For the first run, the black hook will take a few seconds to download and run. From now on, if the code is not formatted on a Git commit, it will be reformatted, and the commit process will halt (so that you can check the commit results). Once you feel safe to proceed, commit one more time, and you're all good. The best part is that once this code is on GitHub, every collaborator will have to format with those exact settings!

Lastly, we want to add black to our development dependencies in the pyproject.toml file so that our fellow developers get black as part of their development environment automatically:

[tool.poetry.dev-dependencies]
pytest = "^3.0"
pytest-cov = "^2.7"
pytest-azurepipelines = "^0.6.0"
black = "^19.3"

Don’t forget to run poetry add black and poetry update. For more on black (or, rather, the motivation behind it), please check out this video from PyCon 2019 by Łukasz Langa, the creator of black: https://www.youtube.com/watch?v=ia19n_yK4Qs.

Good code formatting is important, and settling on one style within the team is even more so. But what are the other dimensions of good code? And, more importantly, how can we measure them? That's what we'll talk about in the next section.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset