Dissecando um inseto (ou como usar o pdb, the Python Debugger)

Boas, pessoal! Hoje eu estou aqui pra mostrar como se usa o (básico do) Python Debugger, o pdb, que é (óbvio) um depurador pra se usar com o Python. Este exemplo é feito usando o Python 3.

Mas… como é?

Bom, existe mais de uma maneira de usar o pdb. A que vou mostrar é chamando o pdb como um script para depurar outro script. Então, primeiro, vamos criar um scriptosco com um erro mais tosco ainda pra gente começar a brincar com o pdb. O scriptosco é o seguinte:

#-*- coding: utf-8 -*-

def divide(a, b):
    erro = False
    try:
        return float(a) / float(b)
    except:
        erro = True

    if erro:
        raise Exception("Não vou te dizer qual é o erro...")

a = 1
b = 2
divide(a, b)
a = 3
b = 0
divide(a, b)

Bom, rodando isso aí, a gente tem o seguinte:

$ $python3 exemplopdb.py
Traceback (most recent call last):
  File "exemplopdb.py", line 18, in
    divide(a, b)
  File "exemplopdb.py", line 11, in divide
    raise Exception("Não vou te dizer qual é o erro...")
Exception: Não vou te dizer qual é o erro...

Será que esse tal de pdb funciona mesmo?

Agora que temos um erro, podemos usar o pdb pra achar cara. A gente vai fingir que não vê nada errado até a hora certa, tá? :P A sintexe pra se chamar o pdb é a seguinte: python -m pdb <meu_script> Então, ao chamar nosso doente junto com o pdb, a gente vai cair no shell do pdb. Assim:

$ python3 -m pdb exemplopdb.py
--Return--
> /media/5511fc83-ad85-484b-9b0e-0948abcb6026_/virtualpython/lib/python3.1/encodings/__init__.py(67)normalize_encoding()->'utf_32_be'
-> return ''.join(chars)
(Pdb)

Nós começaremos criando breakpoints nas linhas 11 e 18. Fazemos isto com o comando b[reak]. Depois, utilizando o comando c[ontinue], continuaremos a execução do programa até que algum breakpoint seja encontrado. E por fim, usaremos o comando list para listar um trecho de código e ver onde paramos.

(Pdb) break exemplopdb.py:11
Breakpoint 1 at /media/sda6/Projetos & afins/scripts/exemplopdb.py:11
(Pdb) b exemplopdb.py:18
Breakpoint 2 at /media/sda6/Projetos & afins/scripts/exemplopdb.py:18
(Pdb) c
> /media/sda6/Projetos & afins/scripts/exemplopdb.py(18)()
-> divide(a, b)
(Pdb) list
 13          a = 1
 14          b = 2
 15          divide(a, b)
 16          a = 3
 17          b = 0
 18 B->      divide(a, b)
 19
[EOF]
(Pdb)

Nosso primeiro breakpoint é bem na chamada da função, então vamos «entrar na função» e acompanhar a execução. A gente faz isso com o comando s[tep]. Uma vez na função, a gente pode acompanhar a execução linha-por-linha usando o comando n[ext] e também pode imprimir os valores das variáveis com print.

(Pdb) s
--Call--
> /media/sda6/Projetos & afins/scripts/exemplopdb.py(3)divide()
-> def divide(a, b):
(Pdb) list
  1          #-*- coding: utf-8 -*-
  2
  3  ->      def divide(a, b):
  4              erro = False
  5              try:
  6                  return float(a) / float(b)
  7              except:
  8                  erro = True
  9
 10              if erro:
 11 B                raise Exception("Não vou te dizer qual é o erro...")
(Pdb) n
> /media/sda6/Projetos & afins/scripts/exemplopdb.py(4)divide()
-> erro = False
(Pdb) n
> /media/sda6/Projetos & afins/scripts/exemplopdb.py(5)divide()
-> try:
(Pdb) n
> /media/sda6/Projetos & afins/scripts/exemplopdb.py(6)divide()
-> return float(a) / float(b)
(Pdb) print(a, b)
(3, 0)
(Pdb) n
ZeroDivisionError: 'float division'
> /media/sda6/Projetos & afins/scripts/exemplopdb.py(6)divide()
-> return float(a) / float(b)
(Pdb)

Bom, aí matamos o erro, não? Funciona mesmo! Moral da história: As vezes o pdb pode salvar várias horas do seu dia. Faça dele um amigo. :)