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

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