Adding extra frames to traceback in C module

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Roger Binns

    #1

    Adding extra frames to traceback in C module

    One thing I would like to do in my extension module is
    add extra frames to the traceback when an extension
    occurs. At the moment C code is invisible to tracebacks.
    This is relevant when the C code makes a Python callback.
    For example if the following code sequence happens
    (time going down)

    Python C

    A
    B
    C
    D
    E
    F
    G
    H

    If there is an exception in H then the traceback seen
    from A will be "B C G H". I want to get D, E and F
    into there as well. This is because "G H" could be
    called for several different reasons in the C code
    and adding the extra information will establish why.

    I couldn't find anything on the web or in the documentation
    to explain how to do it. I did find snippets of code
    doing things like PyTraceback_Her e but they use a real
    Python frame which I don't have and don't know how to
    synthesize.

    Roger


  • John Machin

    #2
    Re: Adding extra frames to traceback in C module

    On 10/06/2006 1:24 PM, Roger Binns wrote:[color=blue]
    > One thing I would like to do in my extension module is
    > add extra frames to the traceback when an extension
    > occurs. At the moment C code is invisible to tracebacks.
    > This is relevant when the C code makes a Python callback.[/color]

    [snip]
    [color=blue]
    > I couldn't find anything on the web or in the documentation
    > to explain how to do it. I did find snippets of code
    > doing things like PyTraceback_Her e but they use a real
    > Python frame which I don't have and don't know how to
    > synthesize.[/color]

    In the C code generated by Pyrex, the frame is faked up on the fly if an
    error occurs:

    C:\junk>demotrb ackmain.py
    Traceback (most recent call last):
    File "C:\junk\demotr backmain.py", line 12, in ?
    funcb()
    File "C:\junk\demotr backmain.py", line 3, in funcb
    demotrback.func c(funce)
    File "demotrback.pyx ", line 2, in demotrback.func c
    funcd1(cbfunc)
    File "demotrback.pyx ", line 5, in demotrback.func d1
    funcd2(callb)
    File "demotrback.pyx ", line 8, in demotrback.func d2
    callb()
    File "C:\junk\demotr backmain.py", line 6, in funce
    funcf()
    File "C:\junk\demotr backmain.py", line 9, in funcf
    x = 1 / 0
    ZeroDivisionErr or: integer division or modulo by zero

    Check out

    then whip up some quick examples and look at the generated code.

    HTH,
    John

    Comment

    • greg

      #3
      Re: Adding extra frames to traceback in C module

      Roger Binns wrote:[color=blue]
      > One thing I would like to do in my extension module is
      > add extra frames to the traceback when an extension
      > occurs.
      >
      > I did find snippets of code
      > doing things like PyTraceback_Her e but they use a real
      > Python frame which I don't have and don't know how to
      > synthesize.[/color]

      This is the code Pyrex uses to add frames to the traceback.
      It creates a fake frame object and fills in just enough
      of it to keep the traceback printing code happy.

      Or you could just use Pyrex for your extension module
      in the first place, and get it done for you automatically.

      -----------------------------------------------------------
      #include "compile.h"
      #include "frameobjec t.h"
      #include "traceback. h"

      static void __Pyx_AddTraceb ack(char *funcname) {
      PyObject *py_srcfile = 0;
      PyObject *py_funcname = 0;
      PyObject *py_globals = 0;
      PyObject *empty_tuple = 0;
      PyObject *empty_string = 0;
      PyCodeObject *py_code = 0;
      PyFrameObject *py_frame = 0;

      py_srcfile = PyString_FromSt ring(%(FILENAME )s);
      if (!py_srcfile) goto bad;
      py_funcname = PyString_FromSt ring(funcname);
      if (!py_funcname) goto bad;
      py_globals = PyModule_GetDic t(%(GLOBALS)s);
      if (!py_globals) goto bad;
      empty_tuple = PyTuple_New(0);
      if (!empty_tuple) goto bad;
      empty_string = PyString_FromSt ring("");
      if (!empty_string) goto bad;
      py_code = PyCode_New(
      0, /*int argcount,*/
      0, /*int nlocals,*/
      0, /*int stacksize,*/
      0, /*int flags,*/
      empty_string, /*PyObject *code,*/
      empty_tuple, /*PyObject *consts,*/
      empty_tuple, /*PyObject *names,*/
      empty_tuple, /*PyObject *varnames,*/
      empty_tuple, /*PyObject *freevars,*/
      empty_tuple, /*PyObject *cellvars,*/
      py_srcfile, /*PyObject *filename,*/
      py_funcname, /*PyObject *name,*/
      %(LINENO)s, /*int firstlineno,*/
      empty_string /*PyObject *lnotab*/
      );
      if (!py_code) goto bad;
      py_frame = PyFrame_New(
      PyThreadState_G et(), /*PyThreadState *tstate,*/
      py_code, /*PyCodeObject *code,*/
      py_globals, /*PyObject *globals,*/
      0 /*PyObject *locals*/
      );
      if (!py_frame) goto bad;
      py_frame->f_lineno = %(LINENO)s;
      PyTraceBack_Her e(py_frame);
      bad:
      Py_XDECREF(py_s rcfile);
      Py_XDECREF(py_f uncname);
      Py_XDECREF(empt y_tuple);
      Py_XDECREF(empt y_string);
      Py_XDECREF(py_c ode);
      Py_XDECREF(py_f rame);
      }

      --
      Greg

      Comment

      Working...