Deixe darem pitaco no seu código com Black

Já abordamos code formatters aqui no blog. Para Javascript temos o Prettier como solução mais famosa, e há de se reconhecer a série de vantagens no uso da mesma. Acontece que para Python temos algumas ferramentas tão interessantes quanto, como o autopep8, yapf e o Black.

E é sobre o último que falaremos nesse post.

Se você está interessado em um comparativo, Kevin Peters escreveu um artigo bem interessante para o Medium chamado "Auto formatters for Python".

Além do PEP 8

A motivação para usar o Black é a mesma descrita no post sobre Prettier: Reduzir tempo discutindo code style, e deixar com que uma ferramenta tome essa decisão pelo time.

Em Python, o caminho para chegarmos a um consenso é relativamente menor. Uma das primeiras coisas que aprendi ao iniciar a minha jornada programando com a linguagem foi seguir a PEP 8 religiosamente. Nela estão descritas as convenções de código adotadas oficialmente, como linhas em branco, indentação, nomes, comentários, etc. Qual o motivo de perder tempo pensando em um style guide para o seu projeto se isso já foi discutido e formalizado pela comunidade?

Ferramentas de linting como pycodestyle e flake8 são essenciais e muito comuns. São elas que irão te alertar sobre possíveis quebras de estilo de código.

Mas com o Black vamos além...

Formatador descompromissado

O Black é um code formatter para Python, de código aberto (MIT), que tem por lema tornar a formatação "transparente", para que você possa focar no conteúdo.

O time do Black alega que a ferramenta é "descompromissada", mas nem por isso ela deixa de ser pretensiosa. Diretamente do repositório no Github:

By using it, you agree to cede control over minutiae of hand-formatting. In return, Black gives you speed, determinism, and freedom from pycodestyle nagging about formatting. You will save time and mental energy for more important matters.

Em outras palavras, a ferramenta segue as recomendações da PEP 8 e formata seu código automaticamente. Na verdade, o coding style utilizado é um subset da PEP 8, logo, algumas regras são "manipuladas" (como line-length e aspas ao invés de apóstrofos) de acordo com decisões tomadas pelo time de desenvolvedores da ferramenta.

"Foto do filme A Vida Secreta de Walter Mitty"
Pare de perder tempo discutindo convenção de código no code review e vá viver sua vida, como o Walter fez (gq.co.za)

Caso você não concorde com algumas liberdades que a ferramenta toma, é possível customizar algumas regras adotadas pelo editor. Por exemplo, se você é um usuário assíduo de single quotes e não concorda com o uso de double quotes, pode executar o utilitário com o argumento --skip-string-normalization. Na humilde opinião de quem vos escreve, se você se pegar usando o Black com muitas exceções, talvez valha a pena procurar outra ferramenta de formatting, como os próprios desenvolvedores sugerem:

Pro-tip: If you're asking yourself "Do I need to configure anything?" the answer is "No". Black is all about sensible defaults.

No terminal

Mas chega de papo, vamos ao que interessa:

$ pip install black

Como qualquer biblioteca Python, instalamos o Black através do utilitário pip. Na sequência, basta executá-lo apontando qual arquivo você pretende formatar.

$ black test.py
reformatted test.py
All done! ✨ 🍰 ✨
1 file reformatted.

Também é possível passar um diretório como argumento:

$ black plugins/
reformatted /Users/klaus/Workspace/blog/plugins/global_license.py
reformatted /Users/klaus/Workspace/blog/plugins/slideshare.py
All done! ✨ 🍰 ✨
2 files reformatted, 4 files left unchanged.

Não estranhe se a simpática fatia de bolo acima abrir o seu apetite.

Customizações, embora possam ser chamadas através de parâmetros de linha de comando, também podem ser armazenadas no pyproject.toml do seu projeto, como ilustra a documentação oficial.

No editor

Mas o melhor mesmo é ter o Black disponível no seu editor, deixando-o trabalhar em tempo de escrita de código.

Há uma vasta opção de editores que suportam o Black. Para o Vim, continuo com a opinião do artigo "Vim para desenvolvimento Python" e recomendo a utilização do ALE:

" ~/.vimrc

Plug 'w0rp/ale', { 'do': 'pip install black' }
call plug#end()

let g:ale_fix_on_save = 1
let g:ale_fixers = {
\   'python': [
\       'black',
\       'remove_trailing_lines',
\       'trim_whitespace'
\   ]
\}

Já para o VS Code, com o plugin oficial para Python, podemos configurá-lo como ferramenta de formatting:

{
  "python.formatting.blackPath": "black",
  "python.formatting.provider": "black"
}

Em todo lugar

Outra opção que deveria ser adotada, independente da utilização do Black no editor, é o uso de commit hooks para formatar arquivos alterados controlados via git. Volto a recomendar o pre-commit como ferramenta, e a boa notícia é que existe um hook com Black configurado e prontinho para uso:

repos:
- repo: https://github.com/ambv/black
rev: stable
hooks:
- id: black
    language_version: python3.7

Considerações finais

É impressionante a quantidade de tempo e atrito que economizamos quando adotamos uma ferramenta como Black ou yapf. Discussões relacionadas a style guide praticamente inexistem, e os code reviews são mais focados no problema e na qualidade do código, do que com convenções.

Já tive experiências ruins com formatters em Python, é verdade. Nem todo time ou projeto se adapta bem com esse tipo de "ferramenta impositiva", e embora os pontos positivos sejam óbvios, é na prática que você verá os negativos. Mas não me vejo mais deixando de ter esse tipo de auxílio enquanto escrevo código.

É também uma forma de pensarmos na experiência dos outros desenvolvedores, que se juntarão ao projeto durante o seu ciclo de vida.

Até a próxima.

Referências