]> granicus.if.org Git - python/commitdiff
bpo-37394: Fix pure Python implementation of the queue module (GH-14351)
authorPablo Galindo <Pablogsal@gmail.com>
Tue, 25 Jun 2019 01:53:30 +0000 (02:53 +0100)
committerGitHub <noreply@github.com>
Tue, 25 Jun 2019 01:53:30 +0000 (02:53 +0100)
Lib/queue.py
Lib/test/test_queue.py
Misc/NEWS.d/next/Library/2019-06-25-02-10-00.bpo-37394.srZ1zx.rst [new file with mode: 0644]

index ef07957781a474a7f24f494144357caa8a714d5a..5bb0431e9494617ede7d87d153bde2e1bbe27315 100644 (file)
@@ -14,7 +14,7 @@ __all__ = ['Empty', 'Full', 'Queue', 'PriorityQueue', 'LifoQueue', 'SimpleQueue'
 
 try:
     from _queue import Empty
-except AttributeError:
+except ImportError:
     class Empty(Exception):
         'Exception raised by Queue.get(block=0)/get_nowait().'
         pass
index c8528f97741dccb3e29e4554796775832eeb46f7..46e2a8c540a72dcfc00768a54dcd854ddafa2e65 100644 (file)
@@ -1,7 +1,6 @@
 # Some simple queue module tests, plus some failure conditions
 # to ensure the Queue locks remain stable.
 import itertools
-import queue
 import random
 import threading
 import time
@@ -9,11 +8,9 @@ import unittest
 import weakref
 from test import support
 
-
-try:
-    import _queue
-except ImportError:
-    _queue = None
+py_queue = support.import_fresh_module('queue', blocked=['_queue'])
+c_queue = support.import_fresh_module('queue', fresh=['_queue'])
+need_c_queue = unittest.skipUnless(c_queue, "No _queue module found")
 
 QUEUE_SIZE = 5
 
@@ -120,12 +117,12 @@ class BaseQueueTestMixin(BlockingTestMixin):
         try:
             q.put(full, block=0)
             self.fail("Didn't appear to block with a full queue")
-        except queue.Full:
+        except self.queue.Full:
             pass
         try:
             q.put(full, timeout=0.01)
             self.fail("Didn't appear to time-out with a full queue")
-        except queue.Full:
+        except self.queue.Full:
             pass
         # Test a blocking put
         self.do_blocking_test(q.put, (full,), q.get, ())
@@ -137,12 +134,12 @@ class BaseQueueTestMixin(BlockingTestMixin):
         try:
             q.get(block=0)
             self.fail("Didn't appear to block with an empty queue")
-        except queue.Empty:
+        except self.queue.Empty:
             pass
         try:
             q.get(timeout=0.01)
             self.fail("Didn't appear to time-out with an empty queue")
-        except queue.Empty:
+        except self.queue.Empty:
             pass
         # Test a blocking get
         self.do_blocking_test(q.get, (), q.put, ('empty',))
@@ -218,12 +215,12 @@ class BaseQueueTestMixin(BlockingTestMixin):
         q = self.type2test(QUEUE_SIZE)
         for i in range(QUEUE_SIZE):
             q.put_nowait(1)
-        with self.assertRaises(queue.Full):
+        with self.assertRaises(self.queue.Full):
             q.put_nowait(1)
 
         for i in range(QUEUE_SIZE):
             q.get_nowait()
-        with self.assertRaises(queue.Empty):
+        with self.assertRaises(self.queue.Empty):
             q.get_nowait()
 
     def test_shrinking_queue(self):
@@ -232,45 +229,88 @@ class BaseQueueTestMixin(BlockingTestMixin):
         q.put(1)
         q.put(2)
         q.put(3)
-        with self.assertRaises(queue.Full):
+        with self.assertRaises(self.queue.Full):
             q.put_nowait(4)
         self.assertEqual(q.qsize(), 3)
         q.maxsize = 2                       # shrink the queue
-        with self.assertRaises(queue.Full):
+        with self.assertRaises(self.queue.Full):
             q.put_nowait(4)
 
-class QueueTest(BaseQueueTestMixin, unittest.TestCase):
-    type2test = queue.Queue
+class QueueTest(BaseQueueTestMixin):
+
+    def setUp(self):
+        self.type2test = self.queue.Queue
+        super().setUp()
+
+class PyQueueTest(QueueTest, unittest.TestCase):
+    queue = py_queue
+
+
+@need_c_queue
+class CQueueTest(QueueTest, unittest.TestCase):
+    queue = c_queue
+
+
+class LifoQueueTest(BaseQueueTestMixin):
+
+    def setUp(self):
+        self.type2test = self.queue.LifoQueue
+        super().setUp()
+
+
+class PyLifoQueueTest(LifoQueueTest, unittest.TestCase):
+    queue = py_queue
+
+
+@need_c_queue
+class CLifoQueueTest(LifoQueueTest, unittest.TestCase):
+    queue = c_queue
+
+
+class PriorityQueueTest(BaseQueueTestMixin):
+
+    def setUp(self):
+        self.type2test = self.queue.PriorityQueue
+        super().setUp()
+
 
-class LifoQueueTest(BaseQueueTestMixin, unittest.TestCase):
-    type2test = queue.LifoQueue
+class PyPriorityQueueTest(PriorityQueueTest, unittest.TestCase):
+    queue = py_queue
 
-class PriorityQueueTest(BaseQueueTestMixin, unittest.TestCase):
-    type2test = queue.PriorityQueue
 
+@need_c_queue
+class CPriorityQueueTest(PriorityQueueTest, unittest.TestCase):
+    queue = c_queue
 
 
 # A Queue subclass that can provoke failure at a moment's notice :)
-class FailingQueueException(Exception):
-    pass
-
-class FailingQueue(queue.Queue):
-    def __init__(self, *args):
-        self.fail_next_put = False
-        self.fail_next_get = False
-        queue.Queue.__init__(self, *args)
-    def _put(self, item):
-        if self.fail_next_put:
-            self.fail_next_put = False
-            raise FailingQueueException("You Lose")
-        return queue.Queue._put(self, item)
-    def _get(self):
-        if self.fail_next_get:
-            self.fail_next_get = False
-            raise FailingQueueException("You Lose")
-        return queue.Queue._get(self)
-
-class FailingQueueTest(BlockingTestMixin, unittest.TestCase):
+class FailingQueueException(Exception): pass
+
+class FailingQueueTest(BlockingTestMixin):
+
+    def setUp(self):
+
+        Queue = self.queue.Queue
+
+        class FailingQueue(Queue):
+            def __init__(self, *args):
+                self.fail_next_put = False
+                self.fail_next_get = False
+                Queue.__init__(self, *args)
+            def _put(self, item):
+                if self.fail_next_put:
+                    self.fail_next_put = False
+                    raise FailingQueueException("You Lose")
+                return Queue._put(self, item)
+            def _get(self):
+                if self.fail_next_get:
+                    self.fail_next_get = False
+                    raise FailingQueueException("You Lose")
+                return Queue._get(self)
+
+        self.FailingQueue = FailingQueue
+
+        super().setUp()
 
     def failing_queue_test(self, q):
         if q.qsize():
@@ -354,13 +394,24 @@ class FailingQueueTest(BlockingTestMixin, unittest.TestCase):
         self.assertTrue(not q.qsize(), "Queue should be empty")
 
     def test_failing_queue(self):
+
         # Test to make sure a queue is functioning correctly.
         # Done twice to the same instance.
-        q = FailingQueue(QUEUE_SIZE)
+        q = self.FailingQueue(QUEUE_SIZE)
         self.failing_queue_test(q)
         self.failing_queue_test(q)
 
 
+
+class PyFailingQueueTest(FailingQueueTest, unittest.TestCase):
+    queue = py_queue
+
+
+@need_c_queue
+class CFailingQueueTest(FailingQueueTest, unittest.TestCase):
+    queue = c_queue
+
+
 class BaseSimpleQueueTest:
 
     def setUp(self):
@@ -388,7 +439,7 @@ class BaseSimpleQueueTest:
             while True:
                 try:
                     val = q.get(block=False)
-                except queue.Empty:
+                except self.queue.Empty:
                     time.sleep(1e-5)
                 else:
                     break
@@ -401,7 +452,7 @@ class BaseSimpleQueueTest:
             while True:
                 try:
                     val = q.get(timeout=1e-5)
-                except queue.Empty:
+                except self.queue.Empty:
                     pass
                 else:
                     break
@@ -470,11 +521,11 @@ class BaseSimpleQueueTest:
         self.assertTrue(q.empty())
         self.assertEqual(q.qsize(), 0)
 
-        with self.assertRaises(queue.Empty):
+        with self.assertRaises(self.queue.Empty):
             q.get(block=False)
-        with self.assertRaises(queue.Empty):
+        with self.assertRaises(self.queue.Empty):
             q.get(timeout=1e-3)
-        with self.assertRaises(queue.Empty):
+        with self.assertRaises(self.queue.Empty):
             q.get_nowait()
         self.assertTrue(q.empty())
         self.assertEqual(q.qsize(), 0)
@@ -541,18 +592,25 @@ class BaseSimpleQueueTest:
 
 
 class PySimpleQueueTest(BaseSimpleQueueTest, unittest.TestCase):
-    type2test = queue._PySimpleQueue
 
+    queue = py_queue
+    def setUp(self):
+        self.type2test = self.queue._PySimpleQueue
+        super().setUp()
 
-@unittest.skipIf(_queue is None, "No _queue module found")
+
+@need_c_queue
 class CSimpleQueueTest(BaseSimpleQueueTest, unittest.TestCase):
 
+    queue = c_queue
+
     def setUp(self):
-        self.type2test = _queue.SimpleQueue
+        self.type2test = self.queue.SimpleQueue
         super().setUp()
 
     def test_is_default(self):
-        self.assertIs(self.type2test, queue.SimpleQueue)
+        self.assertIs(self.type2test, self.queue.SimpleQueue)
+        self.assertIs(self.type2test, self.queue.SimpleQueue)
 
     def test_reentrancy(self):
         # bpo-14976: put() may be called reentrantly in an asynchronous
diff --git a/Misc/NEWS.d/next/Library/2019-06-25-02-10-00.bpo-37394.srZ1zx.rst b/Misc/NEWS.d/next/Library/2019-06-25-02-10-00.bpo-37394.srZ1zx.rst
new file mode 100644 (file)
index 0000000..8d0d2fa
--- /dev/null
@@ -0,0 +1,2 @@
+Fix a bug that was causing the :mod:`queue` module to fail if the
+accelerator module was not available. Patch by Pablo Galindo.