Skip to content

Commit b29b131

Browse files
committed
Init
0 parents  commit b29b131

10 files changed

+311
-0
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.vscode/
2+
log.txt

Pipfile

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[[source]]
2+
url = "https://pypi.org/simple"
3+
verify_ssl = true
4+
name = "pypi"
5+
6+
[packages]
7+
stackprinter = "*"
8+
pysnooper = "*"
9+
10+
[dev-packages]
11+
12+
[requires]
13+
python_version = "3.7"

Pipfile.lock

+37
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Python debugging
2+
3+
This project demonstrates various ways to debug Python programs:
4+
5+
- [Debugging with f-strings](examples/debug_with_console_f_strings.py)
6+
- [Debugging with PySnooper](examples/debug_with_pysnooper.py)
7+
- [Debugging with logging](examples/debug_with_default_logging.py)
8+
- [Debugging with `breakpoint()`](examples/debug_with_breakpoint.py)
9+
- [Debugging with VSCode](examples/debug_with_vscode.py)
10+
- [Debugging with stackprinter](examples/debug_with_stackprinter.py)
11+
12+
## Installation & Usage
13+
14+
To install the project:
15+
```
16+
# inside python-debugging
17+
pipenv install
18+
```
19+
20+
To run the examples, we need to enter the virtual environment:
21+
```
22+
pipenv shell
23+
```
24+
25+
Now just follow the instructions inside each example.
26+
27+
## Licence
28+
29+
Author: [Petr Stříbný](http://stribny.name)
30+
31+
License: The MIT License (MIT)

examples/debug_with_breakpoint.py

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
"""
2+
We can stop execution of the Python program with `breakpoint()` function which
3+
will stop execution of the program in the given place and switches to Python debugger
4+
5+
This is useful to open a debugger right at the place where we need to examine
6+
the state of the program
7+
8+
How to use:
9+
- run the script with `python debug_with_breakpoint.py`
10+
- the program will stop in the first `for` iteration, on the breakpoint() line
11+
- we will get into pdb (Python debugger)
12+
- while now in pdb:
13+
- we can see what `i` variable is by typing `i`
14+
- we can examine `processed_word` variable by typing `processed_word`
15+
- we can use any other pdb functionality
16+
- we can continue the execution of the program by typing `continue` and repeat the examination ^
17+
"""
18+
19+
# Example of the interactive session:
20+
# > python-debugging/debug_with_breakpoint.py(22)process_words()
21+
# -> for i, word in enumerate(words_to_process):
22+
# (Pdb) i
23+
# 0
24+
# (Pdb) processed_word
25+
# 'Debugging'
26+
# (Pdb) continue
27+
# > python-debugging/debug_with_breakpoint.py(22)process_words()
28+
# -> for i, word in enumerate(words_to_process):
29+
# (Pdb) i
30+
# 1
31+
# (Pdb) processed_word
32+
# 'With'
33+
34+
words = ['debugging', 'with', 'breakpoint()']
35+
36+
def process_words(words_to_process):
37+
for i, word in enumerate(words_to_process):
38+
processed_word = str.capitalize(word)
39+
breakpoint()
40+
41+
process_words(words)
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
"""
2+
We can use modern Python f-strings to easily print variables to the output
3+
console of the program
4+
5+
How to use:
6+
- run the script with `python debug_with_console_f_strings.py`
7+
- observe our state (i, processed_word) printed in the console
8+
"""
9+
10+
# The output:
11+
# i=0, processed_word=Debugging
12+
# i=1, processed_word=With
13+
# i=2, processed_word=Console
14+
# i=3, processed_word=F-strings
15+
16+
words = ['debugging', 'with', 'console', 'f-strings']
17+
18+
def process_words(words_to_process):
19+
for i, word in enumerate(words_to_process):
20+
processed_word = str.capitalize(word)
21+
print(f"i={i}, processed_word={processed_word}")
22+
# In Python 3.8 we can use = specifier
23+
# print(f"{i=}, {processed_word=}")
24+
25+
process_words(words)
+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
"""
2+
We can use Python's logging module (https://docs.python.org/3/library/logging.html)
3+
to print information to a console, file or the network to examine what is happening in the program
4+
5+
The advantage of using logging instead of other debugging techniques is that it is suitable to
6+
be commited with the source and used in production
7+
8+
There is a lot of options we can use to configure where and how the information is printed,
9+
e.g. there are several log levels (debug, info, error), several formatting options (%, str.format)
10+
11+
How to use:
12+
- run the script with `python debug_with_default_logging.py`
13+
- observe state (i, processed_word) and exception printed with additional info such as name of
14+
the function or a line number
15+
- observe that information is printed to the console and to a file at the same time
16+
"""
17+
18+
# The output:
19+
# DEBUG process_words() 47 i=0, processed_word=Debugging
20+
# DEBUG process_words() 47 i=1, processed_word=With
21+
# DEBUG process_words() 47 i=2, processed_word=Default
22+
# DEBUG process_words() 47 i=3, processed_word=Logging
23+
# ERROR process_words() 49 The word is not a string
24+
25+
import logging
26+
27+
FORMAT = '%(levelname)-8s %(funcName)s() %(lineno)d\t %(message)s'
28+
formatter = logging.Formatter(FORMAT)
29+
30+
logger = logging.getLogger(__name__)
31+
logger.setLevel(logging.DEBUG)
32+
33+
console_handler = logging.StreamHandler()
34+
console_handler.setFormatter(formatter)
35+
logger.addHandler(console_handler)
36+
37+
file_handler = logging.FileHandler("log.txt")
38+
file_handler.setFormatter(formatter)
39+
logger.addHandler(file_handler)
40+
41+
words = ['debugging', 'with', 'default', 'logging', 42]
42+
43+
def process_words(words_to_process):
44+
for i, word in enumerate(words_to_process):
45+
try:
46+
processed_word = str.capitalize(word)
47+
logger.debug('i=%d, processed_word=%s', i, processed_word)
48+
except TypeError:
49+
logger.error('The word is not a string')
50+
51+
process_words(words)

examples/debug_with_pysnooper.py

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
"""
2+
We can use PySnooper (https://github.com/cool-RR/pysnooper) to automatically
3+
print the state of the program as it is executed line by line
4+
5+
Many options exists to configure the output
6+
7+
How to use:
8+
- run the script with `python debug_with_pysnooper.py`
9+
- observe the state of the program as it is executed printed in the console
10+
"""
11+
12+
# The output:
13+
# Starting var:.. words_to_process = ['debugging', 'with', 'PySnooper']
14+
# 12:04:18.919933 call 15 def process_words(words_to_process):
15+
# 12:04:18.920111 line 16 for i, word in enumerate(words_to_process):
16+
# New var:....... i = 0
17+
# New var:....... word = 'debugging'
18+
# 12:04:18.920229 line 17 processed_word = str.capitalize(word)
19+
# New var:....... processed_word = 'Debugging'
20+
# 12:04:18.920332 line 16 for i, word in enumerate(words_to_process):
21+
# Modified var:.. i = 1
22+
# Modified var:.. word = 'with'
23+
# 12:04:18.920437 line 17 processed_word = str.capitalize(word)
24+
# Modified var:.. processed_word = 'With'
25+
# 12:04:18.920526 line 16 for i, word in enumerate(words_to_process):
26+
# Modified var:.. i = 2
27+
# Modified var:.. word = 'PySnooper'
28+
# 12:04:18.920635 line 17 processed_word = str.capitalize(word)
29+
# Modified var:.. processed_word = 'Pysnooper'
30+
# 12:04:18.920754 line 16 for i, word in enumerate(words_to_process):
31+
# 12:04:18.920846 return 16 for i, word in enumerate(words_to_process):
32+
# Return value:.. None
33+
34+
import pysnooper
35+
36+
words = ['debugging', 'with', 'PySnooper']
37+
38+
@pysnooper.snoop()
39+
def process_words(words_to_process):
40+
for i, word in enumerate(words_to_process):
41+
processed_word = str.capitalize(word)
42+
43+
process_words(words)

examples/debug_with_stackprinter.py

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
"""
2+
We can use stackprinter (https://github.com/cknd/stackprinter/) to enhance
3+
the printed information that we get when an exeption is thrown
4+
5+
How to use:
6+
- run the script with `python debug_with_stackprinter.py`
7+
- observe a different stack trace printed in the console
8+
"""
9+
10+
# The output:
11+
# File debug_with_stackprinter.py, line 22, in <module>
12+
# 18 def process_words(words_to_process):
13+
# 19 for i, word in enumerate(words_to_process):
14+
# 20 processed_word = str.capitalize(word)
15+
# 21
16+
# --> 22 process_words(words)
17+
# ..................................................
18+
# words = ['debugging', 'with', 'stackprinter', 42, ]
19+
# ..................................................
20+
21+
# File debug_with_stackprinter.py, line 20, in process_words
22+
# 18 def process_words(words_to_process):
23+
# 19 for i, word in enumerate(words_to_process):
24+
# --> 20 processed_word = str.capitalize(word)
25+
# ..................................................
26+
# words_to_process = ['debugging', 'with', 'stackprinter', 42, ]
27+
# i = 3
28+
# word = 42
29+
# processed_word = 'Stackprinter'
30+
# ..................................................
31+
32+
# TypeError: descriptor 'capitalize' requires a 'str' object but received a 'int'
33+
34+
import stackprinter
35+
stackprinter.set_excepthook(style='darkbg2')
36+
37+
words = ['debugging', 'with', 'stackprinter', 42]
38+
39+
def process_words(words_to_process):
40+
for i, word in enumerate(words_to_process):
41+
processed_word = str.capitalize(word)
42+
43+
process_words(words)

examples/debug_with_vscode.py

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
"""
2+
We can use the built-in debugger in Visual Studio Code editor to interactively
3+
step-through the program's execution and examine the variables
4+
5+
How to use:
6+
- install VSCode (https://code.visualstudio.com/)
7+
- install Python extension (https://marketplace.visualstudio.com/items?itemName=ms-python.python)
8+
- open debug_with_vscode.py in VSCode
9+
- make sure Python's execution path is set to the virtual environment that we created with pipenv
10+
(see python.pythonPath in .vscode/settings.json for that)
11+
- switch to Debug panel and add a new debug configuration (choose current file), this will create
12+
.vscode/launch.json configuration
13+
- set breakpoints by clicking on the left side of the line number where you want to stop the execution
14+
- click run on the Debug panel
15+
- the program will start and stop at the line you have selected
16+
- you will see all variables displayed in the debug panel and a new floating control panel to control the execution
17+
"""
18+
19+
words = ['debugging', 'with', 'vscode']
20+
21+
def process_words(words_to_process):
22+
for i, word in enumerate(words_to_process):
23+
processed_word = str.capitalize(word) # set breakpoint here
24+
25+
process_words(words)

0 commit comments

Comments
 (0)