logging: don't define QueueListener if Python has no thread support
authorVictor Stinner <victor.stinner@haypocalc.com>
Mon, 2 May 2011 14:11:28 +0000 (16:11 +0200)
committerVictor Stinner <victor.stinner@haypocalc.com>
Mon, 2 May 2011 14:11:28 +0000 (16:11 +0200)
Lib/logging/handlers.py
Lib/test/test_logging.py
Misc/NEWS

index 3a48628d55f8dfc7c2d530707f2858dfbd3ae969..306cf866983a0fcc2ccfeb54f0b6f5ac43ece03f 100644 (file)
@@ -27,7 +27,10 @@ To use, simply 'import logging.handlers' and log away!
 import logging, socket, os, pickle, struct, time, re
 from stat import ST_DEV, ST_INO, ST_MTIME
 import queue
-import threading
+try:
+    import threading
+except ImportError:
+    threading = None
 
 try:
     import codecs
@@ -1218,106 +1221,107 @@ class QueueHandler(logging.Handler):
         except:
             self.handleError(record)
 
-class QueueListener(object):
-    """
-    This class implements an internal threaded listener which watches for
-    LogRecords being added to a queue, removes them and passes them to a
-    list of handlers for processing.
-    """
-    _sentinel = None
-
-    def __init__(self, queue, *handlers):
-        """
-        Initialise an instance with the specified queue and
-        handlers.
-        """
-        self.queue = queue
-        self.handlers = handlers
-        self._stop = threading.Event()
-        self._thread = None
-
-    def dequeue(self, block):
-        """
-        Dequeue a record and return it, optionally blocking.
-
-        The base implementation uses get. You may want to override this method
-        if you want to use timeouts or work with custom queue implementations.
-        """
-        return self.queue.get(block)
-
-    def start(self):
-        """
-        Start the listener.
-
-        This starts up a background thread to monitor the queue for
-        LogRecords to process.
-        """
-        self._thread = t = threading.Thread(target=self._monitor)
-        t.setDaemon(True)
-        t.start()
-
-    def prepare(self , record):
-        """
-        Prepare a record for handling.
-
-        This method just returns the passed-in record. You may want to
-        override this method if you need to do any custom marshalling or
-        manipulation of the record before passing it to the handlers.
-        """
-        return record
-
-    def handle(self, record):
-        """
-        Handle a record.
-
-        This just loops through the handlers offering them the record
-        to handle.
-        """
-        record = self.prepare(record)
-        for handler in self.handlers:
-            handler.handle(record)
-
-    def _monitor(self):
-        """
-        Monitor the queue for records, and ask the handler
-        to deal with them.
-
-        This method runs on a separate, internal thread.
-        The thread will terminate if it sees a sentinel object in the queue.
-        """
-        q = self.queue
-        has_task_done = hasattr(q, 'task_done')
-        while not self._stop.isSet():
-            try:
-                record = self.dequeue(True)
-                if record is self._sentinel:
-                    break
-                self.handle(record)
-                if has_task_done:
-                    q.task_done()
-            except queue.Empty:
-                pass
-        # There might still be records in the queue.
-        while True:
-            try:
-                record = self.dequeue(False)
-                if record is self._sentinel:
+if threading:
+    class QueueListener(object):
+        """
+        This class implements an internal threaded listener which watches for
+        LogRecords being added to a queue, removes them and passes them to a
+        list of handlers for processing.
+        """
+        _sentinel = None
+
+        def __init__(self, queue, *handlers):
+            """
+            Initialise an instance with the specified queue and
+            handlers.
+            """
+            self.queue = queue
+            self.handlers = handlers
+            self._stop = threading.Event()
+            self._thread = None
+
+        def dequeue(self, block):
+            """
+            Dequeue a record and return it, optionally blocking.
+
+            The base implementation uses get. You may want to override this method
+            if you want to use timeouts or work with custom queue implementations.
+            """
+            return self.queue.get(block)
+
+        def start(self):
+            """
+            Start the listener.
+
+            This starts up a background thread to monitor the queue for
+            LogRecords to process.
+            """
+            self._thread = t = threading.Thread(target=self._monitor)
+            t.setDaemon(True)
+            t.start()
+
+        def prepare(self , record):
+            """
+            Prepare a record for handling.
+
+            This method just returns the passed-in record. You may want to
+            override this method if you need to do any custom marshalling or
+            manipulation of the record before passing it to the handlers.
+            """
+            return record
+
+        def handle(self, record):
+            """
+            Handle a record.
+
+            This just loops through the handlers offering them the record
+            to handle.
+            """
+            record = self.prepare(record)
+            for handler in self.handlers:
+                handler.handle(record)
+
+        def _monitor(self):
+            """
+            Monitor the queue for records, and ask the handler
+            to deal with them.
+
+            This method runs on a separate, internal thread.
+            The thread will terminate if it sees a sentinel object in the queue.
+            """
+            q = self.queue
+            has_task_done = hasattr(q, 'task_done')
+            while not self._stop.isSet():
+                try:
+                    record = self.dequeue(True)
+                    if record is self._sentinel:
+                        break
+                    self.handle(record)
+                    if has_task_done:
+                        q.task_done()
+                except queue.Empty:
+                    pass
+            # There might still be records in the queue.
+            while True:
+                try:
+                    record = self.dequeue(False)
+                    if record is self._sentinel:
+                        break
+                    self.handle(record)
+                    if has_task_done:
+                        q.task_done()
+                except queue.Empty:
                     break
-                self.handle(record)
-                if has_task_done:
-                    q.task_done()
-            except queue.Empty:
-                break
-
-    def stop(self):
-        """
-        Stop the listener.
 
-        This asks the thread to terminate, and then waits for it to do so.
-        Note that if you don't call this before your application exits, there
-        may be some records still left on the queue, which won't be processed.
-        """
-        self._stop.set()
-        self.queue.put_nowait(self._sentinel)
-        self._thread.join()
-        self._thread = None
+        def stop(self):
+            """
+            Stop the listener.
+
+            This asks the thread to terminate, and then waits for it to do so.
+            Note that if you don't call this before your application exits, there
+            may be some records still left on the queue, which won't be processed.
+            """
+            self._stop.set()
+            self.queue.put_nowait(self._sentinel)
+            self._thread.join()
+            self._thread = None
index 6623a0f532257626f91c538a2280689e6e5f99cf..90d293e3abe6e0fc4e1146a500d4c3e538722beb 100644 (file)
@@ -2093,6 +2093,8 @@ class QueueHandlerTest(BaseTest):
         self.assertEqual(data.name, self.que_logger.name)
         self.assertEqual((data.msg, data.args), (msg, None))
 
+    @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'),
+                         'logging.handlers.QueueListener required for this test')
     def test_queue_listener(self):
         handler = TestHandler(Matcher())
         listener = logging.handlers.QueueListener(self.queue, handler)
index 2a500949bc18fc81a79cf7a12bb4feb12a485be1..8ca2f02bfc04387a9a433f87172880b42553f926 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -79,6 +79,8 @@ Core and Builtins
 Library
 -------
 
+- logging: don't define QueueListener if Python has no thread support.
+
 - Issue #11277: mmap.mmap() calls fcntl(fd, F_FULLFSYNC) on Mac OS X to get
   around a mmap bug with sparse files. Patch written by Steffen Daode Nurpmeso.