New issue 3120: PyErr_Restore does not restore traceback
https://bitbucket.org/pypy/pypy/issues/3120/pyerr_restore-does-not-restore-traceback

Kirill Smelkov:

Hello up there. I again hit PyPy vs CPython incomatibility while moving parts 
of Pygolang to Cython. Please consider the following minimal example:

\(mymod.pyx\)

```python
# cython: language_level=2
cdef extern from "Python.h":
    ctypedef struct PyObject
    PyObject *PyObject_CallFunction(PyObject *f, const char *fmt, ...)
    void PyErr_Fetch(PyObject **pexc_type, PyObject **pexc_value, PyObject 
**pexc_tb)
    void PyErr_Restore(PyObject *exc_type, PyObject *exc_value, PyObject 
*exc_tb)
    void Py_XINCREF(PyObject*)


# PyExc wraps information about Python exception
cdef class PyExc:
    # retrieved by PyErr_Fetch - keep 1 reference to each
    cdef PyObject *exc_type
    cdef PyObject *exc_value
    cdef PyObject *exc_tb

# call_pyfunc calls f and return PyExc describing exception state after f call.
# f must raise an exception.
def call_pyfunc(f):
    cdef PyExc pyexc = PyExc()

    cdef PyObject *ret
    ret = PyObject_CallFunction(<PyObject*>f, NULL)
    if ret != NULL:
        raise AssertionError('f must raise an exception')

    PyErr_Fetch(&pyexc.exc_type, &pyexc.exc_value, &pyexc.exc_tb)
    return pyexc


# reraise_pyexc reraises pyexc including its original traceback.
def reraise_pyexc(PyExc pyexc not None):
    _pyexc_reraise(pyexc)

cdef void _pyexc_reraise(PyExc pyexc) except *:
    # PyErr_Restore takes 1 reference to restored objects.
    # We want to keep pyerr itself alive and valid.
    Py_XINCREF(pyexc.exc_type);
    Py_XINCREF(pyexc.exc_value);
    Py_XINCREF(pyexc.exc_tb);

    PyErr_Restore(pyexc.exc_type, pyexc.exc_value, pyexc.exc_tb)
```

\(mytest.py\)

```python
#!/usr/bin/env python
  
import mymod

def f():    g()
def g():    h()
def h():    1/0

def main():
    e = mymod.call_pyfunc(f)
    #print(e)
    i(e)

def i(e):   j(e)
def j(e):   k(e)
def k(e):   mymod.reraise_pyexc(e)

if __name__ == '__main__':
    main()
```

When running with CPython `mytest.py` prints traceback that includes _both_ 
i-j-k _and_ f-g-h:

```
(neo) (z-dev) (g.env) kirr@deco:~/src/tools/go/pygolang/x$ python mytest.py 
Traceback (most recent call last):
  File "mytest.py", line 19, in <module>
    main()
  File "mytest.py", line 12, in main
    i(e)
  File "mytest.py", line 14, in i
    def i(e):   j(e)
  File "mytest.py", line 15, in j
    def j(e):   k(e)
  File "mytest.py", line 16, in k
    def k(e):   mymod.reraise_pyexc(e)
  File "mymod.pyx", line 33, in mymod.reraise_pyexc
    _pyexc_reraise(pyexc)
  File "mytest.py", line 5, in f
    def f():    g()
  File "mytest.py", line 6, in g
    def g():    h()
  File "mytest.py", line 7, in h
    def h():    1/0
ZeroDivisionError: integer division or modulo by zero
```

However when run under PyPy \(I verified up till today’s nightly\) the 
traceback _does_ _not_ include f-g-h:

```
(pypy.venv) test1@deco:~/pypy/pygolang/x$ pypy mytest.py 
Traceback (most recent call last):
  File "mytest.py", line 19, in <module>
    main()
  File "mytest.py", line 12, in main
    i(e)
  File "mytest.py", line 14, in i
    def i(e):   j(e)
  File "mytest.py", line 15, in j
    def j(e):   k(e)
  File "mytest.py", line 16, in k
    def k(e):   mymod.reraise_pyexc(e)
  File "mymod.pyx", line 33, in mymod.reraise_pyexc
    _pyexc_reraise(pyexc)
ZeroDivisionError: integer division by zero
```

This minimal example models what happens in C/Pyx version of `sync.WorkGroup` 
in Pygolang and preserving the inner traceback is important there.

```
$ python
Python 2.7.15+ (default, Feb  3 2019, 13:13:16) 
[GCC 8.2.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
```

‌

```
(pypy.venv) test1@deco:~/pypy/pygolang/x$ pypy
Python 2.7.13 (dcc4efe7355e, Nov 19 2019, 23:00:15)
[PyPy 7.3.0-alpha0 with GCC 5.3.1 20160413] on linux2
Type "help", "copyright", "credits" or "license" for more information.
And now for something completely different: ``pypy is like sausages''
```

Thanks beforehand,  
Kirill

/cc @{557058:7cb88866-fb18-487e-a2dc-b19de69f5f0b}


_______________________________________________
pypy-issue mailing list
pypy-issue@python.org
https://mail.python.org/mailman/listinfo/pypy-issue

Reply via email to