Skip to content

Commit f94f26a

Browse files
authored
Make __Pyx_CoroutineAwaitType non-pickleable (cythonGH-4381)
This is explicitly tested for: https://github.com/cython/cython/blob/aea4e6b84b38223c540266f8c57093ee2039f284/tests/run/test_coroutines_pep492.pyx#L2400 It turns out some earlier versions of Python assume that C-API classes without a dict or slot are pickleable by the class name. Currently it isn't pickleable because the class name lookup is failing but this change makes it more robust. See cython#4376
1 parent 7403055 commit f94f26a

File tree

1 file changed

+21
-0
lines changed

1 file changed

+21
-0
lines changed

Cython/Utility/Coroutine.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1501,13 +1501,34 @@ static PyObject *__Pyx_CoroutineAwait_no_new(PyTypeObject *type, PyObject *args,
15011501
}
15021502
#endif
15031503

1504+
// In earlier versions of Python an object with no __dict__ and not __slots__ is assumed
1505+
// to be pickleable by default. Coroutine-wrappers have significant state so shouldn't be.
1506+
// Therefore provide a default implementation.
1507+
// Something similar applies to heaptypes (i.e. with type_specs) with protocols 0 and 1
1508+
// even in more recent versions.
1509+
// We are applying this to all Python versions (hence the commented out version guard)
1510+
// to make the behaviour explicit.
1511+
// #if PY_VERSION_HEX < 0x03060000 || CYTHON_USE_TYPE_SPECS
1512+
static PyObject *__Pyx_CoroutineAwait_reduce_ex(__pyx_CoroutineAwaitObject *self, PyObject *arg) {
1513+
CYTHON_UNUSED_VAR(arg);
1514+
PyErr_Format(PyExc_TypeError, "cannot pickle '%.200s' object",
1515+
Py_TYPE(self)->tp_name);
1516+
return NULL;
1517+
}
1518+
// #endif
1519+
15041520
static PyMethodDef __pyx_CoroutineAwait_methods[] = {
15051521
{"send", (PyCFunction) __Pyx_CoroutineAwait_Send, METH_O,
15061522
(char*) PyDoc_STR("send(arg) -> send 'arg' into coroutine,\nreturn next yielded value or raise StopIteration.")},
15071523
{"throw", (PyCFunction) __Pyx_CoroutineAwait_Throw, METH_VARARGS,
15081524
(char*) PyDoc_STR("throw(typ[,val[,tb]]) -> raise exception in coroutine,\nreturn next yielded value or raise StopIteration.")},
15091525
{"close", (PyCFunction) __Pyx_CoroutineAwait_Close, METH_NOARGS,
15101526
(char*) PyDoc_STR("close() -> raise GeneratorExit inside coroutine.")},
1527+
// only needed with type-specs or version<3.6, but included in all versions for clarity
1528+
// #if PY_VERSION_HEX < 0x03060000 || CYTHON_USE_TYPE_SPECS
1529+
{"__reduce_ex__", (PyCFunction) __Pyx_CoroutineAwait_reduce_ex, METH_O, 0},
1530+
{"__reduce__", (PyCFunction) __Pyx_CoroutineAwait_reduce_ex, METH_NOARGS, 0},
1531+
// #endif
15111532
{0, 0, 0, 0}
15121533
};
15131534

0 commit comments

Comments
 (0)