[Python-checkins] r47201 - sandbox/trunk/pdb/mpdb.py sandbox/trunk/pdb/mthread.py
matt.fleming
python-checkins at python.org
Sun Jul 2 23:27:17 CEST 2006
Author: matt.fleming
Date: Sun Jul 2 23:27:17 2006
New Revision: 47201
Modified:
sandbox/trunk/pdb/mpdb.py
sandbox/trunk/pdb/mthread.py
Log:
move all the thread debugging code into mthread.py and now we can pass arguments to the script being debugged.
Modified: sandbox/trunk/pdb/mpdb.py
==============================================================================
--- sandbox/trunk/pdb/mpdb.py (original)
+++ sandbox/trunk/pdb/mpdb.py Sun Jul 2 23:27:17 2006
@@ -58,14 +58,6 @@
self.lastcmd = ''
self.connection = None
self.debug_thread = False
- # We don't trace the MainThread, so the tracer for the main thread is
- # None.
- self.tracers = [None]
- self.threads = [threading.currentThread()]
- self.current_thread = self.threads[0]
-
- self._info_cmds.append('target')
- self._info_cmds.append('thread')
def _rebind_input(self, new_input):
""" This method rebinds the debugger's input to the object specified
@@ -173,17 +165,6 @@
args = arg.split()
if 'target'.startswith(args[0]) and len(args[0]) > 2:
self.msg("target is %s" % self.target)
- elif 'thread'.startswith(args[0]) and len(args[0])> 2:
- if not self.debug_thread:
- self.errmsg('Thread debugging is not on.')
- return
- # We need some way to remove old thread instances
- for t in self.threads:
- if t == self.current_thread:
- self.msg('* %d %s' % (self.threads.index(t)+1, t))
- else:
- self.msg(' %d %s' % (self.threads.index(t)+1, t))
- return
else:
pydb.Pdb.do_info(self, arg)
@@ -199,8 +180,6 @@
self.msg_nocr("info %s --" % cmd)
if 'target'.startswith(cmd):
self.msg("Names of targets and files being debugged")
- elif 'thread'.startswith(cmd):
- self.msg('Information about active and inactive threads.')
else:
pydb.Pdb.info_helper(self, cmd)
@@ -212,29 +191,16 @@
args = arg.split()
if 'thread'.startswith(args[0]):
- threading.settrace(self.thread_trace_dispatch)
+ try:
+ import mthread
+ except ImportError:
+ self.errmsg('Thread debugging is not on')
+ return
+ mthread.init(self.msg, self.errmsg)
self.msg('Thread debugging on')
self.debug_thread = True
return
- def thread_trace_dispatch(self, frame, event, arg):
- """ Create an MTracer object so trace the thread. """
- # This method is called when a thread is being created with the
- # threading module. The _MainThread is no longer of primary concern,
- # this new thread is.
- try:
- from mthread import MTracer
- except ImportError:
- self.errmsg('Could not import mthread.MTracer')
- sys.settrace(None)
- return # Thread not being traced
-
- self.threads.append(threading.currentThread())
- self.msg('New thread: %s' % self.threads[-1])
- m = MTracer(self.breaks, self.filename, self.stdout)
- self.tracers.append(m)
- sys.settrace(m.trace_dispatch)
-
# Debugger commands
def do_attach(self, addr):
""" Attach to a process or file outside of Pdb.
@@ -443,84 +409,13 @@
self.msg("Re exec'ing\n\t%s" % self._sys_argv)
os.execvp(self._sys_argv[0], self._sys_argv)
-
-
- def do_thread(self, arg):
- """Use this command to switch between threads.
-The new thread ID must be currently known.
-
-List of thread subcommands:
-
-thread apply -- Apply a command to a thread
-
-Type "help thread" followed by thread subcommand name for full documentation.
-Command name abbreviations are allowed if unambiguous.
-"""
- if not self.debug_thread:
- self.errmsg('Thread debugging not on.')
- return
- args = arg.split()
- if len(args) == 0:
- self.msg('Current thread is %d (%s)' % \
- (self.threads.index(self.current_thread)+1,
- self.current_thread))
- return
- if len(args) < 2:
- if args[0].isdigit():
- # XXX Switch to a different thread, although this doesn't
- # actually do anything yet.
- t_num = int(args[0])-1
- if t_num > len(self.threads):
- self.errmsg('Thread ID %d not known.' % t_num+1)
- return
- self.current_thread = self.threads[t_num]
- self.msg('Switching to thread %d (%s)' % (t_num+1, \
- self.current_thread))
- return
- self.errmsg('Please specify a Thread ID')
- return
- if len(args) < 3:
- self.errmsg('Please specify a command following the thread' \
- + ' ID')
- return
- if len(self.threads) == 0:
- self.errmsg('No threads')
- return
- if len(self.threads) < int(args[1]):
- self.errmsg('Thread ID %d not known.' % int(args[1]))
- return
- # These should always be in sync
- t = self.threads[int(args[1])-1]
- t_tracer = self.tracers[int(args[1])-1]
- func = args[2]
- if len(args) > 2:
- str_params = ""
- for w in args[3:]:
- str_params += w
- str_params.rstrip()
- eval('t_tracer.do_' + func + '(str_params)')
- #except AttributeError:
- # self.errmsg('No such thread subcommand')
- # return
- else:
- try:
- eval('t_tracer.do_'+func+'()')
- except AttributeError:
- self.errmsg('Undefined thread apply subcommand "%s".' \
- % args[0])
- return
-
-def pdbserver(addr):
+def pdbserver(addr, m):
""" This method sets up a pdbserver debugger that allows debuggers
to connect to 'addr', which a protocol-specific address, i.e.
tcp = 'tcp mydomainname.com:9876'
serial = 'serial /dev/ttyC0'
"""
- m = MPdb()
- m._sys_argv = ['python']
- for i in sys.argv:
- m._sys_argv.append(i)
- m._program_sys_argv = sys.argv[1:]
+ m._program_sys_argv = list(m._sys_argv[2:])
m.mainpyfile = m._program_sys_argv[1]
m.do_pdbserver(addr)
while True:
@@ -549,37 +444,38 @@
def main():
""" Main entry point to this module. """
opts, args = parse_opts()
+
+ mpdb = MPdb()
+ mpdb._sys_argv = ['python']
+ for i in sys.argv:
+ mpdb._sys_argv.append(i)
+ mpdb._program_sys_argv = mpdb._sys_argv[4:]
+ sys.argv = list(args)
+ if not opts.scriptname:
+ if not args and not opts.target:
+ print 'Error: mpdb.py must be called with a script name if ' \
+ + '-p or -t switches are not specified.'
+ sys.exit(1)
+ elif not opts.target:
+ mainpyfile = args[0]
+ else:
+ mainpyfile = opts.scriptname
if opts.target:
target(opts.target)
sys.exit()
elif opts.pdbserver:
- pdbserver(opts.pdbserver)
+ pdbserver(opts.pdbserver, mpdb)
sys.exit()
- else:
- if not opts.scriptname:
- if not args:
- print 'Error: mpdb.py must be called with a script name if ' \
- + '-p or -t switches are not specified.'
- sys.exit(1)
- else:
- mainpyfile = args[0]
- if not os.path.exists(mainpyfile):
- print 'Error:', mainpyfile, 'does not exist'
- sys.exit(1)
- mpdb = MPdb()
+
while 1:
try:
- mpdb._sys_argv = ['python']
- for i in sys.argv:
- mpdb._sys_argv.append(i)
- mpdb._program_sys_argv = mpdb._sys_argv[1:]
mpdb._runscript(mainpyfile)
if mpdb._user_requested_quit:
break
mpdb.msg("The program finished and will be restarted")
except Restart:
sys.argv = list(mpdb._program_sys_argv)
- mpdb.msg('Restarting with %s with arguments:\n\t%s'
+ mpdb.msg('Restarting %s with arguments:\n\t%s'
% (mpdb.filename(mainpyfile),
' '.join(mpdb._program_sys_argv[1:])))
except SystemExit:
@@ -605,6 +501,7 @@
# Parse arguments
def parse_opts():
parser = OptionParser()
+ parser.disable_interspersed_args()
parser.add_option("-s", "--script", dest="scriptname",
help="The script to debug")
parser.add_option("-t", "--target", dest="target",
@@ -615,7 +512,7 @@
+ "command. The arguments should be of the form," \
+ " 'protocol address scriptname'.")
(options, args) = parser.parse_args()
- return (options,args)
+ return (options, args)
if __name__ == '__main__':
main()
Modified: sandbox/trunk/pdb/mthread.py
==============================================================================
--- sandbox/trunk/pdb/mthread.py (original)
+++ sandbox/trunk/pdb/mthread.py Sun Jul 2 23:27:17 2006
@@ -13,11 +13,10 @@
which is useful, for instance, if a breakpoint occurs inside
a thread's run() method.
"""
- def __init__(self, breaks={}, filename=None, stdout=None):
+ def __init__(self, msg, errmsg, breaks={}, filename=None):
self.thread = threading.currentThread()
- if stdout is None:
- stdout = sys.stdout
- self.out = stdout
+ self.msg = msg
+ self.errmsg = errmsg
# Each tracer instance must keep track of its own breakpoints
self.breaks = breaks
self.fncache = {}
@@ -115,10 +114,10 @@
except TypeError:
err = self.set_break(filename, line, temporary, cond)
- if err: print >> self.out, err
+ if err: self.msg, err
else:
bp = self.get_breaks(filename, line)[-1]
- print >> self.out, "Breakpoint %d set in file %s, line %d." \
+ self.msg, "Breakpoint %d set in file %s, line %d." \
% (bp.number, self.filename(bp.file), bp.line)
def __parse_filepos(self, arg):
@@ -132,8 +131,8 @@
filename = arg[:colon].rstrip()
f = self.lookupmodule(filename)
if not f:
- print >> self.out, "%s not found from sys.path" % \
- self._saferepr(filename)
+ self.msg("%s not found from sys.path" %
+ self._saferepr(filename))
return (None, None, None)
else:
filename = f
@@ -141,7 +140,7 @@
try:
lineno = int(arg)
except ValueError, msg:
- print >> self.out, 'Bad lineno: %s' % str(arg)
+ self.msg('Bad lineno: %s' % str(arg))
return (None, filename, None)
return (None, filename, lineno)
else:
@@ -177,10 +176,10 @@
# last thing to try
(ok, filename, ln) = self.lineinfo(arg)
if not ok:
- print >> self.out, 'The specified object %s is not' % \
- str(repr(arg)),
- print >> self.out, ' a function, or not found' \
- +' along sys.path or no line given.'
+ self.msg('The specified object %s is not ' \
+ ' a function, or not found' \
+ ' along sys.path or no line given.' %
+ str(repr(arg)))
return (None, None, None)
funcname = ok # ok contains a function name
@@ -237,29 +236,29 @@
"""
line = linecache.getline(filename, lineno)
if not line:
- print >>self.out, 'End of file'
+ self.errmsg('End of file')
return 0
line = line.strip()
# Don't allow setting breakpoint at a blank line
if (not line or (line[0] == '#') or
(line[:3] == '"""') or line[:3] == "'''"):
- print >>self.out, '*** Blank or comment'
+ self.errmsg('Blank or comment')
return 0
return lineno
def trace_dispatch(self, frame, event, arg):
self.curframe = frame
if event == 'line':
- print >> self.out, self.thread.getName(),'*** line'
- return self.trace_dispatch
+ self.msg('%s *** line' % self.thread.getName())
+ return self.dispatch_line
if event == 'call':
- print >> self.out, self.thread.getName(), '*** call'
+ self.msg('%s *** call' % self.thread.getName())
return self.trace_dispatch
if event == 'return':
- print >> self.out, self.thread.getName(), '*** return'
+ self.msg('%s *** return' % self.thread.getName())
return self.trace_dispatch
if event == 'exception':
- print >> self.out, '*** exception'
+ self.msg('%s *** exception' % self.thread.getName())
return self.trace_dispatch
if event == 'c_call':
print '*** c_call'
@@ -272,3 +271,57 @@
return self.trace_dispatch
print 'bdb.Bdb.dispatch: unknown debugging event:', repr(event)
return self.trace_dispatch
+
+ def dispatch_line(self, frame, event, arg):
+ print frame.f_code.co_filename, self.thread.getName()
+ return self.trace_dispatch
+
+class ThreadDebug(object):
+ def __init__(self, msg, errmsg):
+ self.msg = msg
+ self.errmsg = errmsg
+ self.threads = []
+ self.tracers = []
+ self.current_thread = None
+
+ def trace_dispatch_init(self, frame, event, arg):
+ t = threading.currentThread()
+ self.threads.append(t)
+ m = MTracer(self.msg, self.errmsg)
+ self.tracers.append(m)
+
+ sys.settrace(m.trace_dispatch)
+
+ def get_current_thread(self):
+ self.msg('Current thread is %d (%s)' % \
+ (self.threads.index(self.current_thread)+1,
+ self.current_thread))
+ return
+
+ def set_current_thread(self, args):
+ # XXX Switch to a different thread, although this doesn't
+ # actually do anything yet.
+ t_num = int(args)-1
+ if t_num > len(self.threads):
+ self.errmsg('Thread ID %d not known.' % t_num+1)
+ return
+ self.current_thread = self.threads[t_num]
+ self.msg('Switching to thread %d (%s)' % (t_num+1, \
+ self.current_thread))
+ return
+
+def init(msg, errmsg):
+ """ This method sets up thread debugging by creating a ThreadDebug
+ object that creates MTracer objects for every thread that is created.
+ 'msg' is a method to write standard output to, and 'errmsg' is a method
+ to write error output to.
+ """
+ t = ThreadDebug(msg, errmsg)
+ threading.settrace(t.trace_dispatch_init)
+ #sys.settrace(t.trace_dispatch_init)
+
+
+
+
+
+
More information about the Python-checkins
mailing list