Commits

jayven committed d2b3ab4

Add buttons on the panel

Comments (0)

Files changed (3)

 import pooler
 import linecache
 from itertools import izip, islice
+from osv import osv, fields
+
 from bgconsole import BGConsole
-from osv import osv, fields
+from hook_excpetion import register_exception_callback, \
+    unregister_exception_callback
+
 
 help_text = """
 Usage:
 
 class DebugConsole(osv.osv_memory):
 
+    @property
+    def tb_obj(self):
+        return self.pool.get('hotdebug.tb')
+
+    @property
+    def tb_locals_obj(self):
+        return self.pool.get('hotdebug.tb.locals')
+
+    @property
+    def bgconsole_obj(self):
+        return self.pool.get('hotdebug.console.bgconsole')
+
     def _get_console(self, cr, uid, id, context):
-        bgconsole_obj = self.pool.get('hotdebug.console.bgconsole')
         bgconsole_id = self.browse(cr, uid, id, context=context).bgconsole.id
-        return bgconsole_obj._get_console(cr, uid, bgconsole_id, context)
+        return self.bgconsole_obj._get_console(cr, uid, bgconsole_id, context)
     
     def _clear_exc(self, cr, uid, id, context):
         rec = self.browse(cr, uid, id, context=context)
-        tb_ids = [tb.id for tb in rec.last_traceback]
+        self.tb_locals_obj.unlink(cr, uid, [l.id 
+            for tb in rec.last_traceback for l in tb.locals], context=context)
+        self.tb_obj.unlink(cr, uid, [tb.id for tb in rec.last_traceback],
+                context=context)
         self.write(cr, uid, [rec.id,], {'last_type': '', 'last_value': ''},
                 context=context)
-        # XXX does hotdebug.tb.locals are unlinked as well?
-        self.pool.get('hotdebug.tb').unlink(cr, uid, tb_ids, context=context)
     
-    def _set_exc(self, cr, uid, id, context):
-        console = self._get_console(cr, uid, id, context)
-        if not console.got_exception:
-            return
-
+    def _set_exc(self, cr, uid, id, last_type, last_value, last_traceback,
+            context):
         # first clear the previous exc
         self._clear_exc(cr, uid, id, context)
 
-        # should be set by InteractiveInterpreter.showtraceback at code.py
-        last_type = getattr(sys, 'last_type', None)
-        last_value = getattr(sys, 'last_value', None)
-        last_traceback = getattr(sys, 'last_traceback', None)
-        assert last_type and last_value and last_traceback
+        # write last_type and last_value
         self.write(cr, uid, [id,], {'last_type': str(last_type),
             'last_value': str(last_value)}, context=context)
 
         # now add tracebacks
-        tb_obj = self.pool.get('hotdebug.tb')
-        tb_locals_obj = self.pool.get('hotdebug.tb.locals')
         lines_around = context.get('lines_around', 5)
         tb = last_traceback.tb_next # skip the first one
         while tb is not None:
             line, lines = get_file_part(filename, lineno,
                     lines_around,
                     f.f_globals)
-            tb_id = tb_obj.create(cr, uid, {'console': id,
+            tb_id = self.tb_obj.create(cr, uid, {'console': id,
                 'filename': filename,
                 'where': where,
                 'lineno': lineno,
                 'lines': lines,}, context=context)
 
             for n, v in ns2list(f.f_locals):
-                tb_locals_obj.create(cr, uid, {'tb': tb_id,
+                self.tb_locals_obj.create(cr, uid, {'tb': tb_id,
                     'name': n,
                     'value': v,}, context=context)
             
 
     def create(self, cr, uid, vals, context=None):
         # create the associated bgconsole and create the record
-        bgconsole_obj = self.pool.get('hotdebug.console.bgconsole')
-        bgconsole_id = bgconsole_obj.create(cr, uid, {}, context=context)
-        output = bgconsole_obj._get_console(cr, uid, bgconsole_id,
+        bgconsole_id = self.bgconsole_obj.create(cr, uid, {}, context=context)
+        output = self.bgconsole_obj._get_console(cr, uid, bgconsole_id,
                 context).output
         ret = super(DebugConsole, self).create(cr, uid, {
             'bgconsole': bgconsole_id,
 
         ids = norm_select(ids)
         for id in ids:
+            rec = self.browse(cr, uid, id, context=context)
             console = self._get_console(cr, uid, id, context)
             console.push_cmd(field_val)
             if console.dead:
                         "The console has exited, try restart")
 
             self.write(cr, uid, [id], {'output': console.output})
-            self._set_exc(cr, uid, id, context)
+            if console.got_exception and rec.catch_console_exception:
+                # should be set by InteractiveInterpreter.showtraceback at 
+                # code.py
+                last_type = getattr(sys, 'last_type', None)
+                last_value = getattr(sys, 'last_value', None)
+                last_traceback = getattr(sys, 'last_traceback', None)
+                assert last_type and last_value and last_traceback
+                self._set_exc(cr, uid, id, last_type, last_value,
+                        last_traceback, context)
 
         return True
 
         if context is None:
             context = {}
 
-        bgconsole_obj = self.pool.get('hotdebug.console.bgconsole')
         ids = norm_select(ids)
         for rec in self.browse(cr, uid, ids, context=context):
             # clear exception
             self._clear_exc(cr, uid, rec.id, context)
             # create new console and set
             old_id = rec.bgconsole.id
-            new_id = bgconsole_obj.create(cr, uid, {}, context=context)
-            output = bgconsole_obj._get_console(cr, uid, new_id, context).output
+            new_id = self.bgconsole_obj.create(cr, uid, {}, context=context)
+            output = self.bgconsole_obj._get_console(cr, uid, new_id,
+                    context).output
             self.write(cr, uid, [rec.id], {'bgconsole': new_id, 'output': output},
                     context=context)
             # unlink the old one
-            bgconsole_obj.unlink(cr, uid, [old_id], context=context)
+            self.bgconsole_obj.unlink(cr, uid, [old_id], context=context)
         return True
 
+    def set_catch_console_exception(self, cr, uid, ids, context=None):
+        if context is None:
+            context = {}
+        return self.write(cr, uid, ids, {
+            'catch_console_exception': context.get('catch_console_exception',
+                False),
+        }, context=context)
+
+    def set_catch_server_exception(self, cr, uid, ids, context=None):
+        if context is None:
+            context = {}
+        catch_server_exception = context.get('catch_server_exception', False)
+        id = ids[0]
+        dbname = cr.dbname
+        if catch_server_exception:
+            def cb(last_type, last_value, last_traceback):
+                # need to open a new cursor here
+                try:
+                    cr = pooler.get_db_only(dbname).cursor()
+                    self._set_exc(cr, uid, id, last_type, last_value,
+                            last_traceback, context)
+                finally:
+                    cr.close()
+            register_exception_callback(id, cb)
+        else:
+            unregister_exception_callback(id)
+        return self.write(cr, uid, ids, {
+            'catch_console_exception': catch_console_exception,
+        }, context=context)
+        
     _name = 'hotdebug.console'
     _columns = {
         'bgconsole': fields.many2one('hotdebug.console.bgconsole',
         'last_traceback': fields.one2many('hotdebug.tb',
             'console',
             'Last exception traceback'),
+        'catch_console_exception': fields.boolean('Catch console exception?',
+            readonly=True),
+        'catch_server_exception': fields.boolean('Catch server exception?',
+            readonly=True),
         'help': fields.text('Help', readonly=True),
     }
     _defaults = {
         'output': BGConsole.banner(),
         'last_type': '',
         'last_value': '',
+        'catch_console_exception': True,
+        'catch_server_exception': False,
         'help': help_text,
     }
 
                             <button colspan="2" name="restart_console" string="Restart console" type="object" icon="gtk-go-forward" />
                         </page>
                         <page string="Last exception">
+                            <field name="catch_console_exception" invisible="1" />
+                            <field name="catch_server_exception" invisible="1" />
+                            <button colspan="2" name="set_catch_console_exception" string="Catch console exception"
+                                attrs="{'readonly':[('catch_console_exception','=',True)]}"
+                                context="{'catch_console_exception':True}"
+                                type="object" icon="gtk-go-forward" />
+                            <button colspan="2" name="set_catch_console_exception" string="Don't catch console exception"
+                                attrs="{'readonly':[('catch_console_exception','=',False)]}"
+                                context="{'catch_console_exception':False}"
+                                type="object" icon="gtk-go-forward" />
+                            <button colspan="2" name="set_catch_server_exception" string="Catch server exception"
+                                attrs="{'readonly':[('catch_server_exception','=',True)]}"
+                                context="{'catch_server_exception':True}"
+                                type="object" icon="gtk-go-forward" />
+                            <button colspan="2" name="set_catch_server_exception" string="Don't catch server exception"
+                                attrs="{'readonly':[('catch_server_exception','=',False)]}"
+                                context="{'catch_server_exception':False}"
+                                type="object" icon="gtk-go-forward" />
                             <separator colspan="4" string="Last exception type" />
                             <field name="last_type" nolabel="1" colspan="4" />
                             <separator colspan="4" string="Last exception value" />

hook_excpetion.py

 _exception_callback_tls = threading.local()
 
 
-def register_exception_callback(cb):
+def register_exception_callback(id, cb):
     '''
     Register a thread-local callback that will be called when THIS thread
     has uncaught exception
     '''
-    _exception_callback_tls.cb = cb
+    if getattr(_exception_callback_tls, 'callbacks', None):
+        _exception_callback_tls.callbacks = {}
+    _exception_callback_tls.callbacks[id] = cb
 
 
-def unregister_exception_callback():
+def unregister_exception_callback(id):
     '''
     Reverse op of register_exception_callback
     '''
-    if getattr(_exception_callback_tls, 'cb', None):
-        del _exception_callback_tls.cb
+    if getattr(_exception_callback_tls, 'callbacks', None):
+        _exception_callback_tls.callbacks.pop(id, None)
 
 
 def _hook_excpetion():
             try:
                 return old(self, method, auth, params)
             except:
-                cb = getattr(_exception_callback_tls, 'cb', None)
+                cbs = getattr(_exception_callback_tls, 'callbacks', None)
                 # only process the same thread's exception
-                if cb is not None:
-                    cb(*sys.exc_info())
+                if cbs:
+                    last_type, last_value, last_traceback = sys.exc_info()
+                    for cb in cbs.itervalues():
+                        cb(last_type, last_value, last_traceback)
                 raise
         dispatch._hooked = True
         return dispatch