Using PySnooper for Python Debugging

Never use print for debug in Python, instead, use awesome tool like PySnooper

When your Python code doesn’t run as expected or when you want to examine if your program is running correctly, you may use a full-fledged debugger with breakpoints and watches. But in some cases, you can’t be bothered to set one up right now.

You want to know which lines are running and which aren’t, and what the values of the local variables are.

Most people would use print lines, in strategic locations, some of them showing the values of variables.

PySnooper lets you do the same, except instead of carefully crafting the right print lines, you just add one decorator line to the function you’re interested in. You’ll get a play-by-play log of your function, including which lines ran and when, and exactly when local variables were changed.

Installation

  • Install PySnooper using pip

    pip install pysnooper
  • Using conda

    conda install -c conda-forge pysnooper

Usage

Here is an example how PySnooper works. Let say you have a function to sum up to the n. Let’s snoop on it by adding the @pysnooper.snoop() decorator:

import pysnooper

@pysnooper.snoop()
def sum_up(number):
  s = 0
  for i in range(1, number+1):
    s += i

  return s

print(sum_up(10))

The output to the console is:

Starting var:.. number = 5
14:52:25.242890 call         5 def sum_up(number):
14:52:25.243049 line         6     s = 0
New var:....... s = 0
14:52:25.244005 line         7     for i in range(1, number + 1):
New var:....... i = 1
14:52:25.244005 line         8         s += i
Modified var:.. s = 1
14:52:25.244983 line         7     for i in range(1, number + 1):
Modified var:.. i = 2
14:52:25.244983 line         8         s += i
Modified var:.. s = 3
14:52:25.251813 line         7     for i in range(1, number + 1):
Modified var:.. i = 3
14:52:25.254806 line         8         s += i
Modified var:.. s = 6
14:52:25.272309 line         7     for i in range(1, number + 1):
Modified var:.. i = 4
14:52:25.275238 line         8         s += i
Modified var:.. s = 10
14:52:25.278208 line         7     for i in range(1, number + 1):
Modified var:.. i = 5
14:52:25.280118 line         8         s += i
Modified var:.. s = 15
14:52:25.281806 line         7     for i in range(1, number + 1):
14:52:25.282758 line        10     return s
14:52:25.284699 return      10     return s
Return value:.. 15
15

Or if you don’t want to trace an entire function, you can wrap the relevant part in a with block:

import pysnooper


def average(number):
    s = 0
    for i in range(1, number + 1):
        s += i

    with pysnooper.snoop():
        avg = s / number

        return avg


print(average(5))

The output:

New var:....... number = 5
New var:....... s = 15
New var:....... i = 5
14:57:20.398242 line        10         avg = s / number
New var:....... avg = 3.0
14:57:20.410059 line        12         return avg
3.0

Features

  • You can redirect the output to a file:

    @pysnooper.snoop('/path/to/output/file.log')
  • Add prefix to snoop lines

    @pysnooper.snoop(prefix='DEBUG ')

Conclusion

Using PySnooper for debugging makes it easier than using multiple print statements. It shows more detail, and of course, it saves your time adding print statement. But if you are using IDE with debugger with breakpoints and watches, use it instead.

Last modified October 4, 2020