8000 bpo-42085: Introduce dedicated entry in PyAsyncMethods for sending va… · python/cpython@1e996c3 · GitHub
[go: up one dir, main page]

Skip to content

Commit 1e996c3

Browse files
authored
bpo-42085: Introduce dedicated entry in PyAsyncMethods for sending values (#22780)
1 parent e59b2de commit 1e996c3

File tree

13 files changed

+146
-49
lines changed

13 files changed

+146
-49
lines changed

Doc/c-api/typeobj.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,8 @@ sub-slots
199199
+---------------------------------------------------------+-----------------------------------+--------------+
200200
| :c:member:`~PyAsyncMethods.am_anext` | :c:type:`unaryfunc` | __anext__ |
201201
+---------------------------------------------------------+-----------------------------------+--------------+
202+
| :c:member:`~PyAsyncMethods.am_send` | :c:type:`sendfunc` | |
203+
+---------------------------------------------------------+-----------------------------------+--------------+
202204
| |
203205
+---------------------------------------------------------+-----------------------------------+--------------+
204206
| :c:member:`~PyNumberMethods.nb_add` | :c:type:`binaryfunc` | __add__ |
@@ -2304,6 +2306,7 @@ Async Object Structures
23042306
unaryfunc am_await;
23052307
unaryfunc am_aiter;
23062308
unaryfunc am_anext;
2309+
sendfunc am_send;
23072310
} PyAsyncMethods;
23082311

23092312
.. c:member:: unaryfunc PyAsyncMethods.am_await
@@ -2337,6 +2340,15 @@ Async Object Structures
23372340
Must return an :term:`awaitable` object. See :meth:`__anext__` for details.
23382341
This slot may be set to ``NULL``.
23392342

2343+
.. c:member:: sendfunc PyAsyncMethods.am_send
2344+
2345+
The signature of this function is::
2346+
2347+
PySendResult am_send(PyObject *self, PyObject *arg, PyObject **result);
2348+
2349+
See :c:func:`PyIter_Send` for details.
2350+
This slot may be set to ``NULL``.
2351+
23402352

23412353
.. _slot-typedefs:
23422354

@@ -2432,6 +2444,10 @@ Slot Type typedefs
24322444
24332445
.. c:type:: PyObject *(*binaryfunc)(PyObject *, PyObject *)
24342446
2447+
.. c:type:: PySendResult (*sendfunc)(PyObject *, PyObject *, PyObject **)
2448+
2449+
See :c:member:`~PyAsyncMethods.am_send`.
2450+
24352451
.. c:type:: PyObject *(*ternaryfunc)(PyObject *, PyObject *, PyObject *)
24362452
24372453
.. c:type:: PyObject *(*ssizeargfunc)(PyObject *, Py_ssize_t)

Include/abstract.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -339,11 +339,6 @@ PyAPI_FUNC(int) PyIter_Check(PyObject *);
339339
PyAPI_FUNC(PyObject *) PyIter_Next(PyObject *);
340340

341341
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030A0000
342-
typedef enum {
343-
PYGEN_RETURN = 0,
344-
PYGEN_ERROR = -1,
345-
PYGEN_NEXT = 1,
346-
} PySendResult;
347342

348343
/* Takes generator, coroutine or iterator object and sends the value into it.
349344
Returns:

Include/cpython/object.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,10 +167,13 @@ typedef struct {
167167
objobjargproc mp_ass_subscript;
168168
} PyMappingMethods;
169169

170+
typedef PySendResult (*sendfunc)(PyObject *iter, PyObject *value, PyObject **result);
171+
170172
typedef struct {
171173
unaryfunc am_await;
172174
unaryfunc am_aiter;
173175
unaryfunc am_anext;
176+
sendfunc am_send;
174177
} PyAsyncMethods;
175178

176179
typedef struct {

Include/object.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,11 @@ given type object has a specified feature.
356356
/* Type is abstract and cannot be instantiated */
357357
#define Py_TPFLAGS_IS_ABSTRACT (1UL << 20)
358358

359+
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030A0000
360+
/* Type has am_send entry in tp_as_async slot */
361+
#define Py_TPFLAGS_HAVE_AM_SEND (1UL << 21)
362+
#endif
363+
359364
/* These flags are used to determine if a type is a subclass. */
360365
#define Py_TPFLAGS_LONG_SUBCLASS (1UL << 24)
361366
#define Py_TPFLAGS_LIST_SUBCLASS (1UL << 25)
@@ -582,6 +587,15 @@ PyAPI_DATA(PyObject) _Py_NotImplementedStruct; /* Don't use this directly */
582587
#define Py_GT 4
583588
#define Py_GE 5
584589

590+
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030A0000
591+
/* Result of calling PyIter_Send */
592+
typedef enum {
593+
PYGEN_RETURN = 0,
594+
PYGEN_ERROR = -1,
595+
PYGEN_NEXT = 1,
596+
} PySendResult;
597+
#endif
598+
585599
/*
586600
* Macro for implementing rich comparisons
587601
*

Include/typeslots.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,7 @@
8888
/* New in 3.5 */
8989
#define Py_tp_finalize 80
9090
#endif
91+
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030A0000
92+
/* New in 3.10 */
93+
#define Py_am_send 81
94+
#endif

Lib/test/test_sys.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1407,7 +1407,7 @@ def delx(self): del self.__x
14071407
check(int, s)
14081408
# class
14091409
s = vsize(fmt + # PyTypeObject
1410-
'3P' # PyAsyncMethods
1410+
'4P' # PyAsyncMethods
14111411
'36P' # PyNumberMethods
14121412
'3P' # PyMappingMethods
14131413
'10P' # PySequenceMethods
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add dedicated entry to PyAsyncMethods for sending values

Modules/_asynciomodule.c

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1479,7 +1479,8 @@ future_cls_getitem(PyObject *cls, PyObject *type)
14791479
static PyAsyncMethods FutureType_as_async = {
14801480
(unaryfunc)future_new_iter, /* am_await */
14811481
0, /* am_aiter */
1482-
0 /* am_anext */
1482+
0, /* am_anext */
1483+
0, /* am_send */
14831484
};
14841485

14851486
static PyMethodDef FutureType_methods[] = {
@@ -1597,37 +1598,60 @@ FutureIter_dealloc(futureiterobject *it)
15971598
}
15981599
}
15991600

1600-
static PyObject *
1601-
FutureIter_iternext(futureiterobject *it)
1601+
static PySendResult
1602+
FutureIter_am_send(futureiterobject *it,
1603+
PyObject *Py_UNUSED(arg),
1604+
PyObject **result)
16021605
{
1606+
/* arg is unused, see the comment on FutureIter_send for clarification */
1607+
16031608
PyObject *res;
16041609
FutureObj *fut = it->future;
16051610

1611+
*result = NULL;
16061612
if (fut == NULL) {
1607-
return NULL;
1613+
return PYGEN_ERROR;
16081614
}
16091615

16101616
if (fut->fut_state == STATE_PENDING) {
16111617
if (!fut->fut_blocking) {
16121618
fut->fut_blocking = 1;
16131619
Py_INCREF(fut);
1614-
return (PyObject *)fut;
1620+
*result = (PyObject *)fut;
1621+
return PYGEN_NEXT;
16151622
}
16161623
PyErr_SetString(PyExc_RuntimeError,
16171624
"await wasn't used with future");
1618-
return NULL;
1625+
return PYGEN_ERROR;
16191626
}
16201627

16211628
it->future = NULL;
16221629
res = _asyncio_Future_result_impl(fut);
16231630
if (res != NULL) {
1624-
/* The result of the Future is not an exception. */
1625-
(void)_PyGen_SetStopIterationValue(res);
1626-
Py_DECREF(res);
1631+
*result = res;
1632+
return PYGEN_RETURN;
16271633
}
16281634

16291635
Py_DECREF(fut);
1630-
return NULL;
1636+
return PYGEN_ERROR;
1637+
}
1638+
1639+
static PyObject *
1640+
FutureIter_iternext(futureiterobject *it)
1641+
{
1642+
PyObject *result;
1643+
switch (FutureIter_am_send(it, Py_None, &result)) {
1644+
case PYGEN_RETURN:
1645+
(void)_PyGen_SetStopIterationValue(result);
1646+
Py_DECREF(result);
1647+
return NULL;
1648+
case PYGEN_NEXT:
1649+
return result;
1650+
case PYGEN_ERROR:
1651+
return NULL;
1652+
default:
1653+
Py_UNREACHABLE();
1654+
}
16311655
}
16321656

16331657
static PyObject *
@@ -1716,14 +1740,24 @@ static PyMethodDef FutureIter_methods[] = {
17161740
{NULL, NULL} /* Sentinel */
17171741
};
17181742

1743+
static PyAsyncMethods FutureIterType_as_async = {
1744+
0, /* am_await */
1745+
0, /* am_aiter */
1746+
0, /* am_anext */
1747+
(sendfunc)FutureIter_am_send, /* am_send */
1748+
};
1749+
1750+
17191751
static PyTypeObject FutureIterType = {
17201752
PyVarObject_HEAD_INIT(NULL, 0)
17211753
"_asyncio.FutureIter",
17221754
.tp_basicsize = sizeof(futureiterobject),
17231755
.tp_itemsize = 0,
17241756
.tp_dealloc = (destructor)FutureIter_dealloc,
1757+
.tp_as_async = &FutureIterType_as_async,
17251758
.tp_getattro = PyObject_GenericGetAttr,
1726-
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
1759+
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
1760+
Py_TPFLAGS_HAVE_AM_SEND,
17271761
.tp_traverse = (traverseproc)FutureIter_traverse,
17281762
.tp_iter = PyObject_SelfIter,
17291763
.tp_iternext = (iternextfunc)FutureIter_iternext,

Modules/_testcapimodule.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6142,7 +6142,8 @@ awaitObject_await(awaitObject *ao)
61426142
static PyAsyncMethods awaitType_as_async = {
61436143
(unaryfunc)awaitObject_await, /* am_await */
61446144
0, /* am_aiter */
6145-
0 /* am_anext */
6145+
0, /* am_anext */
6146+
0, /* am_send */
61466147
};
61476148

61486149

Objects/abstract.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2669,6 +2669,32 @@ PyIter_Next(PyObject *iter)
26692669
return result;
26702670
}
26712671

2672+
PySendResult
2673+
PyIter_Send(PyObject *iter, PyObject *arg, PyObject **result)
2674+
{
2675+
_Py_IDENTIFIER(send);
2676+
assert(arg != NULL);
2677+
assert(result != NULL);
2678+
if (PyType_HasFeature(Py_TYPE(iter), Py_TPFLAGS_HAVE_AM_SEND)) {
2679+
assert (Py_TYPE(iter)->tp_as_async != NULL);
2680+
assert (Py_TYPE(iter)->tp_as_async->am_send != NULL);
2681+
return Py_TYPE(iter)->tp_as_async->am_send(iter, arg, result);
2682+
}
2683+
if (arg == Py_None && PyIter_Check(iter)) {
2684+
*result = Py_TYPE(iter)->tp_iternext(iter);
2685+
}
2686+
else {
2687+
*result = _PyObject_CallMethodIdOneArg(iter, &PyId_send, arg);
2688+
}
2689+
if (*result != NULL) {
2690+
return PYGEN_NEXT;
2691+
}
2692+
if (_PyGen_FetchStopIterationValue(result) == 0) {
2693+
return PYGEN_RETURN;
2694+
}
2695+
return PYGEN_ERROR;
2696+
}
2697+
26722698
/*
26732699
* Flatten a sequence of bytes() objects into a C array of
26742700
* NULL terminated string pointers with a NULL char* terminating the array.

Objects/genobject.c

Lines changed: 26 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -268,30 +268,10 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
268268
return result ? PYGEN_RETURN : PYGEN_ERROR;
269269
}
270270

271-
PySendResult
272-
PyIter_Send(PyObject *iter, PyObject *arg, PyObject **result)
271+
static PySendResult
272+
PyGen_am_send(PyGenObject *gen, PyObject *arg, PyObject **result)
273273
{
274-
_Py_IDENTIFIER(send);
275-
assert(arg != NULL);
276-
assert(result != NULL);
277-
278-
if (PyGen_CheckExact(iter) || PyCoro_CheckExact(iter)) {
279-
return gen_send_ex2((PyGenObject *)iter, arg, result, 0, 0);
280-
}
281-
282-
if (arg == Py_None && PyIter_Check(iter)) {
283-
*result = Py_TYPE(iter)->tp_iternext(iter);
284-
}
285-
else {
286-
*result = _PyObject_CallMethodIdOneArg(iter, &PyId_send, arg);
287-
}
288-
if (*result != NULL) {
289-
return PYGEN_NEXT;
290-
}
291-
if (_PyGen_FetchStopIterationValue(result) == 0) {
292-
return PYGEN_RETURN;
293-
}
294-
return PYGEN_ERROR;
274+
return gen_send_ex2(gen, arg, result, 0, 0);
295275
}
296276

297277
static PyObject *
@@ -788,6 +768,14 @@ static PyMethodDef gen_methods[] = {
788768
{NULL, NULL} /* Sentinel */
789769
};
790770

771+
static PyAsyncMethods gen_as_async = {
772+
0, /* am_await */
773+
0, /* am_aiter */
774+
0, /* am_anext */
775+
(sendfunc)PyGen_am_send, /* am_send */
776+
};
777+
778+
791779
PyTypeObject PyGen_Type = {
792780
PyVarObject_HEAD_INIT(&PyType_Type, 0)
793781
"generator", /* tp_name */
@@ -798,7 +786,7 @@ PyTypeObject PyGen_Type = {
798786
0, /* tp_vectorcall_offset */
799787
0, /* tp_getattr */
800788
0, /* tp_setattr */
801-
0, /* tp_as_async */
789+
&gen_as_async, /* tp_as_async */
802790
(reprfunc)gen_repr, /* tp_repr */
803791
0, /* tp_as_number */
804792
0, /* tp_as_sequence */
@@ -809,7 +797,8 @@ PyTypeObject PyGen_Type = {
809797
PyObject_GenericGetAttr, /* tp_getattro */
810798
0, /* tp_setattro */
811799
0, /* tp_as_buffer */
812-
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
800+
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
801+
Py_TPFLAGS_HAVE_AM_SEND, /* tp_flags */
813802
0, /* tp_doc */
814803
(traverseproc)gen_traverse, /* tp_traverse */
815804
0, /* tp_clear */
@@ -1031,7 +1020,8 @@ static PyMethodDef coro_methods[] = {
10311020
static PyAsyncMethods coro_as_async = {
10321021
(unaryfunc)coro_await, /* am_await */
10331022
0, /* am_aiter */
1034-
0 /* am_anext */
1023+
0, /* am_anext */
1024+
(sendfunc)PyGen_am_send, /* am_send */
10351025
};
10361026

10371027
PyTypeObject PyCoro_Type = {
@@ -1055,7 +1045,8 @@ PyTypeObject PyCoro_Type = {
10551045
PyObject_GenericGetAttr, /* tp_getattro */
10561046
0, /* tp_setattro */
10571047
0, /* tp_as_buffer */
1058-
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
1048+
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
1049+
Py_TPFLAGS_HAVE_AM_SEND, /* tp_flags */
10591050
0, /* tp_doc */
10601051
(traverseproc)gen_traverse, /* tp_traverse */
10611052
0, /* tp_clear */
@@ -1413,7 +1404,8 @@ static PyMethodDef async_gen_methods[] = {
14131404
static PyAsyncMethods async_gen_as_async = {
14141405
0, /* am_await */
14151406
PyObject_SelfIter, /* am_aiter */
1416-
(unaryfunc)async_gen_anext /* am_anext */
1407+
(unaryfunc)async_gen_anext, /* am_anext */
1408+
(sendfunc)PyGen_am_send, /* am_send */
14171409
};
14181410

14191411

@@ -1438,7 +1430,8 @@ PyTypeObject PyAsyncGen_Type = {
14381430
PyObject_GenericGetAttr, /* tp_getattro */
14391431
0, /* tp_setattro */
14401432
0, /* tp_as_buffer */
1441-
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
1433+
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
1434+
Py_TPFLAGS_HAVE_AM_SEND, /* tp_flags */
14421435
0, /* tp_doc */
14431436
(traverseproc)async_gen_traverse, /* tp_traverse */
14441437
0, /* tp_clear */
@@ -1676,7 +1669,8 @@ static PyMethodDef async_gen_asend_methods[] = {
16761669
static PyAsyncMethods async_gen_asend_as_async = {
16771670
PyObject_SelfIter, /* am_await */
16781671
0, /* am_aiter */
1679-
0 /* am_anext */
1672+
0, /* am_anext */
1673+
0, /* am_send */
16801674
};
16811675

16821676

@@ -2084,7 +2078,8 @@ static PyMethodDef async_gen_athrow_methods[] = {
20842078
static PyAsyncMethods async_gen_athrow_as_async = {
20852079
PyObject_SelfIter, /* am_await */
20862080
0, /* am_aiter */
2087-
0 /* am_anext */
2081+
0, /* am_anext */
2082+
0, /* am_send */
20882083
};
20892084

20902085

0 commit comments

Comments
 (0)
0