[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