Black is an opinionated code formatter for Python. In this guide, we will learn how to install Black, use it format code, integrate it with VSCode, and finally, set up pre-commit hooks to format our code before pushing.
To understand what Black does, take a look at this before and after comparison:
a = 0
while True:
a += 0
print ( "increased" )
b = [{"name": "Bob", "age": 56}, {
"name": "Jack", "age": 12
},
]
a = 0
while True:
a += 0
print("increased")
b = [
{ "name": "Bob", "age": 56 },
{ "name": "Jack", "age": 12 },
]
You can try it out before installing it with the Black Playground.
Should I use Black?
Many programmers choose not to use Black since it's opinionated and not customizable. One advantage of using it is that you spend less time arguing about code style since all the formatting is done for you, and there are no options to change. Still many people dislike it. Guide van Rossum also tweeted "Black is overrated unless your team argues over style a lot".
Installation
Global Installation
If you're not using a virtual environment, and you want to format a single .py
file, install Black globally:
pip install black
# Mac
pip3 install black
To confirm the installation is successful, enter black --version
in your terminal, and ensure that you see an output similar to black, version 20.8b1
.
Virtual environment installation
If you're using a virtual environment (venv, pipenv, poetry), install Black as a dev-dependency:
# poetry
poetry add black --dev
Installing Black with Pipenv
Pipenv does not allow pre-releases. To install Black, add this to your Pipfile
:
[dev-packages]
black = "==21.5b1"
Thank you to u/Kanjirito for bringing this up! Also see #1760.
Using the CLI
Create a new Python file and enter some ugly, unformatted code. For example, leave spaces between print
, the string, and the brackets:
print( "black" )
a = 0
In your Terminal, navigate to the directory where example.py
is located, and run the Black command. The command takes in the filename as a parameter, so in our case, it's
black example.py
You should get an output with 1 file reformatted.
. Now example.py
should look like
print("black")
a = 0
As you can see, it's remove the extra whitespaces and added a newline at the end of the file.
You can also specify a directory (instead of a file) with black like black src/
. All .py
inside the directories will be formatted.
Black with VScode
Open a Python file, then open the command palette and type >Format Document
VScode may show you the notification: "Formatter autopep8 is not installed. Install?" You can click Use black.
You can now use the keyboard shortcut opt-shift-F
(on Mac) to format your code.
You should also add the following line to you settings.json
if you always want to format Python files with Black:
{
"python.formatting.provider": "black"
}
Should I keep Black as my global formatting provider?
I like to use Black by default for formatting my Python code. Although I use it globally, certain projects may use a different formatter such as autopep8. In that case, I can override the setting python.formatting.provider
in the project's settings (in the workspace.json
file)
Options
Black has sensible defaults and in most cases, you do not need to configure it at all. You may, however, want to change certain parameters, such as the line length. You can add the line-length
flag:
black --line-length 80 example.py
You cannot change the indentation from 4 spaces
The tab length is fixed at 4. It is not configurable. See #378.
Read more about options and code style in The Black code style.
Specifying options in VScode
Specify settings for Black in VScode with the python.formatting.blackArgs
setting. For example, if you want your line length to be 80, add this to your settings:
{
...,
"python.formatting.blackArgs": ["--line-length", "80"]
}
When you format you use the "Format Document" shortcut (opt-shift-F
) to format your code, the line length will be 80.
Specifying options in pyproject.toml
If your project uses a virtual environment and you want to share Black settings, you can keep them in pyproject.toml
. (Relevant documentation)
For example, to configure the maximum line length, add the following to pyproject.toml
:
[tool.black]
line-length = 80
Check out the documentation for more options.
Trailing commas
Add a trailing comma if a you want an expression with multiple elements to have one element per line.
For example, the following code will not change when you run black on it:
numbers = [1, 2, 3, 4]
If you want each number to be on its own line, add a trailing comma after the 4
:
numbers = [1, 2, 3, 4,]
numbers = [
1,
2,
3,
4,
]
Disabling Black
Say you want your list to look like this:
numbers = [
1, 2, 3,
4, 5, 6,
7, 8, 9
]
Black will format it like this:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
To disable Black for a set of lines, add fmt: off
above and fmt: on
below.
So to ensure that Black doesn't touch the list numbers
, but have it format everything else:
# fmt: off
numbers = [ # This line until "fmt: on" will not be formated by Black
1, 2, 3,
4, 5, 6,
7, 8, 9
]
# fmt: on
a = 1 # This will be formatted by Black
Pre-commit and Black
Pre-commit will allow you to run Black on every commit. It is recommended that you configure Pre-commit with Black in a shared project to reduce merge-conflicts arising due to code formatting.
Install pre-commit with
pip install pre-commit
# On Mac
pip3 install pre-commit
If you're using pipenv or poetry, run pipenv install pre-commit --dev
or poetry add pre-commit --dev
to install pre-commit as a development dependency.
Create a file .pre-commit-config.yaml
and add the following configuration:
repos:
- repo: https://github.com/psf/black
rev: stable
hooks:
- id: black
language_version: python3
Check out the documentation to learn more about pre-commit.
At this stage, initialize your git repository of you haven't already with git init
.
"Install" the pre-commit hooks with the command:
pre-commit install
If you're using pipenv or poetry, run pipenv run pre-commit install
or poetry run pre-commit install
.
If successful, you will see pre-commit installed at .git/hooks/pre-commit
.
Finally, test it out. Create a new Python file with some unformatted code:
print ( "This code is not formatted" )
Make a commit:
git add .
git commit -m "First commit"
The first commit may take a while since Black has to be installed.
If your code is already formatted, the commit is made. If pre-commit formats your code with Black, the commit will not be made. You will see this in your Terminal:
black...........................Failed
- hook id: black
- files were modified by this hook
reformatted file.py
All done! ✨ 🍰 ✨
1 file reformatted.
The commit failed, but your .py
files are now formatted. All you have to do is run the commit again with:
git add . # make sure you add the changed files again!
git commit -m "First commit"
If successful, you should see this in your Terminal:
black...........................Passed
To confirm that the commit has been made, you can run always run git log --oneline
.
Warning: The 'rev' field of repo '[https://github.com/psf/black](https://github.com/psf/black)' appears to be a mutable reference ...
This warning appears because in .pre-commit-config.yaml
, the Black version is set to stable
, and therefore can change when Black is updated.
In order to pin the version, run pre-commit autoupdate
in the terminal. Upon running this, your .pre-commit-config.yaml
will be updated to something like:
repos:
- repo: https://github.com/psf/black
rev: 21.5b1
...
Read more about this at Using the latest version for a repository.