Disable watchpoint stepping by default (use cy step -w or cy step --watchpoint to...
[cython.git] / Cython / Debugger / libcython.py
index a6142ab59804a622580859895da2550bafbca551..4648d522a45448b143dc3ebe98fd0dd80e5168e0 100644 (file)
@@ -256,7 +256,7 @@ class CythonBase(object):
                 filename = None
                 lineno = 0
             else:
-                filename = symbol_and_line_obj.symtab.filename
+                filename = symbol_and_line_obj.symtab.fullname()
                 lineno = symbol_and_line_obj.line
                 if pygments:
                     lexer = pygments.lexers.CLexer(stripall=False)
@@ -578,21 +578,26 @@ class CyCy(CythonCommand):
         cy next
         cy run
         cy cont
+        cy finish
         cy up
         cy down
+        cy select
         cy bt / cy backtrace
-        cy print
         cy list
+        cy print
         cy locals
         cy globals
+        cy exec
     """
     
     name = 'cy'
     command_class = gdb.COMMAND_NONE
     completer_class = gdb.COMPLETE_COMMAND
     
-    def __init__(self, *args):
-        super(CythonCommand, self).__init__(*args, prefix=True)
+    def __init__(self, name, command_class, completer_class):
+        # keep the signature 2.5 compatible (i.e. do not use f(*a, k=v)
+        super(CythonCommand, self).__init__(name, command_class, 
+                                            completer_class, prefix=True)
         
         commands = dict(
             import_ = CyImport.register(),
@@ -830,10 +835,9 @@ class CyBreak(CythonCommand):
         return compl
 
 
-class CythonCodeStepper(CythonCommand, libpython.GenericCodeStepper):
+class CythonInfo(CythonBase, libpython.PythonInfo):
     """
-    Base class for CyStep and CyNext. It implements the interface dictated by
-    libpython.GenericCodeStepper.
+    Implementation of the interface dictated by libpython.LanguageInfo.
     """
     
     def lineno(self, frame):
@@ -843,20 +847,19 @@ class CythonCodeStepper(CythonCommand, libpython.GenericCodeStepper):
         # related code. The C level should be dispatched to the 'step' command.
         if self.is_cython_function(frame):
             return self.get_cython_lineno(frame)
-        else:
-            return libpython.py_step.lineno(frame)
+        return super(CythonInfo, self).lineno(frame)
     
     def get_source_line(self, frame):
         try:
-            line = super(CythonCodeStepper, self).get_source_line(frame)
+            line = super(CythonInfo, self).get_source_line(frame)
         except gdb.GdbError:
             return None
         else:
             return line.strip() or None
 
-    @classmethod
-    def register(cls):
-        return cls(cls.name, stepinto=getattr(cls, 'stepinto', False))
+    def exc_info(self, frame):
+        if self.is_python_function:
+            return super(CythonInfo, self).exc_info(frame)
 
     def runtime_break_functions(self):
         if self.is_cython_function():
@@ -867,8 +870,25 @@ class CythonCodeStepper(CythonCommand, libpython.GenericCodeStepper):
         result.extend(self.cy.functions_by_cname)
         return result
 
+
+class CythonExecutionControlCommand(CythonCommand, 
+                                    libpython.ExecutionControlCommandBase):
+    
+    @classmethod
+    def register(cls):
+        return cls(cls.name, cython_info)
+
+
+class CyStep(CythonExecutionControlCommand, libpython.PythonStepperMixin):
+    "Step through Cython, Python or C code."
+    
+    name = 'cy step'
+    stepinto = True
+    
     def invoke(self, args, from_tty):
-        if not self.is_cython_function() and not self.is_python_function():
+        if self.is_python_function():
+            self.python_step(args, self.stepinto)
+        elif not self.is_cython_function():
             if self.stepinto:
                 command = 'step'
             else:
@@ -876,24 +896,17 @@ class CythonCodeStepper(CythonCommand, libpython.GenericCodeStepper):
                 
             self.finish_executing(gdb.execute(command, to_string=True))
         else:
-            self.step()
+            self.step(stepinto=self.stepinto)
 
 
-class CyStep(CythonCodeStepper):
-    "Step through Cython, Python or C code."
-    
-    name = 'cy step'
-    stepinto = True
-
-
-class CyNext(CythonCodeStepper):
+class CyNext(CyStep):
     "Step-over Python code."
 
     name = 'cy next'
     stepinto = False
 
 
-class CyRun(CythonCodeStepper):
+class CyRun(CythonExecutionControlCommand):
     """
     Run a Cython program. This is like the 'run' command, except that it 
     displays Cython or Python source lines as well
@@ -901,26 +914,26 @@ class CyRun(CythonCodeStepper):
     
     name = 'cy run'
     
-    invoke = CythonCodeStepper.run
+    invoke = CythonExecutionControlCommand.run
 
 
-class CyCont(CyRun):
+class CyCont(CythonExecutionControlCommand):
     """
     Continue a Cython program. This is like the 'run' command, except that it 
     displays Cython or Python source lines as well.
     """
     
     name = 'cy cont'
-    invoke = CythonCodeStepper.cont
+    invoke = CythonExecutionControlCommand.cont
 
 
-class CyFinish(CyRun):
+class CyFinish(CythonExecutionControlCommand):
     """
     Execute until the function returns.
     """
     name = 'cy finish'
 
-    invoke = CythonCodeStepper.finish
+    invoke = CythonExecutionControlCommand.finish
 
 
 class CyUp(CythonCommand):
@@ -956,7 +969,7 @@ class CyDown(CyUp):
     _command = 'down'
 
 
-class CySelect(CythonCodeStepper):
+class CySelect(CythonCommand):
     """
     Select a frame. Use frame numbers as listed in `cy backtrace`.
     This command is useful because `cy backtrace` prints a reversed backtrace.
@@ -974,7 +987,7 @@ class CySelect(CythonCodeStepper):
         while frame.newer():
             frame = frame.newer()
         
-        stackdepth = self._stackdepth(frame)
+        stackdepth = libpython.stackdepth(frame)
         
         try:
             gdb.execute('select %d' % (stackdepth - stackno - 1,))
@@ -1028,7 +1041,7 @@ class CyList(CythonCommand):
     command_class = gdb.COMMAND_FILES
     completer_class = gdb.COMPLETE_NONE
     
-    @dispatch_on_frame(c_command='list')
+    @dispatch_on_frame(c_command='list')
     def invoke(self, _, from_tty):
         sd, lineno = self.get_source_desc()
         source = sd.get_source(lineno - 5, lineno + 5, mark_line=lineno, 
@@ -1134,6 +1147,10 @@ class CyGlobals(CyLocals):
 
 
 class CyExec(CythonCommand, libpython.PyExec):
+    """
+    Execute Python code in the nearest Python or Cython frame.
+    """
+    
     name = '-cy-exec'
     command_class = gdb.COMMAND_STACK
     completer_class = gdb.COMPLETE_NONE
@@ -1191,53 +1208,21 @@ class CyExec(CythonCommand, libpython.PyExec):
         expr, input_type = self.readcode(expr)
         executor = libpython.PythonCodeExecutor()
         
-        # get the dict of Cython globals and construct a dict in the inferior
-        # with Cython locals
-        global_dict = gdb.parse_and_eval(
-            '(PyObject *) PyModule_GetDict(__pyx_m)')
-        local_dict = gdb.parse_and_eval('(PyObject *) PyDict_New()')
-        
-        cython_function = self.get_cython_function()
-        
-        try:
-            self._fill_locals_dict(executor, libpython.pointervalue(local_dict))
-            executor.evalcode(expr, input_type, global_dict, local_dict)
-        finally:
+        with libpython.FetchAndRestoreError():
+            # get the dict of Cython globals and construct a dict in the 
+            # inferior with Cython locals
+            global_dict = gdb.parse_and_eval(
+                '(PyObject *) PyModule_GetDict(__pyx_m)')
+            local_dict = gdb.parse_and_eval('(PyObject *) PyDict_New()')
             
-            # try:
-                # tp, val, tb = sys.exc_info()
-                # sys.exc_clear()
-                # 
-                # try:
-                    # long(gdb.parse_and_eval("(void *) 0")) == 0
-                # except RuntimeError:
-                    # # At this point gdb is broken, just exit this shite, it
-                    # # ain't getting better.
-                    # 
-# # /home/mark/source/code/cython/Cython/Debugger/libcython.py:1206: 
-# # RuntimeWarning: tp_compare didn't return -1 or -2 for exception
-# # long(gdb.parse_and_eval("(void *) 0")) == 0
-# # Traceback (most recent call last):
-# # File "/home/mark/source/code/cython/Cython/Debugger/libcython.py", line 1206, 
-# # in invoke
-# # long(gdb.parse_and_eval("(void *) 0")) == 0
-# # RuntimeError: Cannot convert value to int.
-# # Error occurred in Python command: Cannot convert value to int.
-                    # if sys.exc_info()[0] is None and val is not None:
-                        # raise val, tb
-                # 
-                # for name, value in libpython.PyDictObjectPtr(local_dict).iteritems():
-                    # name = name.proxyval(set())
-                    # cyvar = cython_function.locals.get(name)
-                    # if cyvar is not None and cyvar.type == PythonObject:
-                        # gdb.parse_and_eval('set %s = (PyObject *) %d' % (cyvar.cname,
-                                                                         # pointervalue(value._gdbval)))
-            # finally:
-            executor.decref(libpython.pointervalue(local_dict))
-                
-                # if sys.exc_info()[0] is None and val is not None:
-                    # raise val, tb
-                    
+            cython_function = self.get_cython_function()
+            
+            try:
+                self._fill_locals_dict(executor, 
+                                       libpython.pointervalue(local_dict))
+                executor.evalcode(expr, input_type, global_dict, local_dict)
+            finally:
+                executor.decref(libpython.pointervalue(local_dict))
 
 
 # Functions
@@ -1308,5 +1293,6 @@ class CyLine(gdb.Function, CythonBase):
     def invoke(self):
         return self.get_cython_lineno()
 
-
-cy = CyCy.register()
\ No newline at end of file
+cython_info = CythonInfo()
+cy = CyCy.register()
+cython_info.cy = cy
\ No newline at end of file