Skip to content

Commit 5e8c691

Browse files
bpo-32604: Add support for a "default" arg in channel_recv(). (GH-19770)
This allows the caller to avoid creation of an exception when the channel is empty (just like `dict.get()` works). `ChannelEmptyError` is still raised if no default is provided. Automerge-Triggered-By: @ericsnowcurrently
1 parent 6d86a23 commit 5e8c691

File tree

2 files changed

+46
-11
lines changed

2 files changed

+46
-11
lines changed

Lib/test/test__xxsubinterpreters.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1302,6 +1302,27 @@ def test_recv_empty(self):
13021302
with self.assertRaises(interpreters.ChannelEmptyError):
13031303
interpreters.channel_recv(cid)
13041304

1305+
def test_recv_default(self):
1306+
default = object()
1307+
cid = interpreters.channel_create()
1308+
obj1 = interpreters.channel_recv(cid, default)
1309+
interpreters.channel_send(cid, None)
1310+
interpreters.channel_send(cid, 1)
1311+
interpreters.channel_send(cid, b'spam')
1312+
interpreters.channel_send(cid, b'eggs')
1313+
obj2 = interpreters.channel_recv(cid, default)
1314+
obj3 = interpreters.channel_recv(cid, default)
1315+
obj4 = interpreters.channel_recv(cid)
1316+
obj5 = interpreters.channel_recv(cid, default)
1317+
obj6 = interpreters.channel_recv(cid, default)
1318+
1319+
self.assertIs(obj1, default)
1320+
self.assertIs(obj2, None)
1321+
self.assertEqual(obj3, 1)
1322+
self.assertEqual(obj4, b'spam')
1323+
self.assertEqual(obj5, b'eggs')
1324+
self.assertIs(obj6, default)
1325+
13051326
def test_run_string_arg_unresolved(self):
13061327
cid = interpreters.channel_create()
13071328
interp = interpreters.create()

Modules/_xxsubinterpretersmodule.c

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1350,19 +1350,16 @@ _channel_recv(_channels *channels, int64_t id)
13501350
_PyCrossInterpreterData *data = _channel_next(chan, PyInterpreterState_GetID(interp));
13511351
PyThread_release_lock(mutex);
13521352
if (data == NULL) {
1353-
if (!PyErr_Occurred()) {
1354-
PyErr_Format(ChannelEmptyError, "channel %" PRId64 " is empty", id);
1355-
}
13561353
return NULL;
13571354
}
13581355

13591356
// Convert the data back to an object.
13601357
PyObject *obj = _PyCrossInterpreterData_NewObject(data);
1358+
_PyCrossInterpreterData_Release(data);
1359+
PyMem_Free(data);
13611360
if (obj == NULL) {
13621361
return NULL;
13631362
}
1364-
_PyCrossInterpreterData_Release(data);
1365-
PyMem_Free(data);
13661363

13671364
return obj;
13681365
}
@@ -2351,20 +2348,37 @@ Add the object's data to the channel's queue.");
23512348
static PyObject *
23522349
channel_recv(PyObject *self, PyObject *args, PyObject *kwds)
23532350
{
2354-
static char *kwlist[] = {"cid", NULL};
2351+
static char *kwlist[] = {"cid", "default", NULL};
23552352
int64_t cid;
2356-
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:channel_recv", kwlist,
2357-
channel_id_converter, &cid)) {
2353+
PyObject *dflt = NULL;
2354+
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|O:channel_recv", kwlist,
2355+
channel_id_converter, &cid, &dflt)) {
23582356
return NULL;
23592357
}
2358+
Py_XINCREF(dflt);
23602359

2361-
return _channel_recv(&_globals.channels, cid);
2360+
PyObject *obj = _channel_recv(&_globals.channels, cid);
2361+
if (obj != NULL) {
2362+
Py_XDECREF(dflt);
2363+
return obj;
2364+
} else if (PyErr_Occurred()) {
2365+
Py_XDECREF(dflt);
2366+
return NULL;
2367+
} else if (dflt != NULL) {
2368+
return dflt;
2369+
} else {
2370+
PyErr_Format(ChannelEmptyError, "channel %" PRId64 " is empty", cid);
2371+
return NULL;
2372+
}
23622373
}
23632374

23642375
PyDoc_STRVAR(channel_recv_doc,
2365-
"channel_recv(cid) -> obj\n\
2376+
"channel_recv(cid, [default]) -> obj\n\
2377+
\n\
2378+
Return a new object from the data at the front of the channel's queue.\n\
23662379
\n\
2367-
Return a new object from the data at the from of the channel's queue.");
2380+
If there is nothing to receive then raise ChannelEmptyError, unless\n\
2381+
a default value is provided. In that case return it.");
23682382

23692383
static PyObject *
23702384
channel_close(PyObject *self, PyObject *args, PyObject *kwds)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy