Stop Worrying About Python Code Formatting

An overview of the code formatter Black

Janne Kemppainen |

Wouldn't it be nice if you didn't have to worry about code formatting to make the linter happy? What if you didn't need to complain about minor formatting issues every time you are reviewing code? Can't agree on a common code style with your team so your codebase doesn't have a consistent look and feel? You are just starting a new Python project? It might be the right time to try Black.

Code style: black

Black is a Python code formatter which takes over your code formatting and forces consistent, deterministic and pycodestyle abiding results with a single command. I know it sounds like I'm selling you a product but Black is free and open source and I'm writing about it because I think it's a good idea.

Every programmer has their own opinions on how code should look and inexperienced developers might not be aware of the pycodestyle recommendations. As a result the code might not be nice to look at.

Black solves these problems by forcing a certain way of formatting. It will not change the actual functionality of the code so all your bugs will still be there but at least it will make your spaghetti code look pretty! As an added benefit further changes to the code generally cause smaller diffs as Black has been optimized for that.

Installation

The minimum requirement to run Black is Python 3.6 but you can use it to analyze Python code targeting earlier versions too. Installation happens with pip:

>> python3 -m pip install black

This installs the black command. Try that it works:

>> black
No paths given. Nothing to do 😴

You can see all the available options with the --help flag

>> black --help

What does Black actually do to the code?

So what should you expect your code to look like after it has been Blackened? Here are some things that Black is doing:

  • it tries to fit one simple expression on a single line if possible
    • if the line is too long it will split from the outer brackets and try to fit the rest on an indented line
    • if the line is still too long the same rule will be applied again with more indentation for the inner lines
    • comma separated items will be split to separate lines if needed
    • closing brackets are dedented
  • default line length is 88 characters but it can be changed with a configuration parameter
  • unnecessary vertical space is removed
    • max one line of space inside functions
    • spacing is added before and after functions
  • trailing commas are added to comma separated expressions if they span multiple lines as it can make diffs smaller
  • double quotes " are preferred over single quotes ' unless it increases the amount of escaped quotes
  • call chains (fluent API's) are delimited by the dots if needed

So as you can see Black is a little bit opinionated. But this is actually good for you because it means that you don't have to be, just accept what it's doing to your code.

You can try it out with the Black Playground.

Usage

Apart from setting the maximum allowed line length Black doesn't really give any customization options. This is an intentional choice made by the developers to make sure that the results are consistent across projects.

The absolute basic call is to just define the source files or directories and not worry about any of the other parameters. This will format all Python files that are found from the given directories or filenames.

>> black myproject

If you want to use a linge length other than the default 88 you can specify the -l or --line-length parameter to use some other value:

>> black -l 100 myproject

You can also use --include and --exclude to selectively choose which files should be affected inside directories. The parameter values should be regular expressions.

You can disable automatic formatting for a block of code by adding the code between #fmt: off and #fmt: on comments. This is useful for example if you want to display a multidimensional list neatly as a matrix like below:

#fmt: off
identity_matrix = [
    [1, 0, 0],
    [0, 1, 0],
    [0, 0, 1]
]
#fmt: on

Without the magic comments the result would look like this:

identity_matrix = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]

Black can also be integrated to your code editor. You can find the instructions for your specific editor from here. Alternatively, you can also integrate Black with version control with these instructions. This will make sure that the code is formatted before committing.

Using Black in existing projects

Switching an old project to use Black can have some adverse effects. On the first run Black will probably affect a lot of lines in the code as it changes all single quotes to double quotes, for example. This can make it a bit more difficult to track the Git history of a file, depending on the amount of reformatting that was required.

The string formatting issue can be avoided with the -S, or --skip-string-normalization parameter which will disable normalization of string quotes and prefixes. It is can also be used if the project has some existing convention that has different use cases for different quotes.

Conclusion

With Black you have one thing less to worry about when writing Python. At work our team is only starting to use it and after the initial tests I can see how it could keep our code more readable.

If you decied to jump to the Black bandwagon you can share your experiencess to me on Twitter. I'd like to hear your opinions on it. There are also other code formatters available so tell me if you prefer something else.

Subscribe to my newsletter

What's new with PäksTech? Subscribe to receive occasional emails where I will sum up stuff that has happened at the blog and what may be coming next.

powered by TinyLetter | Privacy Policy