Skip to content
This repository was archived by the owner on Feb 13, 2025. It is now read-only.

Commit 52ee18f

Browse files
author
Anselm Kruis
committed
Stackless issue #139: pickle PyAsyncGenASend or PyAsyncGenAThrow
Stackless now pickles awaitable objects of type PyAsyncGenASend or PyAsyncGenAThrow (see PEP 525).
1 parent 80b3f97 commit 52ee18f

File tree

6 files changed

+343
-18
lines changed

6 files changed

+343
-18
lines changed

Doc/library/stackless/pickling.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,14 +116,15 @@ In order to be able to pickle tasklets |SLP| needs to be able to pickle
116116
several other objects, which can't be pickled by |CPY|. |SLP|
117117
uses :func:`copyreg.pickle` to register “reduction” functions for the following
118118
types:
119-
:data:`~types.FunctionType`,
120119
:data:`~types.AsyncGeneratorType`,
121120
:data:`~types.CodeType`,
122121
:data:`~types.CoroutineType`,
122+
:data:`~types.FunctionType`,
123123
:data:`~types.GeneratorType`,
124124
:data:`~types.ModuleType`,
125125
:data:`~types.TracebackType`,
126-
:ref:`Cell Objects <cell-objects>` and
126+
:ref:`Cell Objects <cell-objects>`,
127+
C-types PyAsyncGenASend and PyAsyncGenAThrow (see :pep:`525`) as well as
127128
all kinds of :ref:`Dictionary view objects <dict-views>`.
128129

129130
Frames

Objects/genobject.c

Lines changed: 137 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1465,15 +1465,6 @@ async_gen_init_hooks(PyAsyncGenObject *o)
14651465
}
14661466

14671467

1468-
#ifdef STACKLESS
1469-
int
1470-
slp_async_gen_init_hooks(PyAsyncGenObject *o)
1471-
{
1472-
return async_gen_init_hooks(o);
1473-
}
1474-
#endif
1475-
1476-
14771468
static PyObject *
14781469
async_gen_anext(PyAsyncGenObject *o)
14791470
{
@@ -2199,3 +2190,140 @@ async_gen_athrow_new(PyAsyncGenObject *gen, PyObject *args)
21992190
_PyObject_GC_TRACK((PyObject*)o);
22002191
return (PyObject*)o;
22012192
}
2193+
2194+
2195+
#ifdef STACKLESS
2196+
int
2197+
slp_async_gen_init_hooks(PyAsyncGenObject *o)
2198+
{
2199+
return async_gen_init_hooks(o);
2200+
}
2201+
2202+
2203+
PyObject *
2204+
slp_async_gen_asend_reduce(PyObject *o, PyTypeObject * wrapper_type)
2205+
{
2206+
PyAsyncGenASend *asend;
2207+
PyObject *tup;
2208+
2209+
assert(o != NULL);
2210+
assert(PyAsyncGenASend_CheckExact(o));
2211+
assert(wrapper_type != NULL);
2212+
2213+
asend = (PyAsyncGenASend *)o;
2214+
tup = Py_BuildValue("(O()(OOiO))",
2215+
wrapper_type,
2216+
asend->ags_gen,
2217+
asend->ags_sendval ? asend->ags_sendval : Py_None,
2218+
(int)asend->ags_state,
2219+
asend->ags_sendval ? Py_True : Py_False);
2220+
return tup;
2221+
}
2222+
2223+
2224+
PyObject *
2225+
slp_async_gen_asend_new(PyAsyncGenObject *gen)
2226+
{
2227+
return async_gen_asend_new(gen, NULL);
2228+
}
2229+
2230+
PyObject *
2231+
slp_async_gen_asend_setstate(PyObject *self, PyObject *args)
2232+
{
2233+
PyAsyncGenASend *asend;
2234+
PyObject *gen, *send_val, *has_sendval;
2235+
int state;
2236+
2237+
assert(self != NULL);
2238+
asend = (PyAsyncGenASend *)self;
2239+
2240+
assert(args != NULL);
2241+
if (!PyArg_ParseTuple(args, "O!OiO!:async_gen_asend_setstate",
2242+
&PyAsyncGen_Type,
2243+
&gen,
2244+
&send_val,
2245+
&state,
2246+
&PyBool_Type,
2247+
&has_sendval)) {
2248+
return NULL;
2249+
}
2250+
2251+
assert(PyAsyncGen_CheckExact(gen));
2252+
Py_INCREF(gen);
2253+
Py_SETREF(asend->ags_gen, (PyAsyncGenObject*)gen);
2254+
if (has_sendval != Py_True)
2255+
send_val = NULL;
2256+
else
2257+
Py_INCREF(send_val);
2258+
Py_XSETREF(asend->ags_sendval, send_val);
2259+
asend->ags_state = state;
2260+
2261+
Py_TYPE(self) = Py_TYPE(self)->tp_base;
2262+
Py_INCREF(self);
2263+
return self;
2264+
}
2265+
2266+
2267+
PyObject *
2268+
slp_async_gen_athrow_reduce(PyObject *o, PyTypeObject * wrapper_type)
2269+
{
2270+
PyAsyncGenAThrow *athrow;
2271+
PyObject *tup;
2272+
2273+
assert(o != NULL);
2274+
assert((Py_TYPE(o) == &_PyAsyncGenAThrow_Type));
2275+
assert(wrapper_type != NULL);
2276+
2277+
athrow = (PyAsyncGenAThrow *)o;
2278+
tup = Py_BuildValue("(O()(OOiO))",
2279+
wrapper_type,
2280+
athrow->agt_gen,
2281+
athrow->agt_args ? athrow->agt_args : Py_None,
2282+
(int)athrow->agt_state,
2283+
athrow->agt_args ? Py_True : Py_False);
2284+
return tup;
2285+
}
2286+
2287+
2288+
PyObject *
2289+
slp_async_gen_athrow_new(PyAsyncGenObject *gen)
2290+
{
2291+
return async_gen_athrow_new(gen, NULL);
2292+
}
2293+
2294+
PyObject *
2295+
slp_async_gen_athrow_setstate(PyObject *self, PyObject *args)
2296+
{
2297+
PyAsyncGenAThrow *athrow;
2298+
PyObject *gen, *agt_args, *has_args;
2299+
int state;
2300+
2301+
assert(self != NULL);
2302+
athrow = (PyAsyncGenAThrow *)self;
2303+
2304+
assert(args != NULL);
2305+
if (!PyArg_ParseTuple(args, "O!OiO!:async_gen_athrow_setstate",
2306+
&PyAsyncGen_Type,
2307+
&gen,
2308+
&agt_args,
2309+
&state,
2310+
&PyBool_Type,
2311+
&has_args)) {
2312+
return NULL;
2313+
}
2314+
2315+
assert(PyAsyncGen_CheckExact(gen));
2316+
Py_INCREF(gen);
2317+
Py_SETREF(athrow->agt_gen, (PyAsyncGenObject*)gen);
2318+
if (has_args != Py_True)
2319+
agt_args = NULL;
2320+
else
2321+
Py_INCREF(agt_args);
2322+
Py_XSETREF(athrow->agt_args, agt_args);
2323+
athrow->agt_state = state;
2324+
2325+
Py_TYPE(self) = Py_TYPE(self)->tp_base;
2326+
Py_INCREF(self);
2327+
return self;
2328+
}
2329+
#endif

Stackless/changelog.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ What's New in Stackless 3.X.X?
1616
- https://github.com/stackless-dev/stackless/issues/139
1717
New functions stackless.pickle_flags() and stackless.pickle_flags_default().
1818
They can be used to control pickling of certain objects.
19-
Stackless can now pickle asynchronous generators.
19+
Stackless can now pickle asynchronous generators and awaitables of type
20+
PyAsyncGenASend or PyAsyncGenAThrow (see PEP 525).
2021

2122
- https://github.com/stackless-dev/stackless/issues/175
2223
Cleanup of the Stackless C-API: Including stackless_api.h in an extension

Stackless/core/stackless_impl.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -803,6 +803,12 @@ int slp_safe_pickling(int(*save)(PyObject *, PyObject *, int),
803803

804804
PyObject * PyStackless_Pickle_ModuleDict(PyObject *pickler, PyObject *self);
805805
int slp_async_gen_init_hooks(PyAsyncGenObject *o);
806+
PyObject * slp_async_gen_asend_reduce(PyObject *o, PyTypeObject * wrapper_type);
807+
PyObject * slp_async_gen_asend_new(PyAsyncGenObject *gen);
808+
PyObject * slp_async_gen_asend_setstate(PyObject *self, PyObject *args);
809+
PyObject * slp_async_gen_athrow_reduce(PyObject *o, PyTypeObject * wrapper_type);
810+
PyObject * slp_async_gen_athrow_new(PyAsyncGenObject *gen);
811+
PyObject * slp_async_gen_athrow_setstate(PyObject *self, PyObject *args);
806812

807813
/* debugging/monitoring */
808814

Stackless/pickling/prickelpit.c

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1522,9 +1522,12 @@ static int init_dictitemsviewtype(PyObject * mod)
15221522
static PyTypeObject wrap_PyGen_Type;
15231523
static PyTypeObject wrap_PyCoro_Type;
15241524
static PyTypeObject wrap_PyAsyncGen_Type;
1525+
static PyTypeObject wrap__PyAsyncGenASend_Type;
1526+
static PyTypeObject wrap__PyAsyncGenAThrow_Type;
15251527

15261528
/* Used to initialize a generator created by gen_new. */
15271529
static PyFrameObject *gen_exhausted_frame = NULL;
1530+
static PyAsyncGenObject *gen_exhausted_asyncgen = NULL;
15281531

15291532
/* A helper for pickling the _PyErr_StackItem* members of generator-like and tasklet
15301533
* objects. This method returns a pointer to the object, that contains the
@@ -1844,6 +1847,13 @@ static int init_generatortype(PyObject * mod)
18441847
gen_exhausted_frame = slp_ensure_new_frame(gen->gi_frame);
18451848
if (gen_exhausted_frame == NULL) {
18461849
res = -1;
1850+
} else {
1851+
/* A reference to frame is stolen by PyGen_New. */
1852+
Py_INCREF(gen_exhausted_frame);
1853+
gen_exhausted_asyncgen = (PyAsyncGenObject *)PyAsyncGen_New(gen_exhausted_frame, NULL, NULL);
1854+
}
1855+
if (gen_exhausted_asyncgen == NULL) {
1856+
res = -1;
18471857
}
18481858

18491859
Py_DECREF(gen);
@@ -2111,6 +2121,81 @@ init_async_gentype(PyObject * mod)
21112121
#undef initchain
21122122
#define initchain init_async_gentype
21132123

2124+
static PyObject *
2125+
async_generator_asend_reduce(PyObject *o)
2126+
{
2127+
return slp_async_gen_asend_reduce(o, &wrap__PyAsyncGenASend_Type);
2128+
}
2129+
2130+
static PyObject *
2131+
async_generator_asend_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
2132+
{
2133+
PyObject * o;
2134+
if (is_wrong_type(type)) return NULL;
2135+
assert(type == &wrap__PyAsyncGenASend_Type);
2136+
assert(gen_exhausted_asyncgen != NULL);
2137+
o = slp_async_gen_asend_new(gen_exhausted_asyncgen);
2138+
if (o != NULL)
2139+
Py_TYPE(o) = type;
2140+
return o;
2141+
}
2142+
2143+
static PyObject *
2144+
async_generator_asend_setstate(PyObject *self, PyObject *args)
2145+
{
2146+
if (is_wrong_type(Py_TYPE(self))) return NULL;
2147+
return slp_async_gen_asend_setstate(self, args);
2148+
}
2149+
2150+
MAKE_WRAPPERTYPE(_PyAsyncGenASend_Type, asyncgen_asend, "async_generator_asend", async_generator_asend_reduce,
2151+
async_generator_asend_new, async_generator_asend_setstate)
2152+
2153+
static int
2154+
init_async_generator_asend_type(PyObject * mod)
2155+
{
2156+
return init_type(&wrap__PyAsyncGenASend_Type, initchain, mod);
2157+
}
2158+
#undef initchain
2159+
#define initchain init_async_generator_asend_type
2160+
2161+
static PyObject *
2162+
async_generator_athrow_reduce(PyObject *o)
2163+
{
2164+
return slp_async_gen_athrow_reduce(o, &wrap__PyAsyncGenAThrow_Type);
2165+
}
2166+
2167+
static PyObject *
2168+
async_generator_athrow_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
2169+
{
2170+
PyObject * o;
2171+
if (is_wrong_type(type)) return NULL;
2172+
assert(type == &wrap__PyAsyncGenAThrow_Type);
2173+
assert(gen_exhausted_asyncgen != NULL);
2174+
o = slp_async_gen_athrow_new(gen_exhausted_asyncgen);
2175+
if (o != NULL)
2176+
Py_TYPE(o) = type;
2177+
return o;
2178+
}
2179+
2180+
static PyObject *
2181+
async_generator_athrow_setstate(PyObject *self, PyObject *args)
2182+
{
2183+
if (is_wrong_type(Py_TYPE(self))) return NULL;
2184+
return slp_async_gen_athrow_setstate(self, args);
2185+
}
2186+
2187+
MAKE_WRAPPERTYPE(_PyAsyncGenAThrow_Type, asyncgen_athrow, "async_generator_athrow", async_generator_athrow_reduce,
2188+
async_generator_athrow_new, async_generator_athrow_setstate)
2189+
2190+
static int
2191+
init_async_generator_athrow_type(PyObject * mod)
2192+
{
2193+
return init_type(&wrap__PyAsyncGenAThrow_Type, initchain, mod);
2194+
}
2195+
#undef initchain
2196+
#define initchain init_async_generator_athrow_type
2197+
2198+
21142199
/******************************************************
21152200
21162201
support code for module dict pickling

0 commit comments

Comments
 (0)