Utilizando cores para escrever no terminal (Python)

Overview
Você já se perdeu em um mar de texto enquanto usava o terminal? Neste post leve e informativo, vamos mergulhar em como Python pode tornar suas mensagens de terminal não apenas informativas, mas também visualmente impactantes, graças ao uso de cores. Desde a abordagem simples com caracteres ANSI, passando pela utilização de pacotes como termcolor e sty, vamos explorar formas práticas e fáceis de melhorar a interação com os usuários dos seus scripts. Prepare-se para adicionar um toque de cor ao seu terminal!
Quem conhece Python sabe que uma das coisas que ele faz muito bem é automatizar tarefas. Durante estas automatizações, escrevemos mensagens no terminal, para que o usuário consiga acompanhar o que está acontecendo.
O problema começa quando escrevermos muitas coisas no terminal… fica aquele tanto de texto amontoado e só quem fez aquele script sabe identificar o que é importante ou não. Uma das formas de resolver isso é utilizar cores para destacar as mensagens importantes.Existem algumas formas de fazer isso. Vou começar pela que considero mais simples e que não depende de outros pacotes, depois vou mostrar como utilizar alguns pacotes mais famosos.
1. Utilizando caracteres ANSI
A primeira forma (e mais simples, na minha opinião) é utilizando caracteres ANSI. Esta forma consiste em colocar um conjunto de carecteres logo antes do texto que você quer colorir.
Veja a relação de códigos ANSI e suas respectivas cores:
1RED = "\033[1;31m"
2BLUE = "\033[1;34m"
3CYAN = "\033[1;36m"
4GREEN = "\033[0;32m"
5RESET = "\033[0;0m"
6BOLD = "\033[;1m"
7REVERSE = "\033[;7m"
Agora um exemplo de como aplicar essas cores:
1>>> print(RED + "ERROR!" + RESET + "Something went wrong...")
2ERROR! Something went wrong...
Por que foi necessário concatenar o código RESET? Sem o reset (das cores), o resto da frase ficaria em vermelho.
Agora você pode se divertir a vontade e misturar as cores e estilos da forma que quiser, por exemplo:
1>>> print(BOLD + RED + "ERROR!" + RESET + "Something went wrong...")
2<strong>ERROR!</strong> Something went wrong...
Como pode ser observado, os caracteres referentes ao RESET removem todas as formatações.
OK. Então vimos que é só concatenar os valores… mas fica feio e pouco prático. Seria uma boa ideia encapsular esta lógica, certo? Podemos criar uma classe que resolve isso e (inclusive) implementa o que falamos no último post (Inicializando dicionário com valores padrões)…
A primeira coisa é criar a classe com um dicionário com um dicionário contendo a relação de cores:
1class printer():
2 _colors_ = {
3 **dict.fromkeys(("RED", "ERROR", "NO"), "\033[1;31m"),
4 **dict.fromkeys(("GREEN", "OK", "YES"), "\033[0;32m"),
5 **dict.fromkeys(("YELLOW", "WARN", "MAYBE"), "\033[0;93m"),
6 "BLUE": "\033[1;34m",
7 "CYAN": "\033[1;36m",
8 "RESET": "\033[0;0m",
9 "BOLD": "\033[;1m",
10 "REVERSE": "\033[;7m"
11 }
O próximo passo é criar uma função que recebe o nome da cor e retorna o código ANSI correspondente:
1 def _get_color_(self, key):
2 """Gets the corresponding color ANSI code... """
3 try:
4 return self._colors_[key]
5 except:
6 return self._colors_["RESET"]
A função acima tenta retornar o código correspondente ao argumento informado. Se não for possível, retorna o caractere que faz um reset nos formatos.
Agora é só criar a função que faz o print da mensagem:
1 def print(self, msg , color="RESET"):
2 """Main print function..."""
3
4 # Get ANSI color code.
5 color = self._get_color_(key=color)
6
7 # Printing...
8 print("{}{}{}".format(color, msg, self._colors_["RESET"]))
A função acima recebe como argumento a mensagem e a cor. Se o nome da cor estiver errado, vai mostrar a mensagem sem a formatação.
Para utilizar é simples:
1p = printer()
2
3p.print(msg="SUCCESS Test...", color="GREEN")
4p.print(msg="WARN Test...", color="YELLOW")
5p.print(msg="ERRPR Test...", color="RED")
O fonte acima vai produzir o seguinte resultado:
1SUCCESS Test...
2WARN Test...
3ERROR Test...
Para facilitar, criei esta classe e adicionei três métodos: success (verde), error (vermelho) e warning (amarelo). O fonte dela está no meu Github.
2. Utilizando o pacote termcolor
Para utilizar este pacote, a primeira coisa é baixa-lo. Para isso, utilize o PIP:
1pip install termcolor
Este pacote é bem flexível e possui uma série de opções, mas vou utilizar um exemplo básico aqui:
1from termcolor import colored
2
3print(colored('Error Test!!!', 'red'))
4print(colored('Warning Test!!!', 'yellow'))
5print(colored('Success Test!!!', 'green'))
Disponibilizei este exemplo no meu Github. Existem mais exemplos na pagina deste pacote: https://pypi.python.org/pypi/termcolor
3. Utilizando o pacote sty
Assim como o termcolor, precisamos instalar este pacote. Sugiro utilizar o pip:
1pip install sty
Este pacote tem mais possibilidades. Veja alguns exemplos de utilização abaixo:
1from sty import fg, bg, ef, rs
2
3print(fg.red + 'ERROR Test!' + fg.rs)
4print(fg.li_yellow + 'WARNING Test!' + fg.rs)
5print(fg.green + 'SUCCESS Test!' + fg.rs)
O resultado final é o mesmo dos exemplos anteriores. Inclui no meu Github um exemplo mais completo da utilização deste pacote. Link para o pacote: https://pypi.python.org/pypi/sty/1.0.0b4
Espero ter ajudado.