Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c0e7400

Browse files
committed
Add exc_context parameter to {gen/coro}.throw()
1 parent 59ef993 commit c0e7400

File tree

2 files changed

+52
-21
lines changed

2 files changed

+52
-21
lines changed

Lib/contextlib.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,7 @@ def __exit__(self, typ, value, traceback):
171171
# like a normal function we set the current exception context
172172
# to what it was during the context manager's __enter__
173173
# (see gh-111676).
174-
sys._set_exception(exc_context)
175-
self.gen.throw(value)
174+
self.gen.throw(value, exc_context=exc_context)
176175
except StopIteration as exc:
177176
# Suppress StopIteration *unless* it's the same exception that
178177
# was passed to throw(). This prevents a StopIteration

Objects/genobject.c

Lines changed: 51 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -452,8 +452,8 @@ gen_close(PyObject *self, PyObject *args)
452452

453453

454454
PyDoc_STRVAR(throw_doc,
455-
"throw(value)\n\
456-
throw(type[,value[,tb]])\n\
455+
"throw(value, /, *, exc_context=None)\n\
456+
throw(type[,value[,tb]], /, *, exc_context=None)\n\
457457
\n\
458458
Raise exception in generator, return next yielded value or raise\n\
459459
StopIteration.\n\
@@ -592,14 +592,22 @@ _gen_throw(PyGenObject *gen, int close_on_genexit,
592592
return NULL;
593593
}
594594

595+
/*
596+
throw(...) method of builtins.generator instance
597+
throw(value, /, *, exc_context=None)
598+
throw(type[,value[,tb]], /, *, exc_context=None)
595599
600+
Raise exception in generator, return next yielded value or raise
601+
StopIteration.
602+
*/
596603
static PyObject *
597-
gen_throw(PyObject *op, PyObject *const *args, Py_ssize_t nargs)
604+
gen_throw(PyObject *op, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
598605
{
599606
PyGenObject *gen = _PyGen_CAST(op);
600607
PyObject *typ;
601608
PyObject *tb = NULL;
602609
PyObject *val = NULL;
610+
PyObject *exc_context = NULL;
603611

604612
if (!_PyArg_CheckPositional("throw", nargs, 1, 3)) {
605613
return NULL;
@@ -612,6 +620,18 @@ gen_throw(PyObject *op, PyObject *const *args, Py_ssize_t nargs)
612620
return NULL;
613621
}
614622
}
623+
624+
static const char * const _keywords[] = {"", "", "", "exc_context", NULL};
625+
static _PyArg_Parser _parser = {
626+
.keywords = _keywords,
627+
.fname = "throw",
628+
};
629+
PyObject *argsbuf[4];
630+
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 3, 0, 1, argsbuf);
631+
if (!args) {
632+
return NULL;
633+
}
634+
615635
typ = args[0];
616636
if (nargs == 3) {
617637
val = args[1];
@@ -620,6 +640,17 @@ gen_throw(PyObject *op, PyObject *const *args, Py_ssize_t nargs)
620640
else if (nargs == 2) {
621641
val = args[1];
622642
}
643+
644+
if (kwnames && PyTuple_GET_SIZE(kwnames)){
645+
exc_context = args[3];
646+
if (!Py_IsNone(exc_context) && !PyExceptionInstance_Check(exc_context)){
647+
PyErr_SetString(PyExc_TypeError, "exc_context must be an Exception object or None");
648+
return NULL;
649+
}
650+
}
651+
// update the generator's current exception context before throwing the
652+
// exception into it
653+
PyErr_SetHandledException(exc_context == NULL ? Py_None : exc_context);
623654
return _gen_throw(gen, 1, typ, val, tb);
624655
}
625656

@@ -841,7 +872,7 @@ PyDoc_STRVAR(sizeof__doc__,
841872

842873
static PyMethodDef gen_methods[] = {
843874
{"send", gen_send, METH_O, send_doc},
844-
{"throw", _PyCFunction_CAST(gen_throw), METH_FASTCALL, throw_doc},
875+
{"throw", _PyCFunction_CAST(gen_throw), METH_FASTCALL|METH_KEYWORDS, throw_doc},
845876
{"close", gen_close, METH_NOARGS, close_doc},
846877
{"__sizeof__", gen_sizeof, METH_NOARGS, sizeof__doc__},
847878
{"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")},
@@ -1187,8 +1218,8 @@ PyDoc_STRVAR(coro_send_doc,
11871218
return next iterated value or raise StopIteration.");
11881219

11891220
PyDoc_STRVAR(coro_throw_doc,
1190-
"throw(value)\n\
1191-
throw(type[,value[,traceback]])\n\
1221+
"throw(value, /, *, exc_context=None)\n\
1222+
throw(type[,value[,tb]], *, exc_context=None)\n\
11921223
\n\
11931224
Raise exception in coroutine, return next iterated value or raise\n\
11941225
StopIteration.\n\
@@ -1201,7 +1232,7 @@ PyDoc_STRVAR(coro_close_doc,
12011232

12021233
static PyMethodDef coro_methods[] = {
12031234
{"send", gen_send, METH_O, coro_send_doc},
1204-
{"throw",_PyCFunction_CAST(gen_throw), METH_FASTCALL, coro_throw_doc},
1235+
{"throw", _PyCFunction_CAST(gen_throw), METH_FASTCALL|METH_KEYWORDS, coro_throw_doc},
12051236
{"close", gen_close, METH_NOARGS, coro_close_doc},
12061237
{"__sizeof__", gen_sizeof, METH_NOARGS, sizeof__doc__},
12071238
{"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")},
@@ -1291,10 +1322,10 @@ coro_wrapper_send(PyObject *self, PyObject *arg)
12911322
}
12921323

12931324
static PyObject *
1294-
coro_wrapper_throw(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
1325+
coro_wrapper_throw(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
12951326
{
12961327
PyCoroWrapper *cw = _PyCoroWrapper_CAST(self);
1297-
return gen_throw((PyObject*)cw->cw_coroutine, args, nargs);
1328+
return gen_throw((PyObject*)cw->cw_coroutine, args, nargs, kwnames);
12981329
}
12991330

13001331
static PyObject *
@@ -1314,8 +1345,8 @@ coro_wrapper_traverse(PyObject *self, visitproc visit, void *arg)
13141345

13151346
static PyMethodDef coro_wrapper_methods[] = {
13161347
{"send", coro_wrapper_send, METH_O, coro_send_doc},
1317-
{"throw", _PyCFunction_CAST(coro_wrapper_throw), METH_FASTCALL,
1318-
coro_throw_doc},
1348+
{"throw", _PyCFunction_CAST(coro_wrapper_throw),
1349+
METH_FASTCALL|METH_KEYWORDS, coro_throw_doc},
13191350
{"close", coro_wrapper_close, METH_NOARGS, coro_close_doc},
13201351
{NULL, NULL} /* Sentinel */
13211352
};
@@ -1827,7 +1858,7 @@ async_gen_asend_iternext(PyObject *ags)
18271858

18281859

18291860
static PyObject *
1830-
async_gen_asend_throw(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
1861+
async_gen_asend_throw(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
18311862
{
18321863
PyAsyncGenASend *o = _PyAsyncGenASend_CAST(self);
18331864

@@ -1851,7 +1882,7 @@ async_gen_asend_throw(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
18511882
o->ags_gen->ag_running_async = 1;
18521883
}
18531884

1854-
PyObject *result = gen_throw((PyObject*)o->ags_gen, args, nargs);
1885+
PyObject *result = gen_throw((PyObject*)o->ags_gen, args, nargs, kwnames);
18551886
result = async_gen_unwrap_value(o->ags_gen, result);
18561887

18571888
if (result == NULL) {
@@ -1871,7 +1902,7 @@ async_gen_asend_close(PyObject *self, PyObject *args)
18711902
Py_RETURN_NONE;
18721903
}
18731904

1874-
PyObject *result = async_gen_asend_throw(self, &PyExc_GeneratorExit, 1);
1905+
PyObject *result = async_gen_asend_throw(self, &PyExc_GeneratorExit, 1, NULL);
18751906
if (result == NULL) {
18761907
if (PyErr_ExceptionMatches(PyExc_StopIteration) ||
18771908
PyErr_ExceptionMatches(PyExc_StopAsyncIteration) ||
@@ -1899,7 +1930,8 @@ async_gen_asend_finalize(PyObject *self)
18991930

19001931
static PyMethodDef async_gen_asend_methods[] = {
19011932
{"send", async_gen_asend_send, METH_O, send_doc},
1902-
{"throw", _PyCFunction_CAST(async_gen_asend_throw), METH_FASTCALL, throw_doc},
1933+
{"throw", _PyCFunction_CAST(async_gen_asend_throw),
1934+
METH_FASTCALL|METH_KEYWORDS, throw_doc},
19031935
{"close", async_gen_asend_close, METH_NOARGS, close_doc},
19041936
{NULL, NULL} /* Sentinel */
19051937
};
@@ -2227,7 +2259,7 @@ async_gen_athrow_send(PyObject *self, PyObject *arg)
22272259

22282260

22292261
static PyObject *
2230-
async_gen_athrow_throw(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
2262+
async_gen_athrow_throw(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
22312263
{
22322264
PyAsyncGenAThrow *o = _PyAsyncGenAThrow_CAST(self);
22332265

@@ -2258,7 +2290,7 @@ async_gen_athrow_throw(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
22582290
o->agt_gen->ag_running_async = 1;
22592291
}
22602292

2261-
PyObject *retval = gen_throw((PyObject*)o->agt_gen, args, nargs);
2293+
PyObject *retval = gen_throw((PyObject*)o->agt_gen, args, nargs, kwnames);
22622294
if (o->agt_args) {
22632295
retval = async_gen_unwrap_value(o->agt_gen, retval);
22642296
if (retval == NULL) {
@@ -2311,7 +2343,7 @@ async_gen_athrow_close(PyObject *self, PyObject *args)
23112343
Py_RETURN_NONE;
23122344
}
23132345
PyObject *result = async_gen_athrow_throw((PyObject*)agt,
2314-
&PyExc_GeneratorExit, 1);
2346+
&PyExc_GeneratorExit, 1, NULL);
23152347
if (result == NULL) {
23162348
if (PyErr_ExceptionMatches(PyExc_StopIteration) ||
23172349
PyErr_ExceptionMatches(PyExc_StopAsyncIteration) ||
@@ -2342,7 +2374,7 @@ async_gen_athrow_finalize(PyObject *op)
23422374
static PyMethodDef async_gen_athrow_methods[] = {
23432375
{"send", async_gen_athrow_send, METH_O, send_doc},
23442376
{"throw", _PyCFunction_CAST(async_gen_athrow_throw),
2345-
METH_FASTCALL, throw_doc},
2377+
METH_FASTCALL|METH_KEYWORDS, throw_doc},
23462378
{"close", async_gen_athrow_close, METH_NOARGS, close_doc},
23472379
{NULL, NULL} /* Sentinel */
23482380
};

0 commit comments

Comments
 (0)