Skip to content

Commit 77c07cb

Browse files
author
Anselm Kruis
committed
Issue python#107: reconstruct the frame.f_back linkage in unpickled tracebacks.
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)
1 parent 55f8cd9 commit 77c07cb

File tree

3 files changed

+57
-0
lines changed

3 files changed

+57
-0
lines changed

Stackless/changelog.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ What's New in Stackless 3.X.X?
99

1010
*Release date: 20XX-XX-XX*
1111

12+
- https://bitbucket.org/stackless-dev/stackless/issues/107
13+
Improve unpickling of traceback objects. Stackless now reconstructs the
14+
frame.f_back linkage in frames directly referenced by traceback objects.
15+
1216
- https://bitbucket.org/stackless-dev/stackless/issues/110
1317
Remove the already non functional remains of psyco support.
1418

Stackless/pickling/prickelpit.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1206,6 +1206,14 @@ tb_setstate(PyObject *self, PyObject *args)
12061206
tb->tb_lineno = lineno;
12071207
Py_TYPE(tb) = Py_TYPE(tb)->tp_base;
12081208

1209+
if (frame != NULL && next != NULL && next->tb_frame != NULL &&
1210+
(PyObject *)(next->tb_frame->f_back) == Py_None) {
1211+
/* Reconstruct the f_back chain as far as possible. */
1212+
next->tb_frame->f_back = frame;
1213+
Py_INCREF(frame);
1214+
Py_DECREF(Py_None);
1215+
}
1216+
12091217
Py_INCREF(self);
12101218
return self;
12111219
}

Stackless/unittests/test_pickle.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import pickle
55
import gc
66
import io
7+
import inspect
78

89
from stackless import schedule, tasklet, stackless
910

@@ -611,6 +612,50 @@ class TestDictViewPicklingPy(AbstractTestPickledTasklets, DictViewPicklingTestCa
611612
class TestDictViewPicklingC(AbstractTestPickledTasklets, DictViewPicklingTestCases, CPickleMixin):
612613
pass
613614

615+
616+
class Traceback_TestCases(object):
617+
def testTracebackFrameLinkage(self):
618+
def a():
619+
# raise an exception
620+
1 // 0
621+
622+
def b():
623+
return a()
624+
625+
def c():
626+
return b()
627+
628+
try:
629+
c()
630+
except ZeroDivisionError:
631+
tb = sys.exc_info()[2]
632+
633+
innerframes_orig = inspect.getinnerframes(tb)
634+
p = self.dumps(tb)
635+
tb2 = self.loads(p)
636+
# basics
637+
self.assertIs(type(tb), type(tb2))
638+
self.assertIsNot(tb, tb2)
639+
innerframes = inspect.getinnerframes(tb2)
640+
# compare the content
641+
self.assertListEqual([i[1:] for i in innerframes_orig], [i[1:] for i in innerframes])
642+
# check linkage
643+
all_outerframes_orig = inspect.getouterframes(innerframes_orig[-1][0])
644+
all_outerframes = inspect.getouterframes(innerframes[-1][0])
645+
l = len(innerframes_orig)
646+
self.assertGreater(len(all_outerframes_orig), l)
647+
self.assertGreaterEqual(len(all_outerframes), l)
648+
# compare the content
649+
self.assertListEqual([i[1:] for i in all_outerframes_orig[:l - 1]], [i[1:] for i in all_outerframes[:l - 1]])
650+
651+
652+
class TestTracebackPy(StacklessTestCase, Traceback_TestCases, PyPickleMixin):
653+
pass
654+
655+
656+
class TestTracebackC(StacklessTestCase, Traceback_TestCases, CPickleMixin):
657+
pass
658+
614659
if __name__ == '__main__':
615660
if not sys.argv[1:]:
616661
sys.argv.append('-v')

0 commit comments

Comments
 (0)