dropping into the debugger on an exception

J

Jon Perez

(sorry for the duplicate post, just wanted to make the subject
line clearer)

How do you set up pdb such that you will automatically
get dropped into its prompt if an unanticipated exception
occurs in a script you are using?

ASPN Python cookbook gives you the following method
which you can add to your script and hook into sys.excepthook.
But is there a way to do it without adding stuff to your
script? (It's okay if this means having to invoke the script
from within pdb, but #1, I don't know how to get it stay inside
pdb in the case of an /unanticipated/ exception. And #2, I
don't know how to pass [the equivalent of] command-line
arguments to a script invoked from within pdb.)



def info(type, value, tb):
if hasattr(sys, 'ps1') or not sys.stderr.isatty():
# we are in interactive mode or we don't have a tty-like
# device, so we call the default hook
sys.__excepthook__(type, value, tb)
else:
import traceback, pdb
# we are NOT in interactive mode, print the exception...
traceback.print_exception(type, value, tb)
print
# ...then start the debugger in post-mortem mode.
pdb.pm()

sys.excepthook = info
 
T

Thomas Heller

Jon Perez said:
(sorry for the duplicate post, just wanted to make the subject
line clearer)

How do you set up pdb such that you will automatically
get dropped into its prompt if an unanticipated exception
occurs in a script you are using?

ASPN Python cookbook gives you the following method
which you can add to your script and hook into sys.excepthook.
But is there a way to do it without adding stuff to your
script? (It's okay if this means having to invoke the script
from within pdb, but #1, I don't know how to get it stay inside
pdb in the case of an /unanticipated/ exception. And #2, I
don't know how to pass [the equivalent of] command-line
arguments to a script invoked from within pdb.)
[...]

Is the description in the cookbook unclear? You do *not* have to add
anything to your script - save the code as a file
C:\Python23\sitecustomize.py and everything will work. And you don't
have to start the script from within pdb. The sitecustomize module is
automatically imported when Python starts - if it is found.

I'm appending the version I currently use, maybe it has some
improvements not mentioned in the online version.

Thomas

"""
# code snippet, to be included in 'sitecustomize.py'
import sys
import traceback, pdb
##import pywin.debugger

def info(type, value, tb,
excepthook=sys.__excepthook__,
print_exc=traceback.print_exception,
## debug=pywin.debugger.pm):
debug=pdb.pm):
if not __debug__ \
or not sys \
or hasattr(sys, 'ps1') \
or not sys.stderr.isatty() \
or not sys.stdin.isatty() \
or not hasattr(sys, "last_traceback"):
# call the default hook if one of the following conditions
# is satisfied:
# - Python is running with the -O flag (__debug__ == 0)
# - sys is None (python is shutting down, and the sys module
# already has been cleared)
# - we are in interactive mode (sys has a 'ps1' attribute)
# - sys.stderr is not a tty: we are not connected to a terminal
# - no last_traceback attribute in sys (SyntaxError)
excepthook(type, value, tb)
else:
# print the exception...
print_exc(type, value, tb)
# ...then start the debugger in post-mortem mode.
debug()

sys.excepthook = info
"""
 
J

Jon Perez

Thomas said:
Is the description in the cookbook unclear? You do *not* have to add
anything to your script - save the code as a file
C:\Python23\sitecustomize.py and everything will work. And you don't
have to start the script from within pdb. The sitecustomize module is
automatically imported when Python starts - if it is found.

Yes, I'm aware of this. I don't want to add this to sitecustomize.py
because I don't want this happening all the time.

I was hoping to for a different strategy. Would it be possible
to start up pdb(), call a script from there, give it the equivalent
of command line arguments, do a cont (or whatever is required) and
then have it /stay/ within pdb if an unanticipated exception occurs
(as opposed to having to set up a breakpoint)?
 
P

Peter Hansen

Jon said:
Yes, I'm aware of this. I don't want to add this to sitecustomize.py
because I don't want this happening all the time.

Just to be clear: you don't want this to happen all the time,
you want it to happen only with a particular script, yet you
don't want to modify that script at all?

Would it be sufficient to have a local sitecustomize.py file
in the directory where the script is, or do you have other
scripts in that folder which you don't want to get the same
treatment?

What about a wrapper which you invoke instead of the script,
which sets this up and then runs the real script using
"import" and an appropriate direct call?

-Peter
 
T

Thomas Heller

Peter Hansen said:
Just to be clear: you don't want this to happen all the time,
you want it to happen only with a particular script, yet you
don't want to modify that script at all?

I also don't understand *why* he wants to have it that way.

There's also one (hidden?) feature in the code I posted: The excepthook
only calls the debugger when __debug__ is true, so you can also avoid
the debugger when the python is started with the -O flag.

Thomas
 
J

Jon Perez

Peter said:
Just to be clear: you don't want this to happen all the time,
you want it to happen only with a particular script, yet you
don't want to modify that script at all?

Correct. I don't even want it to happen all of the time
with that particular script (because I may eventually
deploy it for others to use who may be confused by
being dropped into pdb). I can easily disable it by not
assigning info() to sys.excepthook. But like I said, preferably,
I don't even want to add anything to the script source code.
Would it be sufficient to have a local sitecustomize.py file
in the directory where the script is, or do you have other
scripts in that folder which you don't want to get the same
treatment?
What about a wrapper which you invoke instead of the script,
which sets this up and then runs the real script using
"import" and an appropriate direct call?

These are both acceptable to a certain extent, and frankly,
if these were the alternatives, I will just stick to putting
info() in any script I intend to debug this way.

I was just wondering if there wasn't a cleaner/more intuitive
way which would be to just invoke the script from within pdb
and have pdb do the right thing (i.e. stay within itself) upon
an exception.

Can't one prevent pdb from exiting if an (unanticipated)
exception occurs in a script (or function) it invokes?

And secondly, how do you pass command-line arguments to a
script invoked from within pdb? I'm not even sure how to
invoke a script proper like you would from a command line, all
the examples I see invoke specific functions within a script.

Not being able to accomplish simple things like this in a
straightforward manner is what's keeping me from wholeheartedly
embracing pdb.
 
J

Jon Perez

Thomas said:
I also don't understand *why* he wants to have it that way.

Just in case you missed the answer I gave earlier...

I don't even want this behaviour all the time with the same
script because end-users will be confused if they get dropped
into pdb. Believe me, you don't want to explain what pdb is
to people who have a hard time even navigating via the
command prompt!

The best situation would be to be able to invoke this behaviour
only when I want it (i.e. during coding/debugging) and not have
to change anything (including sitecustomize.py) when I don't
want it around (the same machine might be used by both the
developer and the end-user).

Essentially, I believe this means being able to invoke the
script from within pdb and getting pdb to remain in itself
in case of an unanticipated exception (is that too much to ask?
:-D) I want to be able to use pdb like other debuggers, i.e.
it's only active when I call a program under it, and also behave
like other debuggers which do not exit if an error occurs.
 
P

Peter Hansen

Jon said:
Just in case you missed the answer I gave earlier...

I don't even want this behaviour all the time with the same
script because end-users will be confused if they get dropped
into pdb. Believe me, you don't want to explain what pdb is
to people who have a hard time even navigating via the
command prompt!

The best situation would be to be able to invoke this behaviour
only when I want it (i.e. during coding/debugging)

Basically this seems to require command line options, right?j
If so, just include a standard snippet in the __main__ section
of your scripts which checks the first command line option to
see if it's "--jon's_special_pdb_magic" (or whatever ;-) ) and
then programmatically invoke the excepthook stuff...

-Peter
 
T

Thomas Heller

Peter Hansen said:
Basically this seems to require command line options, right?j
If so, just include a standard snippet in the __main__ section
of your scripts which checks the first command line option to
see if it's "--jon's_special_pdb_magic" (or whatever ;-) ) and
then programmatically invoke the excepthook stuff...

Or he writes a simple script (debug.py?) by copying the
"if __name__ == '__main__:'" section of lib/pdb.py, and
throws in an additional assignment to sys.excepthook,
and then runs "python debug.py myscript.py <script-args>"

Thomas
 
C

Chris Liechti

Just in case you missed the answer I gave earlier...

I don't even want this behaviour all the time with the same
script because end-users will be confused if they get dropped
into pdb. Believe me, you don't want to explain what pdb is
to people who have a hard time even navigating via the
command prompt!

The best situation would be to be able to invoke this behaviour
only when I want it (i.e. during coding/debugging) and not have
to change anything (including sitecustomize.py) when I don't
want it around (the same machine might be used by both the
developer and the end-user).

i usualy use something like that:
if __name__ == '__main__':
try:
from optparse import OptionParser

parser = OptionParser()
#...
parser.add_option("-d", "--debug",
action="store_true", dest="debug", default=False,
help="enable debug outputs")

(options, args) = parser.parse_args()

logger.setLevel(logging.WARN)
if options.verbose:
logger.setLevel(logging.INFO)

if options.debug:
logger.setLevel(logging.DEBUG)

main()
except SystemExit:
raise
except Exception, msg:
if debug:
#raise #i usualy use that
pdb.pm() #that's what you want
else:
sys.stderr.write("%s: %s\n" % (msg.__class__.__name__, msg))
sys.exit(1)


that way, adding a -d on the command line will enable more log messages and
full tracebacks (or pdb). you could of also use a separate option for pdb
or only enable it if multiple -ddd are given (debug level increased)

chris
 
F

Fernando Perez

Jon said:
(sorry for the duplicate post, just wanted to make the subject
line clearer)

How do you set up pdb such that you will automatically
get dropped into its prompt if an unanticipated exception
occurs in a script you are using?

You may want to try out ipython (http://ipython.scipy.org). It does exactly
what you want (and a lot more):

In [1]: cd ~/test
/usr/local/home/fperez/test

In [2]: pdb
Automatic pdb calling has been turned ON

In [3]: run error
hi
Ramp time: 0.0
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)

/usr/local/home/fperez/test/error.py
109
110 print 'speedup:',Rtime/RNtime
111
112
--> 113 if __name__ == '__main__': main()

/usr/local/home/fperez/test/error.py in main()
104 array_num = zeros(size,'d')
105 for i in xrange(reps):
--> 106 RampNum(array_num, size, 0.0, 1.0)
107 RNtime = time.clock()-t0
108 print 'RampNum time:', RNtime

/usr/local/home/fperez/test/error.py in RampNum(result, size, start, end)
88 tmp = zeros(1e2)
89 step = (end-start)/(size-1-tmp)
---> 90 result[:] = arange(size)*step + start
91
92 def main():

ValueError: frames are not aligned
/usr/local/home/fperez/test/error.py(90)RampNum()
-> result[:] = arange(size)*step + start
(Pdb) print start
0.0


You can then quit pdb, type 'pdb' again to disable the feature, and move on.

Cheers,

f
 
J

Jon Perez

Thanks everyone, for taking the time out to answer...

Hopefully pdb operation can one day be as simple and
straightforward as with other debuggers. Run pdb,
invoke a script from it, and have it remain within pdb
when an exception happens.
 
Z

ziaran

Jon said:
Thanks everyone, for taking the time out to answer...

Hopefully pdb operation can one day be as simple and
straightforward as with other debuggers. Run pdb,
invoke a script from it, and have it remain within pdb
when an exception happens.

Jon, I think rpdb does that,
http://rpdb.digitalpeers.com/
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,902
Latest member
Elena68X5

Latest Threads

Top