Skip to content

Commit 3ab0136

Browse files
bpo-32604: Implement force-closing channels. (gh-6937)
This will make it easier to clean up channels (e.g. when used in tests).
1 parent 74fc9c0 commit 3ab0136

File tree

2 files changed

+232
-25
lines changed

2 files changed

+232
-25
lines changed

Lib/test/test__xxsubinterpreters.py

Lines changed: 96 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1379,12 +1379,104 @@ def test_close_multiple_times(self):
13791379
with self.assertRaises(interpreters.ChannelClosedError):
13801380
interpreters.channel_close(cid)
13811381

1382-
def test_close_with_unused_items(self):
1382+
def test_close_empty(self):
1383+
tests = [
1384+
(False, False),
1385+
(True, False),
1386+
(False, True),
1387+
(True, True),
1388+
]
1389+
for send, recv in tests:
1390+
with self.subTest((send, recv)):
1391+
cid = interpreters.channel_create()
1392+
interpreters.channel_send(cid, b'spam')
1393+
interpreters.channel_recv(cid)
1394+
interpreters.channel_close(cid, send=send, recv=recv)
1395+
1396+
with self.assertRaises(interpreters.ChannelClosedError):
1397+
interpreters.channel_send(cid, b'eggs')
1398+
with self.assertRaises(interpreters.ChannelClosedError):
1399+
interpreters.channel_recv(cid)
1400+
1401+
def test_close_defaults_with_unused_items(self):
1402+
cid = interpreters.channel_create()
1403+
interpreters.channel_send(cid, b'spam')
1404+
interpreters.channel_send(cid, b'ham')
1405+
1406+
with self.assertRaises(interpreters.ChannelNotEmptyError):
1407+
interpreters.channel_close(cid)
1408+
interpreters.channel_recv(cid)
1409+
interpreters.channel_send(cid, b'eggs')
1410+
1411+
def test_close_recv_with_unused_items_unforced(self):
13831412
cid = interpreters.channel_create()
13841413
interpreters.channel_send(cid, b'spam')
13851414
interpreters.channel_send(cid, b'ham')
1386-
interpreters.channel_close(cid)
1415+
1416+
with self.assertRaises(interpreters.ChannelNotEmptyError):
1417+
interpreters.channel_close(cid, recv=True)
1418+
interpreters.channel_recv(cid)
1419+
interpreters.channel_send(cid, b'eggs')
1420+
interpreters.channel_recv(cid)
1421+
interpreters.channel_recv(cid)
1422+
interpreters.channel_close(cid, recv=True)
1423+
1424+
def test_close_send_with_unused_items_unforced(self):
1425+
cid = interpreters.channel_create()
1426+
interpreters.channel_send(cid, b'spam')
1427+
interpreters.channel_send(cid, b'ham')
1428+
interpreters.channel_close(cid, send=True)
13871429

1430+
with self.assertRaises(interpreters.ChannelClosedError):
1431+
interpreters.channel_send(cid, b'eggs')
1432+
interpreters.channel_recv(cid)
1433+
interpreters.channel_recv(cid)
1434+
with self.assertRaises(interpreters.ChannelClosedError):
1435+
interpreters.channel_recv(cid)
1436+
1437+
def test_close_both_with_unused_items_unforced(self):
1438+
cid = interpreters.channel_create()
1439+
interpreters.channel_send(cid, b'spam')
1440+
interpreters.channel_send(cid, b'ham')
1441+
1442+
with self.assertRaises(interpreters.ChannelNotEmptyError):
1443+
interpreters.channel_close(cid, recv=True, send=True)
1444+
interpreters.channel_recv(cid)
1445+
interpreters.channel_send(cid, b'eggs')
1446+
interpreters.channel_recv(cid)
1447+
interpreters.channel_recv(cid)
1448+
interpreters.channel_close(cid, recv=True)
1449+
1450+
def test_close_recv_with_unused_items_forced(self):
1451+
cid = interpreters.channel_create()
1452+
interpreters.channel_send(cid, b'spam')
1453+
interpreters.channel_send(cid, b'ham')
1454+
interpreters.channel_close(cid, recv=True, force=True)
1455+
1456+
with self.assertRaises(interpreters.ChannelClosedError):
1457+
interpreters.channel_send(cid, b'eggs')
1458+
with self.assertRaises(interpreters.ChannelClosedError):
1459+
interpreters.channel_recv(cid)
1460+
1461+
def test_close_send_with_unused_items_forced(self):
1462+
cid = interpreters.channel_create()
1463+
interpreters.channel_send(cid, b'spam')
1464+
interpreters.channel_send(cid, b'ham')
1465+
interpreters.channel_close(cid, send=True, force=True)
1466+
1467+
with self.assertRaises(interpreters.ChannelClosedError):
1468+
interpreters.channel_send(cid, b'eggs')
1469+
with self.assertRaises(interpreters.ChannelClosedError):
1470+
interpreters.channel_recv(cid)
1471+
1472+
def test_close_both_with_unused_items_forced(self):
1473+
cid = interpreters.channel_create()
1474+
interpreters.channel_send(cid, b'spam')
1475+
interpreters.channel_send(cid, b'ham')
1476+
interpreters.channel_close(cid, send=True, recv=True, force=True)
1477+
1478+
with self.assertRaises(interpreters.ChannelClosedError):
1479+
interpreters.channel_send(cid, b'eggs')
13881480
with self.assertRaises(interpreters.ChannelClosedError):
13891481
interpreters.channel_recv(cid)
13901482

@@ -1403,7 +1495,7 @@ def test_close_by_unassociated_interp(self):
14031495
interp = interpreters.create()
14041496
interpreters.run_string(interp, dedent(f"""
14051497
import _xxsubinterpreters as _interpreters
1406-
_interpreters.channel_close({cid})
1498+
_interpreters.channel_close({cid}, force=True)
14071499
"""))
14081500
with self.assertRaises(interpreters.ChannelClosedError):
14091501
interpreters.channel_recv(cid)
@@ -1416,7 +1508,7 @@ def test_close_used_multiple_times_by_single_user(self):
14161508
interpreters.channel_send(cid, b'spam')
14171509
interpreters.channel_send(cid, b'spam')
14181510
interpreters.channel_recv(cid)
1419-
interpreters.channel_close(cid)
1511+
interpreters.channel_close(cid, force=True)
14201512

14211513
with self.assertRaises(interpreters.ChannelClosedError):
14221514
interpreters.channel_send(cid, b'eggs')

0 commit comments

Comments
 (0)