see /examples/week-03/exceptions/recursion_limit.py
i = 0
def recurse():
global i
i += 1
print i
recurse()
recurse()
That value can be changed with sys.setrecursionlimit(N)
see /examples/week-03/exceptions/sys_mod_frame_inspect.py
import sys, traceback
def one():
one_local_var = "foo"
two()
def two():
two_local_var = "foo"
three()
def three():
# print the stack
for num in range(3):
frame = sys._getframe(num)
show_frame(num, frame)
# or,
traceback.print_stack()
# or more rudely
1/0
def show_frame(num, frame):
print " frame = sys._getframe(%s)" % num
print " function = %s()" % frame.f_code.co_name
print " file/line = %s:%s" % (frame.f_code.co_filename, frame.f_lineno)
print " locals: %s" % frame.f_locals.keys()
one()
Take a look at /examples/week-03-debugging/exceptions/visualize_frames.py
[ OUTER FRAMES ]:
module with {}
main with {'x': 'baz'}
func_one with {'y': 'baz'}
func_two with {'z': 'baz'}
you are here: file=frames_and_stacks.py line=16 function=func_two
The inspect module can do a lot, read thedocs
When either the interpreter or your own code detects an error condition, an exception may be raised
The exception will bubble up the call stack until it is handled. If it's not, the interpreter will exit.
At each level in the stack, a handler can either:
The most basic form uses the builtins try and except
try:
print "do some stuff"
1 / 0
print "do some more stuff"
except:
print "stuff failed"
def divide(x, y):
try:
print "line 1"
result = x / y
print "line 2"
except ZeroDivisionError as e:
print "caught division error: %s" % str(e)
except Exception as e:
print "exception %s. message: %s" % (type(e), e.args)
raise
else:
print "everything worked great"
return result
finally:
print "this is executed no matter what"
[name for name in dir(__builtin__) if "Error" in name]
If one of these meets your needs, by all means use it. Else, define a new exception type by subclassing one, perhaps Exception
In [32]: import exceptions
In [33]: exceptions?
Type: module
String Form:
Docstring:
Python's standard exception class hierarchy.
Exceptions found here are defined both in the exceptions module and the
built-in namespace
Sometimes you need to create your own
class CustomException( Exception ):
pass
raise CustomException( 'pass an error message here' )
It's that simple
Modify the example program examples/week-03/wikidef/
Debuggers are code which allows the inspection of state of other code during runtime.
Rudimentary tools
Console debuggers
GUI debuggers
investigate import issues with -v
inspect environment after running script with -i
A flexible logging system that comes with the standard library
Any module using the logging api can have logging output routed the same as your code
The four main classes of logging
Basic handling, filtering, and formatting can be done through the logging module's basicConfig method
More complex and configurable configurations can be created with the class interfaces for each of those tasks
Timestamps can be included by passing the kwarg format='%(asctime)s %(message)s')
to basicConfig
import logging
logging.basicConfig(filename='example.log', level=logging.DEBUG)
logging.debug("debug level message")
logging.warning("debug level message")
see examples/logging/example1.py
import logging
# create logger
logger = logging.getLogger('simple_example')
logger.setLevel(logging.DEBUG)
# create console handler and set level to debug
handler = logging.StreamHandler()
handler.setLevel(logging.DEBUG)
# create formatter
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# add formatter to handler
handler.setFormatter(formatter)
# add handler to logger
logger.addHandler(handler)
# 'application' code
logger.debug('debug message')
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')
Most logging considerations revolve around the different handlers
Let's play with some of the code in /examples/week-03/logging/
Pros:
Cons:
The 4-fold ways of invoking pdb
Note: in most cases where you see the word 'pdb' in the examples, you can replace it with 'ipdb'. ipdb is the ipython enhanced version of pdb which is mostly compatible, and generally easier to work with. But it doesn't ship with Python.
For analyzing crashes due to uncaught exceptions
python -i script.py
import pdb; pdb.pm()
pdb.run('some.expression()')
python -m pdb script.py
"-m [module]" finds [module] in sys.path and executes it as a script
Insert the following line into your code where you want execution to halt:
import pdb; pdb.set_trace()
It's not always OK/possible to modify your code in order to debug it, but this is often the quickest way to begin inspecting state
The goal of each of the preceding techniques was to get to the pdb prompt and get to work inspecting state
% python -m pdb define.py robot
pdb> break api.py:21
# list breakpoints
pdb> break
pdb> clear 1
# print lines of code in current context
pdb> list
# print lines in range
pdb> list 1,28
# print stack trace, aliased to (bt, w)
pdb> where
# move one level up the stack
pdb> up
# move one level down the stack
pdb> down
# execute until function returns
pdb> return
# Execute the current line, stop at the first possible occasion
pdb> step
# Continue execution until the next line in the current function is reached or it returns.
pdb> next
# Continue execution
pdb> continue
pdb> help break
b(reak) ([file:]lineno | function) [, condition]
With a line number argument, set a break there in the current
file. With a function name, set a break at first executable line
of that function. Without argument, list all breaks. 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.
Clear (delete) breakpoints
clear [bpnumber [bpnumber...]]
disable breakpoints
disable [bpnumber [bpnumber...]]
enable breakpoints
enable [bpnumber [bpnumber...]]
pdb> help condition
condition bpnumber str_condition
str_condition is a string specifying an expression which
must evaluate to true before the breakpoint is honored.
If str_condition is absent, any existing condition is removed;
i.e., the breakpoint is made unconditional.
Set conditions
condition 1 x==1
Clear conditions
condition 1
see debugging/examples/long_loop.py
On error condition, drop to pdb
nosetests --pdb
On test failure, drop to pdb:
nosetests --pdb-failures
From JetBrains, and integrates some of their vast array of development tools
Free Community Edition (CE) is available
Good visual debugging support
A multi-language IDE
Python support via http://pydev.org/
Automatic variable and expression watching
Supports a lot of debugging features like conditional breakpoints, provided you look in the right places!
Further reading
http://pydev.org/manual_adv_debugger.htmlA multi platform Python debugger with threading support
Easier to start up and get debugging
winpdb your_app.py
To debug an application running a different Python, even remotely:
import rpdb2; rpdb2.start_embedded_debugger("password")
Find the wikidef app in the examples folder
Using (i)pdb in module mode (python -m pdb ) debug the app and find the server type that wikipedia is using by looking at response.headers.headers in Wikipedia.article
You can enter the debugger by running
python -m pdb ./define.py robot
You can get to the code by walking through each line with 's'tep and 'n'ext commands, or by setting a breakpoint and 'c'ontinuing.
What's the result?
/