This article assumes you are already familiar with flake8. Probably you faced at least one of the challenges below related to:
- adoption requires a lot of code reformatting
- some rules contradict each other, like
- different rules on different projects
- newer versions requiring rework
- … why I am wasting my time with linting
Still hacking did not help migrating codebases to pass various PEP rules and neither preventing divergent preferences across projects.
Code formatting tools for Python existed for a very long time, with autopep8 and yapf being quite well known. Still, they came with other issues attached to them, so they did not manage to get too much popularity.
But then Black came to the picture, with a very bold tagline Black is the uncompromising Python code formatter as a direct reference to the famous Ford quote. To summarize, sometimes a lack of options is a feature by itself. It did work for Ford, and also worked for Black.
The project was even moved under Python Software Foundation back in 2019, which is a confirmation of its importance to the Python community. The list of famous packages adopting it grows every day, including Django, PyTest, tox, pandas, sqlalchemy, virtualenv. I doubt you have a single project that does not list at least two of these as upstream dependencies.
Where is the value of consistent code style
Many argue that coding style is a personal decision. This may be true if you work like a hermit and you are the only contributor of your project.
I see personal styles as being hindering collaboration and contributions to open source projects. Why wasting time debating code style during a code review when we can spend time reviewing code functionality instead?
That is one of the reasons why I was a big supporter of using linters. They offload this boring task and avoid getting personal. When the linting job fails in CI (if they missed checking locally), the developer will know what to do to fix it, without having to bother another human.
Would black introduce bugs in my source
Black will not ever change the behavior of your code after reformating because it assures that the Python bytecode remains the same. So, it does reformat only stuff that do not affect how code runs.
Does back replace flake8
Not at all. Black only reformats, you still run flake8 to check for various issues not covered by black. Flake8 very close to be perfectly compatible with black.
Configuring flake8 to meet black style
As you can see below, there are very few changes needed. Keep in mind that
your flake8 config may be located in another location. I mention here only
the recommended one. For example, using
tox.ini for this is not recommended
because it is specific to tox and you may want to assure flake8 config is loaded
regardless if it is called form tox our from outside, like an IDE.
# setup.cfg [flake8] # Recommend matching the black line length (default 88), # rather than using the flake8 default of 79: max-line-length = 88 extend-ignore = # See https://github.com/PyCQA/pycodestyle/issues/373 E203,
What about double quote replacements
Indeed, the requoting is the most controversial decision ever made by black but the good news is that this sole option can be disabled.
I hated it initially, but after reading more I kinda understand why it was done like this. These days I support it, in a black purrist kind of way.
For projects with more than two contributors I suggest disabling requoting as it would make adoption even more controversial, at least for the first months.
# pyproject.toml [tool.black] skip-string-normalization = true
How to enable black for tox users
As examples are usually easier to read than literacy, check:
# tox.ini [tox] envlist = linters,... [linters:env] deps = black flake8 flake8-black commands = black # you want black before flake8 flake8
How to enable black for pre-commit users
If you are using pre-commit to run various linters, you should have something like this:
# .pre-commit-config.yaml --- repos: - repo: https://github.com/python/black.git rev: 19.10b0 hooks: - id: black language_version: python3 - repo: https://gitlab.com/pycqa/flake8.git rev: 3.7.9 hooks: - id: flake8 additional_dependencies: - flake8-black>=0.1.1 language_version: python3
Adoption on multiple repositories
Adopting black by bigger organizations and teams should not be seen as a task for a specific sprint. Its adoptions should be gradual, like one or two repositories per sprint, starting with the smaller ones first.
The less code you have on a repository the better, the less amount of incoming changes you have, the better. Do these repositories first and let others acclimatize with it.
For a bigger code, it may worth doing the reformatting in partial chunks, especially merging these will require rebasing existing proposed changes.