Black is a quite popular autoformatter for Python code. Author of black (ambv) is a Python core developer. In May 2019 black bacame Python’s official tool. Sounds cool, doesn’t it? I really love autoformatting (especially go format), it allows yout to forget about code styles and avoid bikeshedding, but in the same time keep your code beautiful, readable and consistent. And I’m not recommend you to use Black for a while.
Flake8 is a most popular linter for Python. Flake8 has 3.5kk downloads in this month, while Black 0.6kk downloads. Flake8 is linter, Black is a fromatter, so why not to use both at the same time?
Black tries to have opinion about everything. Every situation must have one and only one solution how it format:
It doesn’t take previous formatting into account.
For example, it tries to fit everything in one line. In many cases you don’t want it:
# formatted by smart developer:
ignore = [
'dist', # distribution archives
'build', # builded project for current OS
]
# formatted by black:
ignore = ["dist", "build"] # distribution archives # builded project for current OS
Black always drops trailing commas from everything. Trailing commas in multiline statements makes adding new elements easier and diffs clean. Read Why you should enforce Dangling Commas for Multiline Statements for details.
# beautiful
'very-very long {subject} (or {subject_alt})'.format(
subject='line',
subject_alt='other piece of text',
)
# black
"very-very long {subject} (or {subject_alt})".format(
subject="line", alt="other piece of text"
)
Additionally, without triling commas you can forget to add comma to the previous element, and interpreter will ok with it because of implicit string concatenation. And for Black it’s valid syntax too:
# ups, I forgot a comma:
(
'1',
'2'
'3'
)
# thank you, black:
("1", "2" "3")
I recommend you to use trailing commas for multiline statements and control it with flake8-commas plugin for flake8.
Another piece of Black philosophy:
It is not configurable.
This is main conception of Black, and it doesn’t work after all. Now Black has flags to configure line length and quotes style. This is because this philosophy doesn’t work while tool isn’t good enough. Maybe, some day, but not in the current state. It makes much troubles:
This is example from Black docs:
[tool.black]
target-version = ['py37']
include = '\.pyi?$'
exclude = '''
(
/(
\.eggs # exclude a few common directories in the
| \.git # root of the project
| \.hg
| \.mypy_cache
| \.tox
| \.venv
| _build
| buck-out
| build
| dist
)/
| foo.py # also separately exclude a file named foo.py in
# the root of the project
)
'''
I never understand what the strange construction is it. Now I got it. It’s regular expression! Why not a list of regexps? Ugh…
Another point of Black’s philosophy is “there is only one style”. So, it’s against of plugins and any extendability: you cannot have any other rules except built-in in Black. And you can’t disable them, of course. However, Black can’t take care about everything. For example, using .format
inside of log messages is a bad practice. Flake8 has plugin for it (flake8-logging-format), but will we ever see this check in Black? I don’t think so.
Black only do changes. It can’t give you feedback or make some changes that can affect your interfaces. For example, Flake8 has flake8-mutable plugin that prevents you from using mutable default arguments for function. Black can’t do anything with it.
Ambv has done a great work. However, it’s one-person project, as most of Open Source projects. Flake8 plugins made by different people and teams. You can think that these rules is incompatible, goes from different styleguides and you can’t combine these plugins together. It’s not true. I’m using almost all Flake8 plugins, and I have no experience when 2 plugins had different opinion about some code.
The Black documentation explicitly states that the project is still in beta test. From the practical perspective, that means that the code style changes in every release. So, if you want to use it in a project, be ready to take an actions:
allow_failure: true
). Otherwise, it will even more complicate backports and black version upgrade.Ok, let’s talk about alternatives and when Black is a good choice.