├── requirements.txt
├── hello.js
├── coin_01.png
├── character.png
├── nodejs_hello.js
├── index.html
├── test_myGame.py
├── PREP.md
├── game.py
├── final_game.py
└── README.md
/requirements.txt:
--------------------------------------------------------------------------------
1 | arcade
--------------------------------------------------------------------------------
/hello.js:
--------------------------------------------------------------------------------
1 | function hello_message(person) {
2 | return 'Hello ' + person;
3 | }
--------------------------------------------------------------------------------
/coin_01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pauleveritt/visual_debugging/HEAD/coin_01.png
--------------------------------------------------------------------------------
/character.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pauleveritt/visual_debugging/HEAD/character.png
--------------------------------------------------------------------------------
/nodejs_hello.js:
--------------------------------------------------------------------------------
1 | function hello_message(person) {
2 | return 'Hello ' + person;
3 | }
4 |
5 | console.log(hello_message('world'));
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
Hello World
3 |
4 | Hello World
5 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/test_myGame.py:
--------------------------------------------------------------------------------
1 | from unittest import TestCase
2 |
3 |
4 | class TestMyGame(TestCase):
5 | def test_setup(self):
6 | from game import MyGame
7 | game = MyGame(100, 100, 'Test')
8 | assert game.is_stopped is True
9 |
10 | def test_not_stopped(self):
11 | from game import MyGame
12 | game = MyGame(100, 100, 'Test')
13 | game.is_stopped = False
14 | game.on_draw()
15 | assert game.is_stopped is True
16 |
17 | def test_stopped(self):
18 | from game import MyGame
19 | game = MyGame(100, 100, 'Test')
20 | game.is_stopped = True
21 | game.on_draw()
22 | assert game.is_stopped is True
23 |
--------------------------------------------------------------------------------
/PREP.md:
--------------------------------------------------------------------------------
1 | ### Before
2 |
3 | - Delete Cython speedups
4 | * \helpers\pydev\_pydevd_bundle
5 | * Remove pydevd_cython.so
6 | - Uninstall ipython
7 | - Default theme, big font
8 | - Ensure Presentation Assistant is on
9 | - Turn off various tools and status bar
10 | - Close Chrome
11 | - Django/Flask template debugging projects open
12 | - Have the numpy/pandas project open
13 | - Delete the run configuration for game.py
14 | - Check value of break on any Python exception
15 | - Delete any watch expressions
16 | - Test exists, with a run configuration for all tests
17 | - Delete run configurations
18 |
19 | - Turn off Notifications and other macOS toolbar stuff
20 | - Close all the Safari tabs
21 | - 1280x720
22 | - Microphone
--------------------------------------------------------------------------------
/game.py:
--------------------------------------------------------------------------------
1 | import random
2 |
3 | import arcade
4 |
5 |
6 | class MyGame(arcade.Window):
7 | def __init__(self, width: int, height: int, title: str) -> None:
8 | super().__init__(width, height, title)
9 | arcade.set_background_color(arcade.color.AMAZON)
10 | self.score: int = 0
11 |
12 | self.all_sprites_list = arcade.SpriteList()
13 | self.player_sprite = arcade.Sprite('character.png', 0.5)
14 | self.player_sprite.center_x = 50
15 | self.player_sprite.center_y = 50
16 | self.all_sprites_list.append(self.player_sprite)
17 |
18 | self.coin_list = arcade.SpriteList()
19 | for i in range(50):
20 | coin = arcade.Sprite('coin_01.png', 0.2)
21 | coin.center_x = random.randrange(600)
22 | coin.center_y = random.randrange(600)
23 | self.all_sprites_list.append(coin)
24 | self.coin_list.append(coin)
25 |
26 | def on_draw(self):
27 | arcade.start_render()
28 | output = f'Score: {self.score:02d}'
29 | arcade.draw_text(output, 100, 100, arcade.color.WHITE)
30 | self.all_sprites_list.draw()
31 |
32 | def update(self, delta_time: float) -> None:
33 | self.all_sprites_list.update()
34 | hit_list = arcade.check_for_collision_with_list(
35 | self.player_sprite,
36 | self.coin_list
37 | )
38 | for coin in hit_list:
39 | coin.kill()
40 | self.score += 1
41 |
42 | def on_mouse_motion(self, x, y, dx, dy):
43 | self.player_sprite.center_x = x
44 | self.player_sprite.center_y = y
45 |
46 |
47 | def main():
48 | MyGame(600, 600, 'My Awesome Game')
49 | arcade.run()
50 |
51 |
52 | if __name__ == '__main__':
53 | main()
54 |
--------------------------------------------------------------------------------
/final_game.py:
--------------------------------------------------------------------------------
1 | import random
2 |
3 | import arcade
4 |
5 |
6 | class MyGame(arcade.Window):
7 | def __init__(self, width, height, title):
8 | super().__init__(width, height, title)
9 | arcade.set_background_color(arcade.color.AMAZON)
10 | self.score = 0
11 |
12 | self.all_sprites_list = arcade.SpriteList()
13 | self.player_sprite = arcade.Sprite('character.png', 0.5)
14 | self.player_sprite.center_x = 50
15 | self.player_sprite.center_y = 50
16 | self.all_sprites_list.append(self.player_sprite)
17 | self.is_stopped: bool = True
18 |
19 | self.coin_list = arcade.SpriteList()
20 | for i in range(50):
21 | coin = arcade.Sprite('coin_01.png', 0.2)
22 | coin.center_x = random.randrange(600)
23 | coin.center_y = random.randrange(600)
24 | self.all_sprites_list.append(coin)
25 | self.coin_list.append(coin)
26 |
27 | def on_draw(self):
28 | arcade.start_render()
29 | output = f'Score: {self.score:02d}'
30 | if self.is_stopped:
31 | arcade.draw_text(output, 100, 100, arcade.color.WHITE)
32 | self.is_stopped = True
33 | self.all_sprites_list.draw()
34 |
35 | def animate(self, delta_time):
36 | self.all_sprites_list.update()
37 | hit_list = arcade.check_for_collision_with_list(
38 | self.player_sprite,
39 | self.coin_list
40 | )
41 |
42 | for coin in hit_list:
43 | coin.kill()
44 | self.score += 1
45 |
46 | def on_mouse_motion(self, x, y, dx, dy):
47 | self.is_stopped = False
48 | self.player_sprite.center_x = x
49 | self.player_sprite.center_y = y
50 |
51 |
52 | def main():
53 | MyGame(600, 600, 'My Game')
54 | arcade.run()
55 |
56 |
57 | if __name__ == '__main__':
58 | main()
59 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Visual Debugging Webinar
2 |
3 | - Debugging without PyCharm's debugger: print and pdb
4 | - First use of the debugger (and the Cython speedups)
5 | - Breakpoints
6 | - Using the console/IPython at a breakpoint
7 | - Conditional breakpoints
8 | - All flavors of stepping through code
9 | - Moving through stack frames
10 | - Setting watches
11 | - Attaching to processes
12 | - Debugging during testing
13 | - Extracting type information
14 | - Django/Flask template debugging
15 | - Viewing numpy/pandas data frames
16 |
17 |
18 |
19 | ### Old-Fashioned Debugging
20 |
21 | - Problem: Where is 0,0
22 | - print statements
23 | - import pdb; pdb.set_trace()
24 |
25 |
26 | ### Visual Debugging
27 |
28 | - Run program like normal, under the debugger
29 | - Install Cython speedups
30 | - Use breakpoint to solve first problem
31 |
32 | ### Poking Around
33 |
34 | - Problem: I want to use f-string `f'Score: {self.score:02d}'` but I'm not sure how
35 | - Interactive would help
36 | - Set breakpoint, then use Evaluate Expression
37 | - Or, Console
38 | - Install iPython and use it
39 |
40 | ### Breakpoints
41 |
42 | - Problem: What is that "delta_time" thing?
43 | - Set breakpoint, observe value, click "Continue"
44 | - Clear breakpoint, click "Continue"
45 | - Problem: wrong filename, what directory am I in?
46 | - Any Exception breakpoint
47 |
48 | ## Stepping
49 |
50 | - Problem: 50 coins at random positions
51 | - Add for loop, but is random doing the right thing?
52 | - Set breakpoint, start regular stepping
53 | - Set breakpoint outside, and step into
54 | - Ditto, step over
55 | - Problem: How does Arcade collisions work?
56 | - Add code then step into
57 |
58 | ### Watch Expressions
59 |
60 | - Problem: Are the number of coins actually decreasing?
61 | - Set breakpoint in for coin in hit_list
62 | - Add a watch expression: len(self.coin_list)
63 | - Cause collision with multiple coins
64 | - Step through and see the watch expression value
65 |
66 | ### Stack Frames
67 |
68 | - Problem: Which coin is in _set_center_x?
69 | - In for loop, step into setting the x
70 | - Move back up the stack
71 | - Observe the watch expression and self.score
72 |
73 | ### Debug During Testing
74 |
75 | - Problem: TDD for "Don't show score when mouse is moving"
76 | - Write a test to see if score goes up on collision
77 | - It fails, I'm confused
78 | - Use debugging
79 | - Fix tests, clear breakpoint, re-run
80 |
81 | ### Attach to Process
82 |
83 | - Run ``game.py`` from command line
84 | - Use "Attach to Process" and then debug it
85 |
86 | ### Extract Type Information
87 |
88 | - Preferences -> Build -> Python Debugger, checkbox for
89 | `Collect`
90 |
91 | ### Django and Flask
92 |
93 | - Open Flask project
94 | - Set a breakpoint in a template
95 |
96 | ### Extra Credit
97 |
98 | - NodeJS/Chrome debugging
99 | - Configuring Stepping
100 | - Keyboard shortcuts for stepping
101 | - Show Execution Point button in toolbar when you get lost
102 | - Mute Breakpoints button
103 | - Inspect watch value in separate window
104 |
--------------------------------------------------------------------------------