Files
practical-python/Notes/08_Testing_debugging/03_Debugging.md
David Beazley b5244b0e61 link experiment
2020-05-26 09:21:19 -05:00

148 lines
3.1 KiB
Markdown

# 8.3 Debugging
### Debugging Tips
So, you're program has crashed...
```bash
bash % python3 blah.py
Traceback (most recent call last):
File "blah.py", line 13, in ?
foo()
File "blah.py", line 10, in foo
bar()
File "blah.py", line 7, in bar
spam()
File "blah.py", 4, in spam
line x.append(3)
AttributeError: 'int' object has no attribute 'append'
```
Now what?!
### Reading Tracebacks
The last line is the specific cause of the crash.
```bash
bash % python3 blah.py
Traceback (most recent call last):
File "blah.py", line 13, in ?
foo()
File "blah.py", line 10, in foo
bar()
File "blah.py", line 7, in bar
spam()
File "blah.py", 4, in spam
line x.append(3)
# Cause of the crash
AttributeError: 'int' object has no attribute 'append'
```
However, it's not always easy to read or understand.
*PRO TIP: Paste the whole traceback into Google.*
### Using the REPL
Use the option `-i` to keep Python alive when executing a script.
```bash
bash % python3 -i blah.py
Traceback (most recent call last):
File "blah.py", line 13, in ?
foo()
File "blah.py", line 10, in foo
bar()
File "blah.py", line 7, in bar
spam()
File "blah.py", 4, in spam
line x.append(3)
AttributeError: 'int' object has no attribute 'append'
>>>
```
It preserves the interpreter state. That means that you can go poking around after the crash. Checking variable values and other state.
### Debugging with Print
`print()` debugging is quite common.
*Tip: Make sure you use `repr()`*
```python
def spam(x):
print('DEBUG:', repr(x))
...
```
`repr()` shows you an accurate representation of a value. Not the *nice* printing output.
```python
>>> from decimal import Decimal
>>> x = Decimal('3.4')
# NO `repr`
>>> print(x)
3.4
# WITH `repr`
>>> print(repr(x))
Decimal('3.4')
>>>
```
### The Python Debugger
You can manually launch the debugger inside a program.
```python
def some_function():
...
breakpoint() # Enter the debugger (Python 3.7+)
...
```
This starts the debugger at the `breakpoint()` call.
For earlier Python versions:
```python
import pdb
...
pdb.set_trace() # Instead of `breakpoint()`
...
```
### Run under debugger
You can also run an entire program under debugger.
```bash
bash % python3 -m pdb someprogram.py
```
It will automatically enter the debugger before the first statement. Allowing you to set breakpoints and change the configuration.
Common debugger commands:
```code
(Pdb) help # Get help
(Pdb) w(here) # Print stack trace
(Pdb) d(own) # Move down one stack level
(Pdb) u(p) # Move up one stack level
(Pdb) b(reak) loc # Set a breakpoint
(Pdb) s(tep) # Execute one instruction
(Pdb) c(ontinue) # Continue execution
(Pdb) l(ist) # List source code
(Pdb) a(rgs) # Print args of current function
(Pdb) !statement # Execute statement
```
For breakpoints location is one of the following.
```code
(Pdb) b 45 # Line 45 in current file
(Pdb) b file.py:45 # Line 34 in file.py
(Pdb) b foo # Function foo() in current file
(Pdb) b module.foo # Function foo() in a module
```