Github:
https://github.com/cool-RR/PySnooper
install
$ pip install pysnooper
Conda with Conda forge channel:
$ conda install -c conda-forge pysnooper
Arch Linux:
$ yay -S python-pysnooper
Fedora Linux:
$ dnf install python3-pysnooper
readme file
PySnooper is a simple debugger. If you've used Bash, it's like set - x python, but it's more advanced.
Your story: you're trying to figure out why your Python code doesn't do what you think it should do. You'll like to use a mature debugger with breakpoints and monitoring, but you don't have to bother setting up one now.
You want to know which rows are running, which are not running, and what the value of the local variable is.
Most people use print lines in strategic locations, some of which display the values of variables.
PySnooper can let you do the same thing. Except that you don't make the correct print line carefully, you just need to add a decorator line to the function you are interested in. You will get the playback log of your function, including which lines run, and the time and exact time of changing local variables.
What makes PySnooper stand out from all other code intelligence tools? You can use it in your bad, huge enterprise code base without any setup. Just open the decorator, as shown below, and redirect the output to a dedicated log file by specifying its path as the first parameter.
example
We are writing a function that converts numbers to binary by returning a list of bits. Let's add @ pysnooper Snoop () decorator to spy on it:
import pysnooper @pysnooper.snoop() def number_to_bits(number): if number: bits = [] while number: number, remainder = divmod(number, 2) bits.insert(0, remainder) return bits else: return [0] number_to_bits(6)
The output of stderr is:
Source path:... /my_code/foo.py Starting var:.. number = 6 15:29:11.327032 call 4 def number_to_bits(number): 15:29:11.327032 line 5 if number: 15:29:11.327032 line 6 bits = [] New var:....... bits = [] 15:29:11.327032 line 7 while number: 15:29:11.327032 line 8 number, remainder = divmod(number, 2) New var:....... remainder = 0 Modified var:.. number = 3 15:29:11.327032 line 9 bits.insert(0, remainder) Modified var:.. bits = [0] 15:29:11.327032 line 7 while number: 15:29:11.327032 line 8 number, remainder = divmod(number, 2) Modified var:.. number = 1 Modified var:.. remainder = 1 15:29:11.327032 line 9 bits.insert(0, remainder) Modified var:.. bits = [1, 0] 15:29:11.327032 line 7 while number: 15:29:11.327032 line 8 number, remainder = divmod(number, 2) Modified var:.. number = 0 15:29:11.327032 line 9 bits.insert(0, remainder) Modified var:.. bits = [1, 1, 0] 15:29:11.327032 line 7 while number: 15:29:11.327032 line 10 return bits 15:29:11.327032 return 10 return bits Return value:.. [1, 1, 0] Elapsed time: 00:00:00.000001
Or, if you don't want to track the entire function, wrap the relevant parts in a with block:
import pysnooper import random def foo(): lst = [] for i in range(10): lst.append(random.randrange(1, 1000)) with pysnooper.snoop(): lower = min(lst) upper = max(lst) mid = (lower + upper) / 2 print(lower, mid, upper) foo()
The output is similar:
New var:....... i = 9 New var:....... lst = [681, 267, 74, 832, 284, 678, ...] 09:37:35.881721 line 10 lower = min(lst) New var:....... lower = 74 09:37:35.882137 line 11 upper = max(lst) New var:....... upper = 832 09:37:35.882304 line 12 mid = (lower + upper) / 2 74 453.0 832 New var:....... mid = 453.0 09:37:35.882486 line 13 print(lower, mid, upper) Elapsed time: 00:00:00.000344
features
If you cannot easily access stderr, you can redirect the output to a file:
@pysnooper.snoop('/my/log/file.log')
You can also pass streams or callable objects instead, which will be used.
View the values of expressions that are not local variables:
@pysnooper.snoop(watch=('foo.bar', 'self.x["whatever"]'))
Display the listening line of the function called by the function:
@pysnooper.snoop(depth=2)
Advanced usage:
link: https://github.com/cool-RR/PySnooper/blob/master/ADVANCED_USAGE.md