Skip to content

Commit 5bf3b89

Browse files
bpo-37394: Fix pure Python implementation of the queue module (GH-14351)
(cherry picked from commit 3f5b908) Co-authored-by: Pablo Galindo <[email protected]>
1 parent ced9e11 commit 5bf3b89

File tree

3 files changed

+111
-51
lines changed

3 files changed

+111
-51
lines changed

Lib/queue.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
try:
1616
from _queue import Empty
17-
except AttributeError:
17+
except ImportError:
1818
class Empty(Exception):
1919
'Exception raised by Queue.get(block=0)/get_nowait().'
2020
pass

Lib/test/test_queue.py

Lines changed: 108 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
11
# Some simple queue module tests, plus some failure conditions
22
# to ensure the Queue locks remain stable.
33
import itertools
4-
import queue
54
import random
65
import threading
76
import time
87
import unittest
98
import weakref
109
from test import support
1110

12-
13-
try:
14-
import _queue
15-
except ImportError:
16-
_queue = None
11+
py_queue = support.import_fresh_module('queue', blocked=['_queue'])
12+
c_queue = support.import_fresh_module('queue', fresh=['_queue'])
13+
need_c_queue = unittest.skipUnless(c_queue, "No _queue module found")
1714

1815
QUEUE_SIZE = 5
1916

@@ -120,12 +117,12 @@ def basic_queue_test(self, q):
120117
try:
121118
q.put(full, block=0)
122119
self.fail("Didn't appear to block with a full queue")
123-
except queue.Full:
120+
except self.queue.Full:
124121
pass
125122
try:
126123
q.put(full, timeout=0.01)
127124
self.fail("Didn't appear to time-out with a full queue")
128-
except queue.Full:
125+
except self.queue.Full:
129126
pass
130127
# Test a blocking put
131128
self.do_blocking_test(q.put, (full,), q.get, ())
@@ -137,12 +134,12 @@ def basic_queue_test(self, q):
137134
try:
138135
q.get(block=0)
139136
self.fail("Didn't appear to block with an empty queue")
140-
except queue.Empty:
137+
except self.queue.Empty:
141138
pass
142139
try:
143140
q.get(timeout=0.01)
144141
self.fail("Didn't appear to time-out with an empty queue")
145-
except queue.Empty:
142+
except self.queue.Empty:
146143
pass
147144
# Test a blocking get
148145
self.do_blocking_test(q.get, (), q.put, ('empty',))
@@ -218,12 +215,12 @@ def test_nowait(self):
218215
q = self.type2test(QUEUE_SIZE)
219216
for i in range(QUEUE_SIZE):
220217
q.put_nowait(1)
221-
with self.assertRaises(queue.Full):
218+
with self.assertRaises(self.queue.Full):
222219
q.put_nowait(1)
223220

224221
for i in range(QUEUE_SIZE):
225222
q.get_nowait()
226-
with self.assertRaises(queue.Empty):
223+
with self.assertRaises(self.queue.Empty):
227224
q.get_nowait()
228225

229226
def test_shrinking_queue(self):
@@ -232,45 +229,88 @@ def test_shrinking_queue(self):
232229
q.put(1)
233230
q.put(2)
234231
q.put(3)
235-
with self.assertRaises(queue.Full):
232+
with self.assertRaises(self.queue.Full):
236233
q.put_nowait(4)
237234
self.assertEqual(q.qsize(), 3)
238235
q.maxsize = 2 # shrink the queue
239-
with self.assertRaises(queue.Full):
236+
with self.assertRaises(self.queue.Full):
240237
q.put_nowait(4)
241238

242-
class QueueTest(BaseQueueTestMixin, unittest.TestCase):
243-
type2test = queue.Queue
239+
class QueueTest(BaseQueueTestMixin):
240+
241+
def setUp(self):
242+
self.type2test = self.queue.Queue
243+
super().setUp()
244+
245+
class PyQueueTest(QueueTest, unittest.TestCase):
246+
queue = py_queue
247+
248+
249+
@need_c_queue
250+
class CQueueTest(QueueTest, unittest.TestCase):
251+
queue = c_queue
252+
253+
254+
class LifoQueueTest(BaseQueueTestMixin):
255+
256+
def setUp(self):
257+
self.type2test = self.queue.LifoQueue
258+
super().setUp()
259+
260+
261+
class PyLifoQueueTest(LifoQueueTest, unittest.TestCase):
262+
queue = py_queue
263+
264+
265+
@need_c_queue
266+
class CLifoQueueTest(LifoQueueTest, unittest.TestCase):
267+
queue = c_queue
268+
269+
270+
class PriorityQueueTest(BaseQueueTestMixin):
271+
272+
def setUp(self):
273+
self.type2test = self.queue.PriorityQueue
274+
super().setUp()
275+
244276

245-
class LifoQueueTest(BaseQueueTestMixin, unittest.TestCase):
246-
type2test = queue.LifoQueue
277+
class PyPriorityQueueTest(PriorityQueueTest, unittest.TestCase):
278+
queue = py_queue
247279

248-
class PriorityQueueTest(BaseQueueTestMixin, unittest.TestCase):
249-
type2test = queue.PriorityQueue
250280

281+
@need_c_queue
282+
class CPriorityQueueTest(PriorityQueueTest, unittest.TestCase):
283+
queue = c_queue
251284

252285

253286
# A Queue subclass that can provoke failure at a moment's notice :)
254-
class FailingQueueException(Exception):
255-
pass
256-
257-
class FailingQueue(queue.Queue):
258-
def __init__(self, *args):
259-
self.fail_next_put = False
260-
self.fail_next_get = False
261-
queue.Queue.__init__(self, *args)
262-
def _put(self, item):
263-
if self.fail_next_put:
264-
self.fail_next_put = False
265-
raise FailingQueueException("You Lose")
266-
return queue.Queue._put(self, item)
267-
def _get(self):
268-
if self.fail_next_get:
269-
self.fail_next_get = False
270-
raise FailingQueueException("You Lose")
271-
return queue.Queue._get(self)
272-
273-
class FailingQueueTest(BlockingTestMixin, unittest.TestCase):
287+
class FailingQueueException(Exception): pass
288+
289+
class FailingQueueTest(BlockingTestMixin):
290+
291+
def setUp(self):
292+
293+
Queue = self.queue.Queue
294+
295+
class FailingQueue(Queue):
296+
def __init__(self, *args):
297+
self.fail_next_put = False
298+
self.fail_next_get = False
299+
Queue.__init__(self, *args)
300+
def _put(self, item):
301+
if self.fail_next_put:
302+
self.fail_next_put = False
303+
raise FailingQueueException("You Lose")
304+
return Queue._put(self, item)
305+
def _get(self):
306+
if self.fail_next_get:
307+
self.fail_next_get = False
308+
raise FailingQueueException("You Lose")
309+
return Queue._get(self)
310+
311+
self.FailingQueue = FailingQueue
312+
313+
super().setUp()
274314

275315
def failing_queue_test(self, q):
276316
if q.qsize():
@@ -354,13 +394,24 @@ def failing_queue_test(self, q):
354394
self.assertTrue(not q.qsize(), "Queue should be empty")
355395

356396
def test_failing_queue(self):
397+
357398
# Test to make sure a queue is functioning correctly.
358399
# Done twice to the same instance.
359-
q = FailingQueue(QUEUE_SIZE)
400+
q = self.FailingQueue(QUEUE_SIZE)
360401
self.failing_queue_test(q)
361402
self.failing_queue_test(q)
362403

363404

405+
406+
class PyFailingQueueTest(FailingQueueTest, unittest.TestCase):
407+
queue = py_queue
408+
409+
410+
@need_c_queue
411+
class CFailingQueueTest(FailingQueueTest, unittest.TestCase):
412+
queue = c_queue
413+
414+
364415
class BaseSimpleQueueTest:
365416

366417
def setUp(self):
@@ -388,7 +439,7 @@ def consume_nonblock(self, q, results, sentinel):
388439
while True:
389440
try:
390441
val = q.get(block=False)
391-
except queue.Empty:
442+
except self.queue.Empty:
392443
time.sleep(1e-5)
393444
else:
394445
break
@@ -401,7 +452,7 @@ def consume_timeout(self, q, results, sentinel):
401452
while True:
402453
try:
403454
val = q.get(timeout=1e-5)
404-
except queue.Empty:
455+
except self.queue.Empty:
405456
pass
406457
else:
407458
break
@@ -470,11 +521,11 @@ def test_basic(self):
470521
self.assertTrue(q.empty())
471522
self.assertEqual(q.qsize(), 0)
472523

473-
with self.assertRaises(queue.Empty):
524+
with self.assertRaises(self.queue.Empty):
474525
q.get(block=False)
475-
with self.assertRaises(queue.Empty):
526+
with self.assertRaises(self.queue.Empty):
476527
q.get(timeout=1e-3)
477-
with self.assertRaises(queue.Empty):
528+
with self.assertRaises(self.queue.Empty):
478529
q.get_nowait()
479530
self.assertTrue(q.empty())
480531
self.assertEqual(q.qsize(), 0)
@@ -541,18 +592,25 @@ class C:
541592

542593

543594
class PySimpleQueueTest(BaseSimpleQueueTest, unittest.TestCase):
544-
type2test = queue._PySimpleQueue
545595

596+
queue = py_queue
597+
def setUp(self):
598+
self.type2test = self.queue._PySimpleQueue
599+
super().setUp()
546600

547-
@unittest.skipIf(_queue is None, "No _queue module found")
601+
602+
@need_c_queue
548603
class CSimpleQueueTest(BaseSimpleQueueTest, unittest.TestCase):
549604

605+
queue = c_queue
606+
550607
def setUp(self):
551-
self.type2test = _queue.SimpleQueue
608+
self.type2test = self.queue.SimpleQueue
552609
super().setUp()
553610

554611
def test_is_default(self):
555-
self.assertIs(self.type2test, queue.SimpleQueue)
612+
self.assertIs(self.type2test, self.queue.SimpleQueue)
613+
self.assertIs(self.type2test, self.queue.SimpleQueue)
556614

557615
def test_reentrancy(self):
558616
# bpo-14976: put() may be called reentrantly in an asynchronous
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix a bug that was causing the :mod:`queue` module to fail if the
2+
accelerator module was not available. Patch by Pablo Galindo.

0 commit comments

Comments
 (0)