Package gluon :: Module debug
[hide private]
[frames] | no frames]

Source Code for Module gluon.debug

  1  #!/usr/bin/env python 
  2  # -*- coding: utf-8 -*- 
  3   
  4  """ 
  5  This file is part of the web2py Web Framework 
  6  Developed by Massimo Di Pierro <mdipierro@cs.depaul.edu>, 
  7  limodou <limodou@gmail.com> and srackham <srackham@gmail.com>. 
  8  License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html) 
  9   
 10  """ 
 11   
 12  import logging 
 13  import pdb 
 14  import Queue 
 15  import sys 
 16   
 17  logger = logging.getLogger("web2py") 
18 19 20 -class Pipe(Queue.Queue):
21 - def __init__(self, name, mode='r', *args, **kwargs):
22 self.__name = name 23 Queue.Queue.__init__(self, *args, **kwargs)
24
25 - def write(self, data):
26 logger.debug("debug %s writting %s" % (self.__name, data)) 27 self.put(data)
28
29 - def flush(self):
30 # mark checkpoint (complete message) 31 logger.debug("debug %s flushing..." % self.__name) 32 self.put(None) 33 # wait until it is processed 34 self.join() 35 logger.debug("debug %s flush done" % self.__name)
36
37 - def read(self, count=None, timeout=None):
38 logger.debug("debug %s reading..." % (self.__name, )) 39 data = self.get(block=True, timeout=timeout) 40 # signal that we are ready 41 self.task_done() 42 logger.debug("debug %s read %s" % (self.__name, data)) 43 return data
44
45 - def readline(self):
46 logger.debug("debug %s readline..." % (self.__name, )) 47 return self.read()
48 49 50 pipe_in = Pipe('in') 51 pipe_out = Pipe('out') 52 53 debugger = pdb.Pdb(completekey=None, stdin=pipe_in, stdout=pipe_out,)
54 55 56 -def set_trace():
57 "breakpoint shortcut (like pdb)" 58 logger.info("DEBUG: set_trace!") 59 debugger.set_trace(sys._getframe().f_back)
60
61 62 -def stop_trace():
63 "stop waiting for the debugger (called atexit)" 64 # this should prevent communicate is wait forever a command result 65 # and the main thread has finished 66 logger.info("DEBUG: stop_trace!") 67 pipe_out.write("debug finished!") 68 pipe_out.write(None)
69 #pipe_out.flush()
70 71 72 -def communicate(command=None):
73 "send command to debbuger, wait result" 74 if command is not None: 75 logger.info("DEBUG: sending command %s" % command) 76 pipe_in.write(command) 77 #pipe_in.flush() 78 result = [] 79 while True: 80 data = pipe_out.read() 81 if data is None: 82 break 83 result.append(data) 84 logger.info("DEBUG: result %s" % repr(result)) 85 return ''.join(result)
86 87 88 # New debugger implementation using qdb and a web UI 89 90 import gluon.contrib.qdb as qdb 91 from threading import RLock 92 93 interact_lock = RLock() 94 run_lock = RLock()
95 96 97 -def check_interaction(fn):
98 "Decorator to clean and prevent interaction when not available" 99 def check_fn(self, *args, **kwargs): 100 interact_lock.acquire() 101 try: 102 if self.filename: 103 self.clear_interaction() 104 return fn(self, *args, **kwargs) 105 finally: 106 interact_lock.release()
107 return check_fn 108
109 110 -class WebDebugger(qdb.Frontend):
111 "Qdb web2py interface" 112
113 - def __init__(self, pipe, completekey='tab', stdin=None, stdout=None):
114 qdb.Frontend.__init__(self, pipe) 115 self.clear_interaction()
116
117 - def clear_interaction(self):
118 self.filename = None 119 self.lineno = None 120 self.exception_info = None 121 self.context = None
122 123 # redefine Frontend methods: 124
125 - def run(self):
126 run_lock.acquire() 127 try: 128 while self.pipe.poll(): 129 qdb.Frontend.run(self) 130 finally: 131 run_lock.release()
132
133 - def interaction(self, filename, lineno, line, **context):
134 # store current status 135 interact_lock.acquire() 136 try: 137 self.filename = filename 138 self.lineno = lineno 139 self.context = context 140 finally: 141 interact_lock.release()
142
143 - def exception(self, title, extype, exvalue, trace, request):
144 self.exception_info = {'title': title, 145 'extype': extype, 'exvalue': exvalue, 146 'trace': trace, 'request': request}
147 148 @check_interaction
149 - def do_continue(self):
150 qdb.Frontend.do_continue(self)
151 152 @check_interaction
153 - def do_step(self):
154 qdb.Frontend.do_step(self)
155 156 @check_interaction
157 - def do_return(self):
158 qdb.Frontend.do_return(self)
159 160 @check_interaction
161 - def do_next(self):
162 qdb.Frontend.do_next(self)
163 164 @check_interaction
165 - def do_quit(self):
166 qdb.Frontend.do_quit(self)
167
168 - def do_exec(self, statement):
169 interact_lock.acquire() 170 try: 171 # check to see if we're inside interaction 172 if self.filename: 173 # avoid spurious interaction notifications: 174 self.set_burst(2) 175 # execute the statement in the remote debugger: 176 return qdb.Frontend.do_exec(self, statement) 177 finally: 178 interact_lock.release()
179 180 # create the connection between threads: 181 182 parent_queue, child_queue = Queue.Queue(), Queue.Queue() 183 front_conn = qdb.QueuePipe("parent", parent_queue, child_queue) 184 child_conn = qdb.QueuePipe("child", child_queue, parent_queue) 185 186 web_debugger = WebDebugger(front_conn) # frontend 187 qdb_debugger = qdb.Qdb( 188 pipe=child_conn, redirect_stdio=False, skip=None) # backend 189 dbg = qdb_debugger 190 191 # enable getting context (stack, globals/locals) at interaction 192 qdb_debugger.set_params(dict(call_stack=True, environment=True)) 193 194 import gluon.main 195 gluon.main.global_settings.debugging = True 196