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