| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 3a45703 commit 9fbbf8b
3 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -9,6 +9,9 @@ What's New in Stackless 3.X.X? | |||
| 9 | 9 | ||
| 10 | 10 | *Release date: 20XX-XX-XX* | |
| 11 | 11 | ||
| 12 | + - https://bitbucket.org/stackless-dev/stackless/issues/130 | ||
| 13 | + Pickling exhausted generators no longer crashes. | ||
| 14 | + | ||
| 12 | 15 | - https://bitbucket.org/stackless-dev/stackless/issues/129 | |
| 13 | 16 | C-API: Calling PyTasklet_New( NULL, ...) no longer crashes. | |
| 14 | 17 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1707,9 +1707,15 @@ static PyObject * | |||
| 1707 | 1707 | gen_reduce(PyGenObject *gen) | |
| 1708 | 1708 | { | |
| 1709 | 1709 | PyObject *tup; | |
| 1710 | + PyObject *gi_frame = (PyObject *)gen->gi_frame; | ||
| 1711 | + if (gi_frame == NULL) { | ||
| 1712 | + /* Pickle NULL as None. See gen_setstate() for the corresponding | ||
| 1713 | + * unpickling code. */ | ||
| 1714 | + gi_frame = Py_None; | ||
| 1715 | + } | ||
| 1710 | 1716 | tup = Py_BuildValue("(O()(Oi))", | |
| 1711 | 1717 | &wrap_PyGen_Type, | |
| 1712 | - gen->gi_frame, | ||
| 1718 | + gi_frame, | ||
| 1713 | 1719 | gen->gi_running | |
| 1714 | 1720 | ); | |
| 1715 | 1721 | return tup; | |
@@ -1736,12 +1742,39 @@ gen_setstate(PyObject *self, PyObject *args) | |||
| 1736 | 1742 | { | |
| 1737 | 1743 | PyGenObject *gen = (PyGenObject *) self; | |
| 1738 | 1744 | PyFrameObject *f; | |
| 1745 | + PyObject *obj; | ||
| 1739 | 1746 | int gi_running; | |
| 1740 | 1747 | ||
| 1741 | 1748 | if (is_wrong_type(Py_TYPE(self))) return NULL; | |
| 1742 | - if (!PyArg_ParseTuple(args, "O!i:generator", | ||
| 1743 | - &PyFrame_Type, &f, &gi_running)) | ||
| 1749 | + if (!PyArg_ParseTuple(args, "Oi:generator", | ||
| 1750 | + &obj, &gi_running)) | ||
| 1751 | + return NULL; | ||
| 1752 | + | ||
| 1753 | + if (obj == Py_None) { | ||
| 1754 | + /* No frame, generator is exhausted */ | ||
| 1755 | + Py_CLEAR(gen->gi_frame); | ||
| 1756 | + | ||
| 1757 | + /* Even if gi_frame is NULL, gi_code is still valid. Therefore | ||
| 1758 | + * I set it to the code of the exhausted frame singleton. | ||
| 1759 | + */ | ||
| 1760 | + assert(gen_exhausted_frame != NULL); | ||
| 1761 | + assert(PyFrame_Check(gen_exhausted_frame)); | ||
| 1762 | + obj = (PyObject *)gen_exhausted_frame->f_code; | ||
| 1763 | + Py_INCREF(obj); | ||
| 1764 | + Py_SETREF(gen->gi_code, obj); | ||
| 1765 | + | ||
| 1766 | + gen->gi_running = gi_running; | ||
| 1767 | + Py_TYPE(gen) = Py_TYPE(gen)->tp_base; | ||
| 1768 | + Py_INCREF(gen); | ||
| 1769 | + return (PyObject *)gen; | ||
| 1770 | + } | ||
| 1771 | + if (!PyFrame_Check(obj)) { | ||
| 1772 | + PyErr_SetString(PyExc_TypeError, | ||
| 1773 | + "invalid frame object for gen_setstate"); | ||
| 1744 | 1774 | return NULL; | |
| 1775 | + } | ||
| 1776 | + f = (PyFrameObject *)obj; | ||
| 1777 | + obj = NULL; | ||
| 1745 | 1778 | ||
| 1746 | 1779 | if (!gi_running) { | |
| 1747 | 1780 | if ((f = slp_ensure_new_frame(f)) != NULL) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3,6 +3,7 @@ | |||
| 3 | 3 | import gc | |
| 4 | 4 | import stackless | |
| 5 | 5 | import types | |
| 6 | + import pickle | ||
| 6 | 7 | ||
| 7 | 8 | from support import test_main # @UnusedImport | |
| 8 | 9 | from support import StacklessTestCase | |
@@ -51,5 +52,28 @@ def test_wrap_generator_frame_code(self): | |||
| 51 | 52 | self.assertIsNot(g0.gi_frame, g1.gi_frame) | |
| 52 | 53 | self.assertEqual(g0.__name__, "exhausted_generator") | |
| 53 | 54 | ||
| 55 | + | ||
| 56 | + class TestGeneratorPickling(StacklessTestCase): | ||
| 57 | + def test_name(self): | ||
| 58 | + def g(): | ||
| 59 | + yield 1 | ||
| 60 | + gen_orig = g() | ||
| 61 | + p = pickle.dumps(gen_orig) | ||
| 62 | + gen_new = pickle.loads(p) | ||
| 63 | + | ||
| 64 | + self.assertEqual(gen_new.__name__, gen_orig.__name__) | ||
| 65 | + | ||
| 66 | + def test_exhausted(self): | ||
| 67 | + def g(): | ||
| 68 | + yield 1 | ||
| 69 | + gen_orig = g() | ||
| 70 | + self.assertEqual(gen_orig.__next__(), 1) | ||
| 71 | + self.assertRaises(StopIteration, gen_orig.__next__) | ||
| 72 | + p = pickle.dumps(gen_orig) | ||
| 73 | + self.assertRaises(StopIteration, gen_orig.__next__) | ||
| 74 | + gen_new = pickle.loads(p) | ||
| 75 | + self.assertRaises(StopIteration, gen_new.__next__) | ||
| 76 | + | ||
| 77 | + | ||
| 54 | 78 | if __name__ == '__main__': | |
| 55 | 79 | unittest.main() | |
| Back | FazBrowse Home | New Git URL |
0 commit comments