Skip to content

Commit

Permalink
Issue python#107: reconstruct the frame.f_back linkage in unpickled t…
Browse files Browse the repository at this point in the history
…racebacks.

This is part 1 of issue python#107. If you unpickle a traceback object, Stackless now reconstructs the f_back links of the assorted frame objects.
There is also a new test case in test_pickle.py.
Manually grafted from pull request python#22.

https://bitbucket.org/stackless-dev/stackless/issues/107
(grafted from 3719f4e0d4371b941777f423941bfe5e875f9cf6)
  • Loading branch information
Anselm Kruis committed Dec 20, 2016
1 parent 55f8cd9 commit 77c07cb
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 0 deletions.
4 changes: 4 additions & 0 deletions Stackless/changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ What's New in Stackless 3.X.X?

*Release date: 20XX-XX-XX*

- https://bitbucket.org/stackless-dev/stackless/issues/107
Improve unpickling of traceback objects. Stackless now reconstructs the
frame.f_back linkage in frames directly referenced by traceback objects.

- https://bitbucket.org/stackless-dev/stackless/issues/110
Remove the already non functional remains of psyco support.

Expand Down
8 changes: 8 additions & 0 deletions Stackless/pickling/prickelpit.c
Original file line number Diff line number Diff line change
Expand Up @@ -1206,6 +1206,14 @@ tb_setstate(PyObject *self, PyObject *args)
tb->tb_lineno = lineno;
Py_TYPE(tb) = Py_TYPE(tb)->tp_base;

if (frame != NULL && next != NULL && next->tb_frame != NULL &&
(PyObject *)(next->tb_frame->f_back) == Py_None) {
/* Reconstruct the f_back chain as far as possible. */
next->tb_frame->f_back = frame;
Py_INCREF(frame);
Py_DECREF(Py_None);
}

Py_INCREF(self);
return self;
}
Expand Down
45 changes: 45 additions & 0 deletions Stackless/unittests/test_pickle.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import pickle
import gc
import io
import inspect

from stackless import schedule, tasklet, stackless

Expand Down Expand Up @@ -611,6 +612,50 @@ class TestDictViewPicklingPy(AbstractTestPickledTasklets, DictViewPicklingTestCa
class TestDictViewPicklingC(AbstractTestPickledTasklets, DictViewPicklingTestCases, CPickleMixin):
pass


class Traceback_TestCases(object):
def testTracebackFrameLinkage(self):
def a():
# raise an exception
1 // 0

def b():
return a()

def c():
return b()

try:
c()
except ZeroDivisionError:
tb = sys.exc_info()[2]

innerframes_orig = inspect.getinnerframes(tb)
p = self.dumps(tb)
tb2 = self.loads(p)
# basics
self.assertIs(type(tb), type(tb2))
self.assertIsNot(tb, tb2)
innerframes = inspect.getinnerframes(tb2)
# compare the content
self.assertListEqual([i[1:] for i in innerframes_orig], [i[1:] for i in innerframes])
# check linkage
all_outerframes_orig = inspect.getouterframes(innerframes_orig[-1][0])
all_outerframes = inspect.getouterframes(innerframes[-1][0])
l = len(innerframes_orig)
self.assertGreater(len(all_outerframes_orig), l)
self.assertGreaterEqual(len(all_outerframes), l)
# compare the content
self.assertListEqual([i[1:] for i in all_outerframes_orig[:l - 1]], [i[1:] for i in all_outerframes[:l - 1]])


class TestTracebackPy(StacklessTestCase, Traceback_TestCases, PyPickleMixin):
pass


class TestTracebackC(StacklessTestCase, Traceback_TestCases, CPickleMixin):
pass

if __name__ == '__main__':
if not sys.argv[1:]:
sys.argv.append('-v')
Expand Down

0 comments on commit 77c07cb

Please sign in to comment.