Skip to content

Commit 2d65e3c

Browse files
expand debugging
1 parent da732c9 commit 2d65e3c

File tree

1 file changed

+249
-11
lines changed

1 file changed

+249
-11
lines changed

book/111_debugging.ipynb

Lines changed: 249 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,8 @@
1717
"metadata": {},
1818
"source": [
1919
"We are humans, we make mistakes – that's very much true for coding.\n",
20-
"Finding errors in our code is fundamental skill to train.\n",
2120
"\n",
22-
"We will cover here a few tools that help us find and fix errors more quickly."
21+
"Finding errors in our code is fundamental skill to train so we will cover here a few tools that help us find and fix errors more quickly."
2322
]
2423
},
2524
{
@@ -32,7 +31,7 @@
3231
"A debugger is a device that allows us to interrupt code execution and jump into the execution context in a interactive mode, so that we can inspect and run code to find out what's going on. \n",
3332
"We called that to \"set a breakpoint\" or \"set a trace\".\n",
3433
"\n",
35-
"There are a few options to do that natively in python."
34+
"There are a few options to do that in python."
3635
]
3736
},
3837
{
@@ -42,35 +41,274 @@
4241
"source": [
4342
"## Python debugger, breakpoints\n",
4443
"The python standard library includes `pdb` module.\n",
44+
"If you call this function in your code you will be put into an interactive session exactly at that point.\n",
45+
"\n",
46+
"Any of the following options would work:\n",
4547
"\n",
4648
"```python\n",
47-
"import pdb; pdb.set_trace()\n",
49+
"# your code\n",
50+
"# your code\n",
51+
"import pdb\n",
52+
"pdb.set_trace()\n",
53+
"# your code\n",
54+
"# your code\n",
55+
"breakpoint()\n",
56+
"# your code\n",
57+
"# your code\n",
58+
"# your code\n",
4859
"```"
4960
]
5061
},
5162
{
52-
"cell_type": "code",
53-
"execution_count": null,
54-
"id": "b40ea608-89a9-4cbd-b07f-4f9a33699d89",
63+
"cell_type": "markdown",
64+
"id": "1a6d1185-f23d-4fd1-80ee-925836018ef8",
5565
"metadata": {},
56-
"outputs": [],
57-
"source": []
66+
"source": [
67+
"Once in the debugger, we have several functions to proceed with code execution with more granular control.\n",
68+
"\n",
69+
"There are several options, but the most commonly used methods are:\n",
70+
"\n",
71+
"- n (next): Continue execution one line, stay in the current function (step over)\n",
72+
"- s (step): Execute current line and stop in a foreign function if one is called (step into) \n",
73+
"- c (continue): Continue whole code execution until a new breakpoint is found"
74+
]
5875
},
5976
{
6077
"cell_type": "markdown",
6178
"id": "4ae14f36-84e6-4def-9240-7a423c587e9c",
6279
"metadata": {},
6380
"source": [
64-
"## IPython debugger"
81+
"## IPython debugger\n",
82+
"The standard python debugger is fine but a bit basic, so sometimes the IPython debugger is a friendlier option.\n",
83+
"\n",
84+
"We need to install it:\n",
85+
"\n",
86+
"```bash\n",
87+
"uv add ipdb\n",
88+
"```\n",
89+
"Then we can do:\n",
90+
"\n",
91+
"```python\n",
92+
"import ipdb\n",
93+
"ipdb.set_trace()\n",
94+
"```"
6595
]
6696
},
6797
{
6898
"cell_type": "markdown",
6999
"id": "886ba261-d3a3-43e0-b7e1-3353d0029622",
70100
"metadata": {},
71101
"source": [
72-
"## Notebook %%debug"
102+
"## Notebook %debug\n",
103+
"Inside the jupyter notebook we can directly jump into a debugger when there is an error.\n",
104+
"\n",
105+
"If a cell throws an error, you can type this \"ipython magic method\" in the following cell:\n",
106+
"\n",
107+
"```python\n",
108+
"%debug\n",
109+
"```"
110+
]
111+
},
112+
{
113+
"cell_type": "code",
114+
"execution_count": 1,
115+
"id": "76c6445c-3cc0-4bc6-b602-97cd5707feee",
116+
"metadata": {},
117+
"outputs": [
118+
{
119+
"ename": "AssertionError",
120+
"evalue": "",
121+
"output_type": "error",
122+
"traceback": [
123+
"\u001b[31m---------------------------------------------------------------------------\u001b[39m",
124+
"\u001b[31mAssertionError\u001b[39m Traceback (most recent call last)",
125+
"\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[1]\u001b[39m\u001b[32m, line 5\u001b[39m\n\u001b[32m 2\u001b[39m a = \u001b[32m1\u001b[39m\n\u001b[32m 3\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m a == \u001b[32m0\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m5\u001b[39m \u001b[43mwrong_func\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n",
126+
"\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[1]\u001b[39m\u001b[32m, line 3\u001b[39m, in \u001b[36mwrong_func\u001b[39m\u001b[34m()\u001b[39m\n\u001b[32m 1\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34mwrong_func\u001b[39m():\n\u001b[32m 2\u001b[39m a = \u001b[32m1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m3\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m a == \u001b[32m0\u001b[39m\n",
127+
"\u001b[31mAssertionError\u001b[39m: "
128+
]
129+
}
130+
],
131+
"source": [
132+
"def wrong_func():\n",
133+
" a = 1\n",
134+
" assert a == 0\n",
135+
"\n",
136+
"wrong_func()"
137+
]
138+
},
139+
{
140+
"cell_type": "code",
141+
"execution_count": 2,
142+
"id": "9225666f-7cce-4bec-96ac-c5fc1f167968",
143+
"metadata": {},
144+
"outputs": [
145+
{
146+
"name": "stdout",
147+
"output_type": "stream",
148+
"text": [
149+
"> \u001b[32m/tmp/ipykernel_81865/3667203143.py\u001b[39m(\u001b[92m3\u001b[39m)\u001b[36mwrong_func\u001b[39m\u001b[34m()\u001b[39m\n",
150+
"\u001b[32m 1\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m wrong_func():\n",
151+
"\u001b[32m 2\u001b[39m a = \u001b[32m1\u001b[39m\n",
152+
"\u001b[32m----> 3\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m a == \u001b[32m0\u001b[39m\n",
153+
"\u001b[32m 4\u001b[39m \n",
154+
"\u001b[32m 5\u001b[39m wrong_func()\n",
155+
"\n"
156+
]
157+
},
158+
{
159+
"name": "stdin",
160+
"output_type": "stream",
161+
"text": [
162+
"ipdb> print(a)\n"
163+
]
164+
},
165+
{
166+
"name": "stdout",
167+
"output_type": "stream",
168+
"text": [
169+
"1\n"
170+
]
171+
},
172+
{
173+
"name": "stdin",
174+
"output_type": "stream",
175+
"text": [
176+
"ipdb> exit\n"
177+
]
178+
}
179+
],
180+
"source": [
181+
"%debug"
182+
]
183+
},
184+
{
185+
"cell_type": "markdown",
186+
"id": "fac0dd96-22c9-40a8-b279-e5043f415fa9",
187+
"metadata": {},
188+
"source": [
189+
"Notice that we typed \"exit\" to get out of the debugger."
190+
]
191+
},
192+
{
193+
"cell_type": "markdown",
194+
"id": "7995bd99-3ba9-49d5-8c18-2b289f999133",
195+
"metadata": {},
196+
"source": [
197+
"## Exercises\n",
198+
"\n",
199+
"Here's a piece of code that will fail at run-time:"
200+
]
201+
},
202+
{
203+
"cell_type": "code",
204+
"execution_count": 8,
205+
"id": "abb2830e-8f39-4bad-9f1c-cc0dd697f09c",
206+
"metadata": {},
207+
"outputs": [],
208+
"source": [
209+
"def f(p):\n",
210+
" assert p == 0\n",
211+
" \n",
212+
"def main():\n",
213+
" a = 0\n",
214+
" f(a)\n",
215+
" b = 1 \n",
216+
" f(b)\n",
217+
" c = 0\n",
218+
" f(c)"
219+
]
220+
},
221+
{
222+
"cell_type": "markdown",
223+
"id": "8275e207-c5b3-4242-832e-4f98d30f1145",
224+
"metadata": {},
225+
"source": [
226+
"1) Run the code to see the error\n",
227+
"2) Set a breakpoint inside `main` to use the debugger\n",
228+
"3) Step through the code using `n (next)` and another time using `s (step)`\n",
229+
"4) Set a second breakpoint inside `main`and run again the code but this time use `c (continue)`\n",
230+
"5) Download [this public dataset](https://github.com/fabridamicelli/ds005588/archive/refs/heads/broken-data.zip) into the folder `/pycourse/data/` (create it if you don't yet have it).\n",
231+
"\n",
232+
"This dataset was modified and has some problems apparently.\n",
233+
"Here's a bit of code to unzip it and read through the files."
234+
]
235+
},
236+
{
237+
"cell_type": "code",
238+
"execution_count": 6,
239+
"id": "bbe54d2f-f5a4-44f1-a015-8a4d19e1097a",
240+
"metadata": {},
241+
"outputs": [],
242+
"source": [
243+
"path = \"/home/fdamicel/projects/pycourse/data/ds005588-broken-data.zip\"\n",
244+
"target = \"/home/fdamicel/projects/pycourse/data\""
245+
]
246+
},
247+
{
248+
"cell_type": "code",
249+
"execution_count": 7,
250+
"id": "e7ad9b30-c041-4edc-83d4-2cfdf984dac7",
251+
"metadata": {},
252+
"outputs": [],
253+
"source": [
254+
"import zipfile"
255+
]
256+
},
257+
{
258+
"cell_type": "code",
259+
"execution_count": 8,
260+
"id": "123149ab-4410-4444-9348-099cbf067f91",
261+
"metadata": {},
262+
"outputs": [],
263+
"source": [
264+
"with zipfile.ZipFile(path) as file:\n",
265+
" file.extractall(target)"
73266
]
267+
},
268+
{
269+
"cell_type": "code",
270+
"execution_count": 13,
271+
"id": "8d95f7c4-977f-4cc5-8f8e-80e87ec7d40a",
272+
"metadata": {},
273+
"outputs": [],
274+
"source": []
275+
},
276+
{
277+
"cell_type": "code",
278+
"execution_count": 14,
279+
"id": "3f764de2-552c-49ab-ae8c-8d8455d254c3",
280+
"metadata": {},
281+
"outputs": [],
282+
"source": []
283+
},
284+
{
285+
"cell_type": "code",
286+
"execution_count": 15,
287+
"id": "4fbd3efe-bd52-4414-99a5-42058984a3c8",
288+
"metadata": {},
289+
"outputs": [
290+
{
291+
"ename": "UnicodeDecodeError",
292+
"evalue": "'utf-8' codec can't decode byte 0xb9 in position 10: invalid start byte",
293+
"output_type": "error",
294+
"traceback": [
295+
"\u001b[31m---------------------------------------------------------------------------\u001b[39m",
296+
"\u001b[31mUnicodeDecodeError\u001b[39m Traceback (most recent call last)",
297+
"\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[15]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m lines = \u001b[43mf\u001b[49m\u001b[43m.\u001b[49m\u001b[43mreadlines\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n",
298+
"\u001b[36mFile \u001b[39m\u001b[32m<frozen codecs>:325\u001b[39m, in \u001b[36mdecode\u001b[39m\u001b[34m(self, input, final)\u001b[39m\n",
299+
"\u001b[31mUnicodeDecodeError\u001b[39m: 'utf-8' codec can't decode byte 0xb9 in position 10: invalid start byte"
300+
]
301+
}
302+
],
303+
"source": []
304+
},
305+
{
306+
"cell_type": "code",
307+
"execution_count": null,
308+
"id": "4877305d-66bb-47ab-95c9-ae9377323bef",
309+
"metadata": {},
310+
"outputs": [],
311+
"source": []
74312
}
75313
],
76314
"metadata": {

0 commit comments

Comments
 (0)