Python Debugger

From CDOT Wiki
Jump to: navigation, search

The Python module pdb defines an interactive source code debugger for Python programs. It supports the following features:

  • setting breakpoints,
  • single stepping at the source code line level,
  • inspection of stack frames,
  • source code listing, and
  • evaluation of arbitrary Python code in the context of any stack frame.

You can use the pdb module to run your Python script interactive mode for debugging purpose, for example:

$ python3 -m pdb a1_template.py
>/home/rchan/ops435/a1/a1_template.py(2)<module>()
-> '''template for ops435 assignment 1 script
(Pdb)

Debugger Commands

Now you are in the Python debugging mode with the Python script "a1_template.py" loaded. The (Pdb) prompt shown at the beginning of the line indicates that the Python interpreter is running under the debugging mode. You can type the word "help" without open or close bracket to get a list of debugging commands:

(Pdb) help
(Pdb) help

Documented commands (type help <topic>):
<source>
========================================
EOF    c          d        h         list      q        rv       undisplay
a      cl         debug    help      ll        quit     s        unt      
alias  clear      disable  ignore    longlist  r        source   until    
args   commands   display  interact  n         restart  step     up       
b      condition  down     j         next      return   tbreak   w        
break  cont       enable   jump      p         retval   u        whatis   
bt     continue   exit     l         pp        run      unalias  where    

Miscellaneous help topics:
==========================
exec  pdb

(Pdb)

Online help on Debugger commands

There are quite a bit of commands to get familiar with. However, we only need to learn a few to get started. Here are the ones that you should know: l, ll, n, s, and b

(Pdb) help l
l(ist) [first [,last] | .]

        List source code for the current file.  Without arguments,
        list 11 lines around the current line or continue the previous
        listing.  With . as argument, list 11 lines around the current
        line.  With one argument, list 11 lines starting at that line.
        With two arguments, list the given range; if the second
        argument is less than the first, it is a count.

        The current line in the current frame is indicated by "->".
        If an exception is being debugged, the line where the
        exception was originally raised or propagated is indicated by
        ">>", if it differs from the current line.
(Pdb) help ll
longlist | ll
        List the whole source code for the current function or frame.
(Pdb) help n
n(ext)
        Continue execution until the next line in the current function
        is reached or it returns.
(Pdb) help s
s(tep)
        Execute the current line, stop at the first possible occasion
        (either in a function that is called or in the current
        function).
(Pdb) help b
b(reak) [ ([filename:]lineno | function) [, condition] ]
        Without argument, list all breaks.

        With a line number argument, set a break at this line in the
        current file.  With a function name, set a break at the first
        executable line of that function.  If a second argument is
        present, it is a string specifying an expression which must
        evaluate to true before the breakpoint is honored.

        The line number may be prefixed with a filename and a colon,
        to specify a breakpoint in another file (probably one that
        hasn't been loaded yet).  The file is searched for on
        sys.path; the .py suffix may be omitted.
(Pdb)

Try it out: l, ll, b, n, s

The list command: l or list

We will first use 'l' to list Python code around the current Python statement to be executed:

(Pdb) l
  1  	#!/usr/bin/env python3
  2  ->	''' template for ops435 assignment 1 script
  3  	    put your script level docstring here...
  4  	    you can have more than one line of docstring.
  5  	    Please personlize the following author declaration:
  6  	-----------------------------------------------------------------------
  7  	OPS435 Assignment 1 - Fall 2020
  8  	Program: a1_[Seneca_name].py (replace [Seneca_name] with your Seneca User name)
  9  	Author: "Student Name"
 10  	The python code in this file (a1_[Seneca_name].py) is original work written by
 11  	"Student Name". No code in this file is copied from any other source

the longlist command: ll or longlist

We can list all the Python statements in the current file with 'll' or 'longlist' command:

(Pdb) ll
  1  	#!/usr/bin/env python3
  2  ->	''' template for ops435 assignment 1 script
  3  	    put your script level docstring here...
  4  	    you can have more than one line of docstring.
  5  	    Please personlize the following author declaration:
  6  	-----------------------------------------------------------------------
  7  	OPS435 Assignment 1 - Fall 2020
  8  	Program: a1_[Seneca_name].py (replace [Seneca_name] with your Seneca User name)
  9  	Author: "Student Name"
 10  	The python code in this file (a1_[Seneca_name].py) is original work written by
 11  	"Student Name". No code in this file is copied from any other source
 12  	except those provided by the course instructor, including any person,
 13  	textbook, or on-line resource. I have not shared this python script
 14  	with anyone or anything except for submission for grading.
 15  	I understand that the Academic Honesty Policy will be enforced and
 16  	violators will be reported and appropriate action will be taken.
 17  	'''
 18  	import os
 19  	import sys
 20  	
 21  	def leap_year(obj):
 22  	    '''
 23  	    put your function level docstring here ...
 24  	    '''
 25  	    ...
 26  	
 27  	    return status
 28  	
 29  	def sanitize(obj1,obj2):
 30  	    '''
 31  	    put your function level docstring here ...
 32  	    '''
 33  	    ...
 34  	
 35  	    return results
 36  	
 37  	def size_check(obj, intobj):
 38  	    '''
 39  	    put your function level docstring here ..
 40  	    '''
 41  	    ...
 42  	
 43  	    return status
 44  	
 45  	def range_check(obj1, obj2):
 46  	    '''
 47  	    put your function level docstring here ..
 48  	    '''
 49  	    ...
 50  	
 51  	    return status
 52  	
 53  	def usage():
 54  	    '''
 55  	    put your function level docstring here ...
 56  	    '''
 57  	    ...
 58  	    return status
 59  	
 60  	if __name__ == "__main__":
 61  	   # step 1
 62  	   if len(sys.argv) != 2:
 63  	      print(usage())
 64  	      sys.exit()
 65  	   # step 2
 66 B	   month_name = ['Jan','Feb','Mar','Apr','May','Jun',
 67  	                 'Jul','Aug','Sep','Oct','Nov','Dec']
 68  	   days_in_month = {1:31, 2:28, 3:31, 4:30, 5:31, 6:30,
 69  	                    7:31, 8:31, 9:30, 10:31, 11:30, 12:31}
 70  	   user_raw_data = sys.argv[1]
 71  	   # step 3
 72  	   allow_chars = '0123456789'
 73  	   dob = sanitize(user_raw_data, allow_chars)
 74  	   print('Sanitized user data:', dob)
 75  	   # setp 4
 76  	   result = size_check(dob,8)
 77  	   if result == False:
 78  	       print("Error 09: wrong data entered")
 79  	       sys.exit()
 80  	   # step 5
 81  	   year = int(dob[0:4])
 82  	   month = int(dob[4:6])
 83  	   day = int(dob[6:])
 84  	   # step 6
 85  	   result = range_check(year,(1900,9999))
 86  	   if result == False:
 87  	       print("Error 10: year out of range, must be 1900 or later")
 88  	       sys.exit()
 89  	   result = range_check(month,(1,12))
 90  	   if result == False:
 91  	       print("Error 02: Wrong month entered")
 92  	       sys.exit()
 93  	   result = leap_year(year)
 94  	   if result == True:
 95  	       days_in_month[2] = 29
 96  	   result = range_check(day, (1, days_in_month[month]))
 97  	   if result == False:
 98  	       print("Error 03: wrong day entered")
 99  	       sys.exit()
100  	   # step 7
101  	   new_dob = str(month_name[month - 1])+' '+ str(day)+', '+str(year)
102  	   # step 8
103  	   print("Your date of birth is:", new_dob)
(Pdb)

set the break point with 'b' or 'break'

Next, let set a break points at line 66 and 72:

(Pdb) b 66
Breakpoint 1 at /home/rchan/Desktop/ops435/2020-03/a1/ops435-a1/a1_template.py:66
(Pdb) b 72
Breakpoint 2 at /home/rchan/Desktop/ops435/2020-03/a1/ops435-a1/a1_template.py:72

At anytime, you can display all the break points and their status with just the 'b' or 'break' command:

(Pdb) b
Num Type         Disp Enb   Where
1   breakpoint   keep yes   at /home/rchan/Desktop/ops435/2020-03/a1/ops435-a1/a1_template.py:66
2   breakpoint   keep yes   at /home/rchan/Desktop/ops435/2020-03/a1/ops435-a1/a1_template.py:72

Use the 'n' command to execute the next Python statement

Here are the step-by-step execution of your Python script:

> /home/rchan/Desktop/ops435/2020-03/a1/ops435-a1/a1_template.py(2)<module>()
-> ''' template for ops435 assignment 1 script
(Pdb) n
> /home/rchan/Desktop/ops435/2020-03/a1/ops435-a1/a1_template.py(18)<module>()
-> import os
(Pdb) n
> /home/rchan/Desktop/ops435/2020-03/a1/ops435-a1/a1_template.py(19)<module>()
-> import sys
(Pdb) n
> /home/rchan/Desktop/ops435/2020-03/a1/ops435-a1/a1_template.py(21)<module>()
-> def leap_year(obj):
(Pdb) n
> /home/rchan/Desktop/ops435/2020-03/a1/ops435-a1/a1_template.py(29)<module>()
-> def sanitize(obj1,obj2):
(Pdb) n
> /home/rchan/Desktop/ops435/2020-03/a1/ops435-a1/a1_template.py(37)<module>()
-> def size_check(obj, intobj):
(Pdb) n
> /home/rchan/Desktop/ops435/2020-03/a1/ops435-a1/a1_template.py(45)<module>()
-> def range_check(obj1, obj2):
(Pdb) n
> /home/rchan/Desktop/ops435/2020-03/a1/ops435-a1/a1_template.py(53)<module>()
-> def usage():
(Pdb) n
> /home/rchan/Desktop/ops435/2020-03/a1/ops435-a1/a1_template.py(60)<module>()
-> if __name__ == "__main__":
(Pdb) n
> /home/rchan/Desktop/ops435/2020-03/a1/ops435-a1/a1_template.py(62)<module>()
-> if len(sys.argv) != 2:
(Pdb)

Please try it your self to have some fun!